Browse Source

Merge branch 'master-v4.3' of https://github.com/wizmo2/squeezelite-esp32 into led_visu-v4.3

Wizmo2 2 years ago
parent
commit
1e8d5371fe
100 changed files with 8327 additions and 1509 deletions
  1. 12 11
      .github/workflows/Platform_build.yml
  2. 6 6
      .github/workflows/esp-idf-v4.3-build.yml
  3. 3 0
      .github/workflows/web_deploy.yml
  4. 2 1
      Dockerfile
  5. 139 75
      README.md
  6. 4 5
      build-scripts/I2S-4MFlash-sdkconfig.defaults
  7. 4 5
      build-scripts/Muse-sdkconfig.defaults
  8. 5 6
      build-scripts/SqueezeAmp-sdkconfig.defaults
  9. 1 3
      components/codecs/CMakeLists.txt
  10. 90 11
      components/codecs/inc/FLAC/all.h
  11. 7 2
      components/codecs/inc/FLAC/assert.h
  12. 8 8
      components/codecs/inc/FLAC/callback.h
  13. 30 12
      components/codecs/inc/FLAC/export.h
  14. 154 147
      components/codecs/inc/FLAC/format.h
  15. 93 41
      components/codecs/inc/FLAC/metadata.h
  16. 3 34
      components/codecs/inc/FLAC/ordinals.h
  17. 47 23
      components/codecs/inc/FLAC/stream_decoder.h
  18. 112 65
      components/codecs/inc/FLAC/stream_encoder.h
  19. 2 1
      components/codecs/inc/ogg/config_types.h
  20. 0 1
      components/codecs/inc/ogg/ogg.h
  21. 15 5
      components/codecs/inc/ogg/os_types.h
  22. 2 2
      components/codecs/inc/opus/opus.h
  23. 4 3
      components/codecs/inc/opus/opus_custom.h
  24. 5 3
      components/codecs/inc/opus/opus_defines.h
  25. 78 91
      components/codecs/inc/opusfile/opusfile.h
  26. BIN
      components/codecs/lib/libFLAC.a
  27. BIN
      components/codecs/lib/libogg.a
  28. BIN
      components/codecs/lib/libopus.a
  29. BIN
      components/codecs/lib/libopusfile.a
  30. 1 1
      components/display/core/gds_default_if.h
  31. 2 1
      components/display/core/ifaces/default_if_spi.c
  32. 3 2
      components/display/display.c
  33. 25 16
      components/driver_bt/bt_app_core.c
  34. 1 1
      components/driver_bt/bt_app_sink.c
  35. 2 2
      components/driver_bt/bt_app_source.c
  36. 3 3
      components/platform_config/platform_config.c
  37. 1 1
      components/platform_config/platform_config.h
  38. 1 1
      components/platform_console/app_squeezelite/CMakeLists.txt
  39. 21 18
      components/platform_console/app_squeezelite/cmd_squeezelite.c
  40. 25 16
      components/platform_console/cmd_config.c
  41. 12 0
      components/platform_console/cmd_i2ctools.c
  42. 0 19
      components/platform_console/cmd_system.c
  43. 4 0
      components/raop/dmap_parser.c
  44. 1 1
      components/raop/raop.c
  45. 1 1
      components/raop/raop_sink.c
  46. 27 23
      components/raop/rtp.c
  47. 7 0
      components/services/accessors.c
  48. 1 0
      components/services/accessors.h
  49. 1 1
      components/services/audio_controls.c
  50. 1 1
      components/services/audio_controls.h
  51. 3 1
      components/services/buttons.c
  52. 8 3
      components/services/messaging.c
  53. 1 0
      components/services/messaging.h
  54. 10 4
      components/spotify/CMakeLists.txt
  55. 425 335
      components/spotify/Shim.cpp
  56. 0 49
      components/spotify/Shim.h
  57. 0 17
      components/spotify/cspot/CMakeLists.txt
  58. 3 0
      components/spotify/cspot/README.md
  59. 2 0
      components/spotify/cspot/bell/.clangd
  60. 52 0
      components/spotify/cspot/bell/.github/workflows/c-cpp.yml
  61. 2 1
      components/spotify/cspot/bell/.gitignore
  62. 9 10
      components/spotify/cspot/bell/.gitmodules
  63. 65 0
      components/spotify/cspot/bell/.vscode/settings.json
  64. 181 107
      components/spotify/cspot/bell/CMakeLists.txt
  65. 0 9
      components/spotify/cspot/bell/README.md
  66. 0 163
      components/spotify/cspot/bell/cJSON/Makefile
  67. 0 71
      components/spotify/cspot/bell/cJSON/tests/unity/examples/example_1/makefile
  68. 0 70
      components/spotify/cspot/bell/cJSON/tests/unity/examples/example_2/makefile
  69. 35 0
      components/spotify/cspot/bell/cmake/FindMbedTLS.cmake
  70. 63 0
      components/spotify/cspot/bell/cmake/Findportaudio.cmake
  71. 14 0
      components/spotify/cspot/bell/example/CMakeLists.txt
  72. 70 0
      components/spotify/cspot/bell/example/main.cpp
  73. 13 0
      components/spotify/cspot/bell/example/scripts/dsp_spectogram.py
  74. 6 0
      components/spotify/cspot/bell/external/alac/.gitignore
  75. 241 0
      components/spotify/cspot/bell/external/alac/ALACMagicCookieDescription.txt
  76. 9 0
      components/spotify/cspot/bell/external/alac/CONTRIBUTING.md
  77. 53 0
      components/spotify/cspot/bell/external/alac/LICENSE
  78. 9 0
      components/spotify/cspot/bell/external/alac/PULL_REQUEST_TEMPLATE.md
  79. 44 0
      components/spotify/cspot/bell/external/alac/ReadMe.txt
  80. 202 0
      components/spotify/cspot/bell/external/alac/codec/ALACAudioTypes.h
  81. 260 0
      components/spotify/cspot/bell/external/alac/codec/ALACBitUtilities.c
  82. 104 0
      components/spotify/cspot/bell/external/alac/codec/ALACBitUtilities.h
  83. 737 0
      components/spotify/cspot/bell/external/alac/codec/ALACDecoder.cpp
  84. 65 0
      components/spotify/cspot/bell/external/alac/codec/ALACDecoder.h
  85. 1432 0
      components/spotify/cspot/bell/external/alac/codec/ALACEncoder.cpp
  86. 92 0
      components/spotify/cspot/bell/external/alac/codec/ALACEncoder.h
  87. 335 0
      components/spotify/cspot/bell/external/alac/codec/APPLE_LICENSE.txt
  88. 177 0
      components/spotify/cspot/bell/external/alac/codec/EndianPortable.c
  89. 59 0
      components/spotify/cspot/bell/external/alac/codec/EndianPortable.h
  90. 362 0
      components/spotify/cspot/bell/external/alac/codec/ag_dec.c
  91. 370 0
      components/spotify/cspot/bell/external/alac/codec/ag_enc.c
  92. 81 0
      components/spotify/cspot/bell/external/alac/codec/aglib.h
  93. 85 0
      components/spotify/cspot/bell/external/alac/codec/alac.vcxproj
  94. 42 0
      components/spotify/cspot/bell/external/alac/codec/build.sh
  95. 381 0
      components/spotify/cspot/bell/external/alac/codec/dp_dec.c
  96. 386 0
      components/spotify/cspot/bell/external/alac/codec/dp_enc.c
  97. 61 0
      components/spotify/cspot/bell/external/alac/codec/dplib.h
  98. 390 0
      components/spotify/cspot/bell/external/alac/codec/matrix_dec.c
  99. 342 0
      components/spotify/cspot/bell/external/alac/codec/matrix_enc.c
  100. 80 0
      components/spotify/cspot/bell/external/alac/codec/matrixlib.h

+ 12 - 11
.github/workflows/BuildTest.yml → .github/workflows/Platform_build.yml

@@ -1,5 +1,8 @@
-name: Manually executable test for ESP-IDF v4.3.1
+name: Platform Build
 on: 
+  push:
+    branches: 
+      - '**4.3'
   workflow_dispatch:
     inputs:
       ui_build:
@@ -10,10 +13,6 @@ on:
         description: 'Force a Release build. When not forced, the system will check for release word in the last commit message to trigger a release'
         required: true
         type: boolean
-  # push:
-  #   branches: 
-  #     - '**4.3'
-
 jobs:
   bootstrap:
     name: Global setup
@@ -138,11 +137,11 @@ jobs:
       if: ${{ needs.bootstrap.outputs.mock == 0 }} 
       run: |
         . ${IDF_PYTHON_ENV_PATH}/bin/activate
-        chmod +x ./components/spotify/cspot/bell/nanopb/generator/protoc
-        chmod +x ./components/spotify/cspot/bell/nanopb/generator/protoc-gen-nanopb
-        chmod +x ./components/spotify/cspot/bell/nanopb/generator/*.py
-        chmod +x ./components/spotify/cspot/bell/nanopb/generator/*.py2
-        chmod +x ./components/spotify/cspot/bell/nanopb/generator/proto/*.py      
+        chmod +x ./components/spotify/cspot/bell/external/nanopb/generator/protoc
+        chmod +x ./components/spotify/cspot/bell/external/nanopb/generator/protoc-gen-nanopb
+        chmod +x ./components/spotify/cspot/bell/external/nanopb/generator/*.py
+        chmod +x ./components/spotify/cspot/bell/external/nanopb/generator/*.py2
+        chmod +x ./components/spotify/cspot/bell/external/nanopb/generator/proto/*.py      
         echo "Copying target sdkconfig"
         cp build-scripts/${TARGET_BUILD_NAME}-sdkconfig.defaults sdkconfig
         echo "Building project"
@@ -228,5 +227,7 @@ jobs:
   update_web_installer:
     name: Update Web Installer After Release
     needs: [ bootstrap, build ]
-    if:  ${{( always() && !cancelled() ) && needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
+    if: ${{ always() && !cancelled() && needs.bootstrap.outputs.release_flag == 1 && needs.bootstrap.outputs.mock == 0 }}
     uses: ./.github/workflows/web_deploy.yml
+    secrets:
+      WEB_INSTALLER: ${{ secrets.WEB_INSTALLER }}

+ 6 - 6
.github/workflows/esp-idf-v4.3-build.yml

@@ -51,11 +51,11 @@ jobs:
       run: |
         git update-index --chmod=+x ./server_certs/getcert.sh
         git update-index --chmod=+x ./buildFirmware.sh
-        git update-index --chmod=+x ./components/spotify/cspot/bell/nanopb/generator/protoc
-        git update-index --chmod=+x ./components/spotify/cspot/bell/nanopb/generator/protoc-gen-nanopb
-        git update-index --chmod=+x ./components/spotify/cspot/bell/nanopb/generator/*.py
-        git update-index --chmod=+x ./components/spotify/cspot/bell/nanopb/generator/*.py2
-        git update-index --chmod=+x ./components/spotify/cspot/bell/nanopb/generator/proto/*.py
+        git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/protoc
+        git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/protoc-gen-nanopb
+        git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/*.py
+        git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/*.py2
+        git update-index --chmod=+x ./components/spotify/cspot/bell/external/nanopb/generator/proto/*.py
         
 
         cd server_certs;./getcert.sh;cat github.pem;cd ..
@@ -65,7 +65,7 @@ jobs:
         BUILD_NUMBER=${{ needs.job1.outputs.build_number }}
         echo "BUILD_NUMBER=${BUILD_NUMBER}" >> $GITHUB_ENV
         echo "DOCKER_IMAGE_NAME=sle118/squeezelite-esp32-idfv4-master" >> $GITHUB_ENV
-        tag="${TARGET_BUILD_NAME}.${{matrix.depth}}.${BUILD_NUMBER}.${branch_name}"
+        tag="${TARGET_BUILD_NAME}.${{matrix.depth}}.${build_version_prefix}${BUILD_NUMBER}.${branch_name}"
         echo "tag=${tag}" >> $GITHUB_ENV
         last_commit="$(git log --pretty=format:'%s' --max-count=1)"
         if [[ "$last_commit" =~ .*"Release".* ]]; then echo "release_flag=1" >> $GITHUB_ENV; else echo "release_flag=0" >> $GITHUB_ENV; fi

+ 3 - 0
.github/workflows/web_deploy.yml

@@ -1,6 +1,9 @@
 name: Update Web Installer
 on:
   workflow_call:
+    secrets:
+      WEB_INSTALLER:
+        required: true       
   workflow_dispatch:
 jobs:
   update_web_installer:

+ 2 - 1
Dockerfile

@@ -15,7 +15,7 @@ ENV GCC_TOOLS_BASE=/opt/esp/tools/xtensa-esp32-elf/esp-2021r2-8.4.0/xtensa-esp32
 # To run the image interactive (windows): 
 # docker run --rm -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv43
 # To run the image interactive (linux):
-# docker run --rm -v `pwd`:/project -w /project -it sle118/squeezelite-esp32-idfv4-master
+# docker run --rm -v `pwd`:/project -w /project -it sle118/squeezelite-esp32-idfv43
 # to build the web app inside of the interactive session
 # pushd components/wifi-manager/webapp/ && npm install && npm run-script build && popd
 #
@@ -90,6 +90,7 @@ RUN : \
   && pip show pygit2 \ 
   && python --version \  
   && pip --version \
+  && pip install protobuf  grpcio-tools \
   && rm -rf $IDF_TOOLS_PATH/dist \
   && :
 

+ 139 - 75
README.md

@@ -1,21 +1,23 @@
-![Cross-Build](https://github.com/sle118/squeezelite-esp32/workflows/Cross-Build/badge.svg?branch=master-cmake)
-![ESP-IDF v4.3.1](https://github.com/sle118/squeezelite-esp32/actions/workflows/esp-idf-v4.3-build.yml/badge.svg?branch=master-v4.3)
+[![Platform Build](https://github.com/sle118/squeezelite-esp32/actions/workflows/Platform_build.yml/badge.svg)](https://github.com/sle118/squeezelite-esp32/actions/workflows/Platform_build.yml)
 # Squeezelite-esp32
-## What is this
+
+## What is this?
 Squeezelite-esp32 is an audio software suite made to run on espressif's ESP32 wifi (b/g/n) and bluetooth chipset. It offers the following capabilities
 
 - Stream your local music and connect to all major on-line music providers (Spotify, Deezer, Tidal, Qobuz) using [Logitech Media Server - a.k.a LMS](https://forums.slimdevices.com/) and enjoy multi-room audio synchronization. LMS can be extended by numerous plugins and can be controlled using a Web browser or dedicated applications (iPhone, Android). It can also send audio to UPnP, Sonos, ChromeCast and AirPlay speakers/devices.
-- Stream from a Bluetooth device (iPhone, Android)
-- Stream from an AirPlay controller (iPhone, iTunes ...) and enjoy synchronization multiroom as well (although it's AirPlay 1 only)
+- Stream from a **Bluetooth** device (iPhone, Android)
+- Stream from an **AirPlay** controller (iPhone, iTunes ...) and enjoy synchronization multiroom as well (although it's AirPlay 1 only)
+- Stream direcly from **Spotify** using SpotifyConnect (thanks to [cspot](https://github.com/feelfreelinux/cspot)
 
 Depending on the hardware connected to the ESP32, you can send audio to a local DAC, to SPDIF or to a Bluetooth speaker. The bare minimum required hardware is a WROVER module with 4MB of Flash and 4MB of PSRAM (https://www.espressif.com/en/products/modules/esp32). With that module standalone, just apply power and you can stream to a Bluetooth speaker. You can also send audio to most I2S DAC as well as to SPDIF receivers using just a cable or an optical transducer.
 
 But squeezelite-esp32 is highly extensible and you can add
 
-- Buttons and Rotary Encoder and map/combine them to various functions (play, pause, volume, next ...)
-- IR receiver (no pullup resistor or capacitor needed, just the 38kHz receiver)
-- Monochrome, GrayScale or Color displays using SPI or I2C (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735, ST7789 and ILI9341).
-- Ethernet using a Microchip LAN8720 with RMII interface or Davicom DM9051 over SPI.
+- [Buttons](#buttons) and [Rotary Encoder](#rotary-encoder) and map/combine them to various functions (play, pause, volume, next ...)
+- [GPIO expander](#gpio-expanders) (buttons, led and rotary)
+- [IR receiver](#infrared) (no pullup resistor or capacitor needed, just the 38kHz receiver)
+- [Monochrome, GrayScale or Color displays](#display) using SPI or I2C (supported drivers are SH1106, SSD1306, SSD1322, SSD1326/7, SSD1351, ST7735, ST7789 and ILI9341).
+- [Ethernet](#ethernet-required-unpublished-version-43) using a Microchip LAN8720 with RMII interface or Davicom DM9051/W5500 over SPI.
 
 Other features include
 
@@ -50,29 +52,44 @@ The esp32 must run at 240 MHz, with Quad-SPI I/O at 80 MHz and a clock of 40 Mhz
 In 16 bits mode, although 192 kHz is reported as max rate, it's highly recommended to limit reported sampling rate to 96k (-Z 96000). Note that some high-speed 24/96k on-line streams might stutter because of TCP/IP stack performances. It is usually due to the fact that the server sends small packets of data and the esp32 cannot receive encoded audio fast enough, regardless of task priority settings (I've tried to tweak that a fair bit). The best option in that case is to let LMS proxy the stream as it will provide larger chunks and a "smoother" stream that can then be handled.
 
 Note as well that some codecs consume more CPU than others or have not been optimized as much. I've done my best to tweak these, but that level of optimization includes writing some assembly which is painful. One very demanding codec is AAC when files are encoded with SBR. It allows reconstruction of upper part of spectrum and thus higher sampling rate, but the codec spec is such that this is optional, you can decode simply lower band and accept lower sampling rate - See the AAC_DISABLE_SBR option below.
+
 ## Supported Hardware
 Any esp32-based hardware with at least 4MB of flash and 4MB of PSRAM will be capable of running squeezelite-esp32 and there are various boards that include such chip. A few are mentionned below, but any should work. You can find various help & instructions [here](https://forums.slimdevices.com/showthread.php?112697-ANNOUNCE-Squeezelite-ESP32-(dedicated-thread))
 
 **For the sake of clarity, WROOM modules DO NOT work as they don't include PSRAM. Some designs might add it externally, but it's (very) unlikely.**
+
 ### Raw WROVER module
 Per above description, a [WROVER module](https://www.espressif.com/en/products/modules/esp32) is enough to run Squeezelite-esp32, but that requires a bit of tinkering to extend it to have analogue audio or hardware buttons (e.g.) 
 
 Please note that when sending to a Bluetooth speaker (source), only 44.1 kHz can be used, so you either let LMS do the resampling, but you must make sure it only sends 44.1kHz tracks or enable internal resampling (using -R) option. If you connect a DAC, choice of sample rates will depends on its capabilities. See below for more details.
 
 Most DAC will work out-of-the-box with simply an I2S connection, but some require specific commands to be sent using I2C. See DAC option below to understand how to send these dedicated commands. There is build-in support for TAS575x, TAS5780, TAS5713 and AC101 DAC.
+
 ### SqueezeAMP
 This is the main hardware companion of Squeezelite-esp32 and has been developped together. Details on capabilities can be found [here](https://forums.slimdevices.com/showthread.php?110926-pre-ANNOUNCE-SqueezeAMP-and-SqueezeliteESP32) and [here](https://github.com/philippe44/SqueezeAMP).
 
-if you want to rebuild, use the `squeezelite-esp32-SqueezeAmp-sdkconfig.defaults` configuration file.
+If you want to rebuild, use the `squeezelite-esp32-SqueezeAmp-sdkconfig.defaults` configuration file.
 
 NB: You can use the pre-build binaries SqueezeAMP4MBFlash which has all the hardware I/O set properly. You can also use the generic binary I2S4MBFlash in which case the NVS parameters shall be set to get the exact same behavior
-- set_GPIO: 12=green,13=red,34=jack,2=spkfault
-- batt_config: channel=7,scale=20.24
-- dac_config: model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0
-- spdif_config: bck=33,ws=25,do=15
+- set_GPIO: `12=green,13=red,34=jack,2=spkfault`
+- bat_config: `channel=7,scale=20.24`
+- dac_config: `model=TAS57xx,bck=33,ws=25,do=32,sda=27,scl=26,mute=14:0`
+- spdif_config: `bck=33,ws=25,do=15`
+
+### MuseLuxe
+This portable battery-powered [speaker](https://raspiaudio.com/produit/esp-muse-luxe) is compatible with squeezelite-esp32 for which there is a dedicated build supplied with every update. If you want to rebuild, use the `squeezelite-esp32-Muse-sdkconfig.defaults` configuration file.
+
+NB: You can use the pre-build binaries Muse4MBFlash which has all the hardware I/O set properly. You can also use the generic binary I2S4MBFlash in which case the NVS parameters shall be set to get the exact same behavior
+- target: `muse`
+- bat_config: `channel=5,scale=7.48,atten=3,cells=1`
+- spi_config: `"mosi=15,miso=2,clk=14` *(this one is probably optional)*
+- dac_config: `model=I2S,bck=5,ws=25,do=26,di=35,i2c=16,sda=18,scl=23,mck`
+- dac_controlset: `{"init":[ {"reg":0,"val":128}, {"reg":0,"val":0}, {"reg":25,"val":4}, {"reg":1,"val":80}, {"reg":2,"val":0},	{"reg":8,"val":0}, {"reg":4,"val":192},	{"reg":0,"val":18}, {"reg":1,"val":0}, {"reg":23,"val":24}, {"reg":24,"val":2}, {"reg":38,"val":9}, {"reg":39,"val":144}, {"reg":42,"val":144}, {"reg":43,"val":128}, {"reg":45,"val":128}, {"reg":27,"val":0}, {"reg":26,"val":0}, {"reg":2,"val":240}, {"reg":2,"val":0},	{"reg":29,"val":28}, {"reg":4,"val":48}, {"reg":25,"val":0}, {"reg":46,"val":33}, {"reg":47,"val":33} ]}`
+- actrls_config: buttons
+- define a "buttons" variable with: `[{"gpio":32, "pull":true, "debounce":10, "normal":{"pressed":"ACTRLS_VOLDOWN"}}, {"gpio":19, "pull":true, "debounce":40, "normal":{"pressed":"ACTRLS_VOLUP"}}, {"gpio":12, "pull":true, "debounce":40, "long_press":1000, "normal":{"pressed":"ACTRLS_TOGGLE"},"longpress":{"pressed":"ACTRLS_POWER"}}]`
 
 ### ESP32-A1S
-Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includes audio codec and headset output. You still need to use a demo board like [this](https://www.aliexpress.com/item/4001060963585.html) or an external amplifier if you want direct speaker connection. Note that there is a version with AC101 codec and another one with ES8388 (see below)
+Works with [ESP32-A1S](https://docs.ai-thinker.com/esp32-a1s) module that includes audio codec and headset output. You still need to use a demo board like [this](https://www.aliexpress.com/item/4001060963585.html) or an external amplifier if you want direct speaker connection. Note that there is a version with AC101 codec and another one with ES8388 with probably two variants - these boards are a mess (see below)
 
 The board shown above has the following IO set
 - amplifier: GPIO21
@@ -88,23 +105,30 @@ The board shown above has the following IO set
 (note that some GPIO need pullups)
 
 So a possible config would be
-- set_GPIO: 21=amp,22=green:0,39=jack:0
+- set_GPIO: `21=amp,22=green:0,39=jack:0`
 - a button mapping: 
-```
-[{"gpio":5,"normal":{"pressed":"ACTRLS_TOGGLE"}},{"gpio":18,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_NEXT"}}, {"gpio":23,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLDOWN"},"shifted":{"pressed":"ACTRLS_PREV"}}]
-```
-for AC101
-- dac_config: model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32
+	```json
+	[{"gpio":5,"normal":{"pressed":"ACTRLS_TOGGLE"}},{"gpio":18,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_NEXT"}}, {"gpio":23,"pull":true,"shifter_gpio":5,"normal":{"pressed":"ACTRLS_VOLDOWN"},"shifted":{"pressed":"ACTRLS_PREV"}}]
+	```
+for **AC101**
+- dac_config: `model=AC101,bck=27,ws=26,do=25,di=35,sda=33,scl=32`
  
-for ES8388
-- dac_config: model=ES8388,bck=5,ws=25,do=26,sda=18,scl=23,i2c=16
+for **ES8388** (it seems that there are variants with same version number - a total mess)
+- dac_config: `model=ES8388,bck=5,ws=25,do=26,sda=18,scl=23,i2c=16`
+or
+- dac_config: `model=ES8388,bck=27,ws=25,do=26,sda=33,scl=32,i2c=16`
+
 ### T-WATCH2020 by LilyGo
 This is a fun [smartwatch](http://www.lilygo.cn/prod_view.aspx?TypeId=50036&Id=1290&FId=t3:50036:3) based on ESP32. It has a 240x240 ST7789 screen and onboard audio. Not very useful to listen to anything but it works. This is an example of a device that requires an I2C set of commands for its dac (see below). There is a build-option if you decide to rebuild everything by yourself, otherwise the I2S default option works with the following parameters
 
-- dac_config: model=I2S,bck=26,ws=25,do=33,i2c=106,sda=21,scl=22
-- dac_controlset: { "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and"} ] }
-- spi_config: dc=27,data=19,clk=18
-- display_config: SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip
+- dac_config: `model=I2S,bck=26,ws=25,do=33,i2c=106,sda=21,scl=22`
+- dac_controlset:
+	```json
+	{ "init": [ {"reg":41, "val":128}, {"reg":18, "val":255} ], "poweron": [ {"reg":18, "val":64, "mode":"or"} ], "poweroff": [ {"reg":18, "val":191, "mode":"and"} ] }
+	```
+- spi_config: `dc=27,data=19,clk=18`
+- display_config: `SPI,driver=ST7789,width=240,height=240,cs=5,back=12,speed=16000000,HFlip,VFlip`
+
 ### ESP32-WROVER + I2S DAC
 Squeezelite-esp32 requires esp32 chipset and 4MB PSRAM. ESP32-WROVER meets these requirements. To get an audio output an I2S DAC can be used. Cheap PCM5102 I2S DACs work others may also work. PCM5012 DACs can be hooked up via:
 
@@ -130,18 +154,23 @@ And the super cool project https://github.com/rochuck/squeeze-amp-too
 ## Configuration
 To access NVS, in the webUI, go to credits and select "shows nvs editor". Go into the NVS editor tab to change NFS parameters. In syntax description below \<\> means a value while \[\] describe optional parameters. 
 
+As mentionned above, there are a few dedicated builds that are provided today: SqueezeAMP and Muse but if you build it yourself, you can also create a build for T-WATCH2020. The default build is a generic firmware named I2S which can be configured through NVS to produce *exactly* the same results than dedicated builds. The difference is that parameters must be entered and can accidently be erased. The GUI provides a great help to load "known config sets" as well. 
+
+By design choice, there is no code that is only embedded for a given version, all code is always there. The philosophy is to minimize as much as possible platform-specific code and use of specific `#ifdef` is prohibited, no matter what. So if you want to add your own platfrom, please look **very hard** at the `main\KConfig.projbuild` to see how you can, using parameters below, make your device purely a configuration-based solution. When there is really no other option, look at `targets\<target>` to add your own code. I will not accept PR for code that can avoid creating such dedicated code whenever possible. The NVS "target" will be used to call target-specific code then, but again this is purely runtime, not compile-time.
+
 ### I2C
 The NVS parameter "i2c_config" set the i2c's gpio used for generic purpose (e.g. display). Leave it blank to disable I2C usage. Note that on SqueezeAMP, port must be 1. Default speed is 400000 but some display can do up to 800000 or more. Syntax is
 ```
 sda=<gpio>,scl=<gpio>[,port=0|1][,speed=<speed>]
 ```
-<strong>Please note that you can not use the same GPIO or port as the DAC</strong>
+**Please note that you can not use the same GPIO or port as the DAC.**
+
 ### SPI
 The esp32 has 4 SPI sub-systems, one is unaccessible so numbering is 0..2 and SPI0 is reserved for Flash/PSRAM. The NVS parameter "spi_config" set the spi's gpio used for generic purpose (e.g. display). Leave it blank to disable SPI usage. The DC parameter is needed for displays. Syntax is
 ```
 data|mosi=<gpio>,clk=<gpio>[,dc=<gpio>][,host=1|2][,miso=<gpio>]
 ``` 
-Default "host" is 1. The "miso" parameter is only used when SPI bus is to be shared with other peripheral (e.g. ethernet, see below), otherwise it can be omitted. Note that "data" can also be named "mosi". 
+Default and only "host" is 1 as others are used already by flash and spiram. The optional "miso" (MasterInSlaveOut) parameter is only used when SPI bus is bi-directional and shared with other peripheral like ethernet, gpio expander. Note that "data" can also be named "mosi" (MasterOutSlaveIn). 
 ### DAC/I2S
 The NVS parameter "dac_config" set the gpio used for i2s communication with your DAC. You can define the defaults at compile time but nvs parameter takes precedence except for SqueezeAMP and A1S where these are forced at runtime. Syntax is
 ```
@@ -149,17 +178,20 @@ bck=<gpio>,ws=<gpio>,do=<gpio>[,mck][,mute=<gpio>[:0|1][,model=TAS57xx|TAS5713|A
 ```
 if "model" is not set or is not recognized, then default "I2S" is used. The option "mck" is used for some codecs that require a master clock (although they should not). Only GPIO0 can be used as MCLK and be aware that this cannot coexit with RMII Ethernet (see ethernet section below). I2C parameters are optional and only needed if your DAC requires an I2C control (See 'dac_controlset' below). Note that "i2c" parameters are decimal, hex notation is not allowed.
 
-So far, TAS57xx, TAS5713, AC101, WM8978 and ES8388 are recognized models where the proper init sequence/volume/power controls are sent. For other codecs that might require an I2C commands, please use the parameter "dac_controlset" that allows definition of simple commands to be sent over i2c for init, power on and off using a JSON syntax:
-```
-{ init: [ {"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}, ... {{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"} ],
-  poweron: [ {"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}, ... {{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"} ],
-  poweroff: [ {"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}, ... {{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"} ] }
+So far, TAS57xx, TAS5713, AC101, WM8978 and ES8388 are recognized models where the proper init sequence/volume/power controls are sent. For other codecs that might require an I2C commands, please use the parameter "dac_controlset" that allows definition of simple commands to be sent over i2c for init, power, speakder and headset on and off using a JSON syntax:
+```json
+{ <command>: [ {"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}, ... {{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"} ],
+  <command>: [ {"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"}, ... {{"reg":<register>,"val":<value>,"mode":<nothing>|"or"|"and"} ],
+  ... }
 ```
-This is standard JSON notation, so if you are not familiar with it, Google is your best friend. Be aware that the '...' means you can have as many entries as you want, it's not part of the syntax. Every section is optional, but it does not make sense to set i2c in the 'dac_config' parameter and not setting anything here. The parameter 'mode' allows to *or* the register with the value or to *and* it. Don't set 'mode' if you simply want to write. **Note that all values must be decimal**. You can use a validator like [this](https://jsonlint.com) to verify your syntax
+Where `<command>` is one of init, poweron, poweroff, speakeron, speakeroff, headseton, headsetoff
+
+This is standard JSON notation, so if you are not familiar with it, Google is your best friend. Be aware that the '...' means you can have as many entries as you want, it's not part of the syntax. Every section is optional, but it does not make sense to set i2c in the 'dac_config' parameter and not setting anything here. The parameter 'mode' allows to *or* the register with the value or to *and* it. Don't set 'mode' if you simply want to write. The 'val parameter can be an array [v1, v2,...] to write a serie of bytes in a single i2c burst (in that case 'mode' is ignored). **Note that all values must be decimal**. You can use a validator like [this](https://jsonlint.com) to verify your syntax
 
 NB: For specific builds (all except I2S), all this is ignored. For know codecs, the built-in sequences can be overwritten using dac_controlset
 
-<strong>Please note that you can not use the same GPIO or port as the I2C</strong>
+**Please note that you can not use the same GPIO or port as the I2C.**
+
 ### SPDIF
 The NVS parameter "spdif_config" sets the i2s's gpio needed for SPDIF. 
 
@@ -184,25 +216,26 @@ GPIO  ----210ohm-----------||---- coax S/PDIF signal out
                     |
 Ground -------------------------- coax signal ground
 ```
+
 ### Display
-The NVS parameter "display_config" sets the parameters for an optional display. Syntax is
+The NVS parameter "display_config" sets the parameters for an optional display. It can be I2C (see [here](#i2c) for shared bus) or SPI (see [here](#spi) for shared bus) Syntax is
 ```
 I2C,width=<pixels>,height=<pixels>[address=<i2c_address>][,reset=<gpio>][,HFlip][,VFlip][driver=SSD1306|SSD1326[:1|4]|SSD1327|SH1106]
-SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735|ST7789|ILI9341[:16|18][,rotate]]
+SPI,width=<pixels>,height=<pixels>,cs=<gpio>[,back=<gpio>][,reset=<gpio>][,speed=<speed>][,HFlip][,VFlip][driver=SSD1306|SSD1322|SSD1326[:1|4]|SSD1327|SH1106|SSD1675|ST7735[:x=<offset>][:y=<offset>]|ST7789|ILI9341[:16|18][,rotate]]
 ```
 - back: a LED backlight used by some older devices (ST7735). It is PWM controlled for brightness
-- reset: some display have a reset pin that is should normally be pulled up if unused
+- reset: some display have a reset pin that is should normally be pulled up if unused. Most displays require reset and will not initialize well otherwise.
 - VFlip and HFlip are optional can be used to change display orientation
 - rotate: for non-square *drivers*, move to portrait mode. Note that *width* and *height* must be inverted then
 - Default speed is 8000000 (8MHz) but SPI can work up to 26MHz or even 40MHz
-- SH1106 is 128x64 monochrome I2C/SPI [here]((https://www.waveshare.com/wiki/1.3inch_OLED_HAT))
+- SH1106 is 128x64 monochrome I2C/SPI [here](https://www.waveshare.com/wiki/1.3inch_OLED_HAT)
 - SSD1306 is 128x32 monochrome I2C/SPI [here](https://www.buydisplay.com/i2c-blue-0-91-inch-oled-display-module-128x32-arduino-raspberry-pi)
 - SSD1322 is 256x64 grayscale 16-levels SPI in multiple sizes [here](https://www.buydisplay.com/oled-display/oled-display-module?resolution=159) - it is very nice
 - SSD1326 is 256x32 monochrome or grayscale 16-levels SPI [here](https://www.aliexpress.com/item/32833603664.html?spm=a2g0o.productlist.0.0.2d19776cyQvsBi&algo_pvid=c7a3db92-e019-4095-8a28-dfdf0a087f98&algo_expid=c7a3db92-e019-4095-8a28-dfdf0a087f98-1&btsid=0ab6f81e15955375483301352e4208&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_)
 - SSD1327 is 128x128 16-level grayscale SPI [here](https://www.amazon.com/gp/product/B079N1LLG8/ref=ox_sc_act_title_1?smid=A1N6DLY3NQK2VM&psc=1) - artwork can be up to 96x96 with vertical vu-meter/spectrum
 - SSD1351 is 128x128 65k/262k color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/1.5inch-rgb-oled-module.htm)
 - SSD1675 is an e-ink paper and is experimental as e-ink is really not suitable for LMS du to its very low refresh rate
-- ST7735 is a 128x160 65k color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/1.8inch-lcd-module.htm). This needs a backlight control
+- ST7735 is a 128x160 65k color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/1.8inch-lcd-module.htm). This needs a backlight control. Some have X/Y offsets betwen the driver and the glass (green/black/red models) that can be added using "x" and "y" options (case sensitive!)
 - ST7789 is a 240x320 65k (262k not enabled) color SPI [here](https://www.waveshare.com/product/displays/lcd-oled/lcd-oled-3/2inch-lcd-module.htm). It also exist with 240x240 displays. See **rotate** for use in portrait mode
 - ILI9341 is another 240x320 65k (262k capable) color SPI. I've not used it much, the driver it has been provided by one external contributor to the project
 
@@ -210,13 +243,12 @@ You can tweak how the vu-meter and spectrum analyzer are displayed, as well as s
 
 The NVS parameter "metadata_config" sets how metadata is displayed for AirPlay and Bluetooth. Syntax is
 ```
-[format=<display_content>][,speed=<speed>][,pause=<pause>]
+[format=<display_content>][,speed=<speed>][,pause=<pause>][,artwork[:0|1]]
 ```
 - 'speed' is the scrolling speed in ms (default is 33ms)
-
 - 'pause' is the pause time between scrolls in ms (default is 3600ms)
-
-- 'format' can contain free text and any of the 3 keywords %artist%, %album%, %title%. Using that format string, the keywords are replaced by their value to build the string to be displayed. Note that the plain text following a keyword that happens to be empty during playback of a track will be removed. For example, if you have set format=%artist% - %title% and there is no artist in the metadata then only <title> will be displayed not " - <title>".
+- 'format' can contain free text and any of the 3 keywords `%artist%`, `%album%`, `%title%`. Using that format string, the keywords are replaced by their value to build the string to be displayed. Note that the plain text following a keyword that happens to be empty during playback of a track will be removed. For example, if you have set format=`%artist% - %title%` and there is no artist in the metadata then only `<title>` will be displayed not ` - <title>`.
+- 'artwork' enables coverart display, if available (does not work for Bluetooth). The optional parameter indicates if the artwork should be resized (1) to fit the available space. Note that the built-in resizer can only do 2,4 and 8 downsizing, so fit is not optimal. The artwork will be placed at the right of the display for landscape displays and underneath the two information lines for others (there is no user option to tweak that).
 
 ### Infrared
 You can use any IR receiver compatible with NEC protocol (38KHz). Vcc, GND and output are the only pins that need to be connected, no pullup, no filtering capacitor, it's a straight connection.
@@ -232,13 +264,13 @@ The parameter "set_GPIO" is used to assign GPIO to various functions.
 
 GPIO can be set to GND provide or Vcc at boot. This is convenient to power devices that consume less than 40mA from the side connector. Be careful because there is no conflict checks being made wrt which GPIO you're changing, so you might damage your board or create a conflict here. 
 
-The \<amp\> parameter can use used to assign a GPIO that will be set to active level (default 1) when playback starts. It will be reset when squeezelite becomes idle. The idle timeout is set on the squeezelite command line through -C \<timeout\>
+The `<amp>` parameter can use used to assign a GPIO that will be set to active level (default 1) when playback starts. It will be reset when squeezelite becomes idle. The idle timeout is set on the squeezelite command line through `-C <timeout>`
 
 If you have an audio jack that supports insertion (use :0 or :1 to set the level when inserted), you can specify which GPIO it's connected to. Using the parameter jack_mutes_amp allows to mute the amp when headset (e.g.) is inserted.
 
 You can set the Green and Red status led as well with their respective active state (:0 or :1)
 
-The \<ir\> parameter set the GPIO associated to an IR receiver. No need to add pullup or capacitor
+The `<ir>` parameter set the GPIO associated to an IR receiver. No need to add pullup or capacitor
 
 Syntax is:
 
@@ -247,8 +279,29 @@ Syntax is:
 ```
 You can define the defaults for jack, spkfault leds at compile time but nvs parameter takes precedence except for well-known configurations where these are forced at runtime.
 **Note that gpio 36 and 39 are input only and cannot use interrupt. When set to jack or speaker fault, a 100ms polling checks their value but that's expensive**
+ 
+### GPIO expanders
+It is possible to add GPIO expanders using I2C or SPI bus. They should mainly be used for buttons but they can support generic-purpose outputs as well. These additional GPIOs can be numbered starting from an arbitrary value (40 and above as esp32 has GPIO 0..39). Then these new "virtual" GPIOs from (e.g) 100 to 115 can be used in [button](#Buttons) configuration, [set_GPIO](#set-gpio) or other config settings.
+
+Each expander can support up to 32 GPIO. To use an expander for buttons, an interrupt must be provided, polling mode is not acceptable. An expander w/o interruption can still be configured, but only output will be usable. Note that the same interrupt can be shared accross expanders, as long as they are using open drain or open collectors (which they probably all do)
+
+The parameter "gpio_exp_config" is a semicolon (;) separated list with following syntax for each expander
+```
+model=<model>,addr=<addr>,[,port=system|dac][,base=<n>|100][,count=<n>|16][,intr=<gpio>][,cs=<gpio>][,speed=<Hz>]
+```	
+- model: pca9535, pca85xx, mcp23017 and mcp23s17 (SPI version)
+- addr: chip i2c/spi address (decimal)
+- port (I2C): use either "system" port (shared with display for example) or "dac" port (system is default)
+- cs (SPI): gpio used for Chip Select
+- speed (SPI): speed of the SPI bus for that device (in Hz)	
+- base: GPIO numbering offset to use everywhere else (default 40)
+- count: number of GPIO of expander (default 16 - might be obsolted if model if sufficient to decide)
+- intr: real GPIO to use as interrupt.
+	
+Note that PWM ("led_brightness" below) is not supported for expanded GPIOs and they cannot be used for high speed or precise timing signals like CS, D/C, Reset and Ready. Buttons, rotary encoder, amplifier control and power are supported. Depending on the actual chipset, pullup or pulldown might be supported so you might have to add external resistors (only MCP23x17 does pullup). The pca8575 is not a great chip, it generate a fair bit of spurious interrupts when used for GPIO out. When using a SPI expander, the bus must be configured using shared [SPI](#SPI) bus
+
 ### LED 
-See §**set_GPIO** for how to set the green and red LEDs. In addition, their brightness can be controlled using the "led_brigthness" parameter. The syntax is
+See [set_GPIO](#set-gpio) for how to set the green and red LEDs. In addition, their brightness can be controlled using the "led_brigthness" parameter. The syntax is
 ```
 [green=0..100][,red=0..100]
 ```
@@ -293,14 +346,15 @@ The SW gpio is optional, you can re-affect it to a pure button if you prefer but
 See also the "IMPORTANT NOTE" on the "Buttons" section and remember that when 'lms_ctrls_raw' (see below) is activated, none of these knobonly,volume,longpress options apply, raw button codes (not actions) are simply sent to LMS
 
 **Note that gpio 36 and 39 are input only and cannot use interrupt, so they cannot be set to A or B. When using them for SW, a 100ms polling is used which is expensive**
+
 ### Buttons
 Buttons are described using a JSON string with the following syntax
-```
+```json
 [
-{"gpio":<num>,		
- "type":"BUTTON_LOW | BUTTON_HIGH",	
+{"gpio":<num>,
+ "type":"BUTTON_LOW | BUTTON_HIGH",
  "pull":[true|false],
- "long_press":<ms>, 
+ "long_press":<ms>,
  "debounce":<ms>,
  "shifter_gpio":<-1|num>,
  "normal": {"pressed":"<action>","released":"<action>"},
@@ -324,7 +378,7 @@ Where (all parameters are optionals except gpio)
  - "shifted": action to take when a button is pressed/released and shifted (see above/below)
  - "longshifted": action to take when a button is long-pressed/released and shifted (see above/below)
 
-Where \<action\> is either the name of another configuration to load (remap) or one amongst
+Where `<action>` is either the name of another configuration to load (remap) or one amongst
 
 ```
 ACTRLS_NONE, ACTRLS_POWER, ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, 
@@ -337,7 +391,7 @@ KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
 One you've created such a string, use it to fill a new NVS parameter with any name below 16(?) characters. You can have as many of these configs as you can. Then set the config parameter "actrls_config" with the name of your default config
 
 For example a config named "buttons" :
-```
+```json
 [{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,"normal":{"pressed":"ACTRLS_VOLDOWN"},"longpress":{"pressed":"buttons_remap"}},
  {"gpio":5,"type":"BUTTON_LOW","pull":true,"shifter_gpio":4,"normal":{"pressed":"ACTRLS_VOLUP"}, "shifted":{"pressed":"ACTRLS_TOGGLE"}}]
 ``` 
@@ -346,7 +400,7 @@ Defines two buttons
 - second on GPIO 5, active low. When pressed it triggers a volume up command. If first button is pressed together with this button, then a play/pause toggle command is generated.
 
 While the config named "buttons_remap"
-```
+```json
 [{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,"normal":{"pressed":"BCTRLS_DOWN"},"longpress":{"pressed":"buttons"}},
  {"gpio":5,"type":"BUTTON_LOW","pull":true,"shifter_gpio":4,"normal":{"pressed":"BCTRLS_UP"}}]
 ``` 
@@ -354,10 +408,14 @@ Defines two buttons
 - first on GPIO 4, active low. When pressed, it triggers a navigation down command. When pressed more than 1000ms, it changes the button configuration for the one described above
 - second on GPIO 5, active low. When pressed it triggers a navigation up command. That button, in that configuration, has no shift option
 
-Below is a difficult but functional 2-buttons interface for your decoding pleasure
+Below is a difficult but functional 2-buttons interface for your decoding pleasure:
 
-*buttons*
+`actrls_config`:
 ```
+buttons
+```
+`buttons`:
+```json
 [{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,
  "normal":{"pressed":"ACTRLS_VOLDOWN"},
  "longpress":{"pressed":"buttons_remap"}},
@@ -367,8 +425,8 @@ Below is a difficult but functional 2-buttons interface for your decoding pleasu
  "longpress":{"pressed":"ACTRLS_NEXT"}}
 ]
 ```
-*buttons_remap*
-```
+`buttons_remap`:
+```json
 [{"gpio":4,"type":"BUTTON_LOW","pull":true,"long_press":1000,
  "normal":{"pressed":"BCTRLS_DOWN"},
  "longpress":{"pressed":"buttons"}},
@@ -379,18 +437,20 @@ Below is a difficult but functional 2-buttons interface for your decoding pleasu
  "longshifted":{"pressed":"BCTRLS_LEFT"}}
 ]
 ```
-<strong>IMPORTANT NOTE</strong>: LMS also supports the possibility to send 'raw' button codes. It's a bit complicated, so bear with me. Buttons can either be processed by SqueezeESP32 and mapped to a "function" like play/pause or they can be just sent to LMS as plain (raw) code and the full logic of press/release/longpress is handled by LMS, you don't have any control on that.
+**IMPORTANT NOTE**: LMS also supports the possibility to send 'raw' button codes. It's a bit complicated, so bear with me. Buttons can either be processed by SqueezeESP32 and mapped to a "function" like play/pause or they can be just sent to LMS as plain (raw) code and the full logic of press/release/longpress is handled by LMS, you don't have any control on that.
 
-The benefit of the "raw" mode is that you can build a player which is as close as possible to a Boom (e.g.) but you can't use the remapping function nor longress or shift logics to do your own mapping when you have a limited set of buttons. In 'raw' mode, all you really need to define is the mapping between the gpio and the button. As far as LMS is concerned, any other option in these JSON payloads does not matter. Now, when you use BT or AirPlay, the full JSON construct described above fully applies, so the shift, longpress, remapping options still work. 
+The benefit of the "raw" mode is that you can build a player which is as close as possible to a Boom (e.g.) but you can't use the remapping function nor longress or shift logics to do your own mapping when you have a limited set of buttons. In 'raw' mode, all you really need to define is the mapping between the gpio and the button. As far as LMS is concerned, any other option in these JSON payloads does not matter. Now, when you use BT or AirPlay, the full JSON construct described above fully applies, so the shift, longpress, remapping options still work.
 
 **Be aware that when using non "raw" mode, the CLI (Command Line Interface) of LMS is used and *must* be available without password**
 
 There is no good or bad option, it's your choice. Use the NVS parameter "lms_ctrls_raw" to change that option
 	
 **Note that gpio 36 and 39 are input only and cannot use interrupt. When using them for a button, a 100ms polling is started which is expensive. Long press is also likely to not work very well**
-### Ethernet (coming soon)
-Wired ethernet is supported by esp32 with various options but squeezelite is only supporting a Microchip LAN8720 with a RMII interface like [this](https://www.aliexpress.com/item/32858432526.html) or Davicom DM9051 over SPI like [that](https://www.amazon.com/dp/B08JLFWX9Z).
-	
+### Ethernet 
+Wired ethernet is supported by esp32 with various options but squeezelite is only supporting a Microchip LAN8720 with a RMII interface like [this](https://www.aliexpress.com/item/32858432526.html) or SPI-ethernet bridges like Davicom DM9051 [that](https://www.amazon.com/dp/B08JLFWX9Z) or W5500 like [this](https://www.aliexpress.com/item/32312441357.html).
+
+**Note:** Touch buttons that can be find on some board like the LyraT V4.3 are not supported currently.
+
 #### RMII (LAN8720)	
 - RMII PHY wiring is fixed and can not be changed
 
@@ -402,6 +462,7 @@ Wired ethernet is supported by esp32 with various options but squeezelite is onl
 | GPIO25 | RX0         | EMAC_RXD0    |
 | GPIO26 | RX1         | EMAC_RXD1    |
 | GPIO27 | CRS_DV      | EMAC_RX_DRV  |
+| GPIO0  | REF_CLK     | 50MHz clock  |
 
 - SMI (Serial Management Interface) wiring is not fixed and you can change it either in the configuration or using "eth_config" parameter with the following syntax:
 ```
@@ -411,30 +472,31 @@ Connecting a reset pin for the LAN8720 is optional but recommended to avoid that
 - Clock
 	
 The APLL of the esp32 is required for the audio codec, so we **need** a LAN8720 that provides a 50MHz clock. That clock **must** be connected to GPIO0, there is no alternative. This means that if your DAC requires an MCLK, then you are out of luck. It is not possible to have both to work together. There might be some workaround using CLK_OUT2 and GPIO3, but I don't have time for this.
-#### SPI (DM9051)
-Ethernet over SPI is supported as well and requires less GPIOs but is obvsiously slower. Another benefit is that the SPI bus can be shared with the display, but it's also possible to have a dedicated SPI interface. The esp32 has 4 SPI sub-systems, one is unaccessible so numbering is 0..2 and SPI0 is reserved for Flash/PSRAM. The "eth_config" parameter syntax becomes:
+#### SPI (DM9051 or W5500)
+Ethernet over SPI is supported as well and requires less GPIOs but is obvsiously slower. SPI is the shared bus set with [spi_config](#spi). The "eth_config" parameter syntax becomes:
 ```
-model=dm9051,cs=<gpio>,speed=<clk_in_Hz>,intr=<gpio>[,host=<-1|1|2>][,rst=<gpio>][,mosi=<gpio>,miso=<gpio>,clk=<gpio>]
+model=dm9051|w5500,cs=<gpio>,speed=<clk_in_Hz>,intr=<gpio>[,rst=<gpio>]
 ```
 - To use the system SPI, shared with display (see spi_config) "host" must be set to -1. Any other value will reserve the SPI interface (careful of conflict with spi_config). The default "host" is 2 to avoid conflicting wiht default "spi_config" settings.
 - When not using system SPI, "mosi" for data out, "miso" for data in and "clk" **must** be set
 - The esp32 has a special I/O multiplexer for faster speed (up to 80 MHz) but that requires using specific GPIOs, which depends on SPI bus (See [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/spi_master.html) for more details)
 
-| Pin Name | SPI2 | SPI3 |
+| Pin Name | SPI1 | SPI2 |
 | -------- | ---- | ---- |		
-| CS0*     |  15  |  5   |
+| CS       |  15  |  5   |
 | SCLK	   |  14  |  18  |
 | MISO	   |  12  |  19  |
 | MOSI	   |  13  |  23  |
 	
-** THIS IS NOT AVAILABLE YET, SO MORE TO COME ON HOW TO USE WIRED ETHERNET***
 ### Battery / ADC
 The NVS parameter "bat_config" sets the ADC1 channel used to measure battery/DC voltage. The "atten" value attenuates the input voltage to the ADC input (the read value maintains a 0-1V rage) where: 0=no attenuation(0..800mV), 1=2.5dB attenuation(0..1.1V), 2=6dB attenuation(0..1.35V), 3=11dB attenuation(0..2.6V). Scale is a float ratio applied to every sample of the 12 bits ADC. A measure is taken every 10s and an average is made every 5 minutes (not a sliding window). Syntax is
 ```
 channel=0..7,scale=<scale>,cells=<2|3>[,atten=<0|1|2|3>]
 ```
 NB: Set parameter to empty to disable battery reading. For well-known configuration, this is ignored (except for SqueezeAMP where number of cells is required)
+
 # Configuration
+
 ## Setup WiFi
 - Boot the esp, look for a new wifi access point showing up and connect to it. Default build ssid and passwords are "squeezelite"/"squeezelite". 
 - Once connected, navigate to 192.168.4.1 
@@ -443,7 +505,6 @@ NB: Set parameter to empty to disable battery reading. For well-known configurat
 - Once connection is established, note down the address the device received; this is the address you will use to configure it going forward 
 
 ## Setup squeezelite command line (optional)
-
 At this point, the device should have disabled its built-in access point and should be connected to a known WiFi network.
 - navigate to the address that was noted in step #1
 - Using the list of predefined options, choose the mode in which you want squeezelite to start
@@ -456,7 +517,6 @@ At this point, the device should have disabled its built-in access point and sho
 - You can enable accessto  NVS parameters under 'credits'
 
 ## Monitor
-
 In addition of the esp-idf serial link monitor option, you can also enable a telnet server (see NVS parameters) where you'll have access to a ton of logs of what's happening inside the WROVER.
 
 ## Update Squeezelite
@@ -488,20 +548,23 @@ See squeezlite command line, but keys options are
 	- r "<minrate>-<maxrate>"
 	- C <sec> : set timeout to switch off amp gpio
 	- W : activate WAV and AIFF header parsing
+
 # Building everything yourself
+
 ## Setting up ESP-IDF
+
 ### Docker
 A simple alternative to building the project's binaries is to leverage the same docker image that is being used on the GitHub Actions to build our releases. The instructions below assume that you have cloned  the squeezelite-esp32 code that you want to build locally and that you have opened a command line/bash session in the folder that contains the code. 
 Pull the most recent docker image for the environment: 
 ```
-docker pull sle118/squeezelite-esp32-idfv4-master
+docker pull sle118/squeezelite-esp32-idfv43
 ```
 Then run the container interactively :
 ```
 for windows:
-docker run -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv4-master
+docker run -v %cd%:/project -w /project -it sle118/squeezelite-esp32-idfv43
 for linux:
-docker run -it -v `pwd`:/workspace/squeezelite-esp32 sle118/squeezelite-esp32-idfv4-master
+docker run -it -v `pwd`:/workspace/squeezelite-esp32 sle118/squeezelite-esp32-idfv43
 ```
 The above command will mount this repo into the docker container and start a bash terminal. From there, simply run idf.py build to build, etc. Note that at the time of writing these lines, flashing is not possible for docker running under windows https://github.com/docker/for-win/issues/1018.
 
@@ -524,6 +587,7 @@ Use `idf.py monitor` to monitor the application (see esp-idf documentation)
 Note: You can use `idf.py build -DDEPTH=32` to build the 32 bits version and add the `-DVERSION=<your_version>` to add a custom version name (it will be 0.0-<your_version>). If you want to change the whole version string, see squeezelite.h. You can also disable the SBR extension of AAC codecs as it consumes a lot of CPU and might overload the esp32. Use `-DAAC_DISABLE_SBR=1` for that
 
 If you have already cloned the repository and you are getting compile errors on one of the submodules (e.g. telnet), run the following git command in the root of the repository location: `git submodule update --init --recursive`
+
 ### Rebuild codecs (highly recommended to NOT try that)
 - for codecs libraries, add -mlongcalls if you want to rebuild them, but you should not (use the provided ones in codecs/lib). if you really want to rebuild them, open an issue
 - libmad, libflac (no esp's version), libvorbis (tremor - not esp's version), alac work

+ 4 - 5
build-scripts/I2S-4MFlash-sdkconfig.defaults

@@ -942,11 +942,10 @@ CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
 # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
 CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
 CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
-CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_ABORT is not set
+CONFIG_FREERTOS_ASSERT_DISABLE=y
+CONFIG_FREERTOS_ISR_STACKSIZE=2096
 # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
-# CONFIG_FREERTOS_ASSERT_DISABLE is not set
-CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
-CONFIG_FREERTOS_ISR_STACKSIZE=1536
 # CONFIG_FREERTOS_LEGACY_HOOKS is not set
 CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
@@ -1119,7 +1118,7 @@ CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
 CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
 # end of SNTP
 
-# CONFIG_LWIP_ESP_LWIP_ASSERT is not set
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
 
 #
 # Hooks

+ 4 - 5
build-scripts/Muse-sdkconfig.defaults

@@ -901,11 +901,10 @@ CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
 # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
 CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
 CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
-CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_ABORT is not set
+CONFIG_FREERTOS_ASSERT_DISABLE=y
+CONFIG_FREERTOS_ISR_STACKSIZE=2096
 # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
-# CONFIG_FREERTOS_ASSERT_DISABLE is not set
-CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
-CONFIG_FREERTOS_ISR_STACKSIZE=1536
 # CONFIG_FREERTOS_LEGACY_HOOKS is not set
 CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
@@ -1078,7 +1077,7 @@ CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
 CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
 # end of SNTP
 
-# CONFIG_LWIP_ESP_LWIP_ASSERT is not set
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
 
 #
 # Hooks

+ 5 - 6
build-scripts/SqueezeAmp-sdkconfig.defaults

@@ -259,7 +259,7 @@ CONFIG_CSPOT_SINK=y
 # Various I/O
 #
 CONFIG_I2C_CONFIG=""
-CONFIG_SET_GPIO=""
+CONFIG_SET_GPIO="0=ir"
 CONFIG_ROTARY_ENCODER=""
 # end of Various I/O
 
@@ -912,11 +912,10 @@ CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
 # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
 CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
 CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
-CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_ABORT is not set
+CONFIG_FREERTOS_ASSERT_DISABLE=y
+CONFIG_FREERTOS_ISR_STACKSIZE=2096
 # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
-# CONFIG_FREERTOS_ASSERT_DISABLE is not set
-CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
-CONFIG_FREERTOS_ISR_STACKSIZE=1536
 # CONFIG_FREERTOS_LEGACY_HOOKS is not set
 CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
 CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
@@ -1089,7 +1088,7 @@ CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
 CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
 # end of SNTP
 
-# CONFIG_LWIP_ESP_LWIP_ASSERT is not set
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
 
 #
 # Hooks

+ 1 - 3
components/codecs/CMakeLists.txt

@@ -1,5 +1,5 @@
 idf_component_register(
-	   INCLUDE_DIRS . ./inc inc/alac inc/FLAC inc/helix-aac inc/mad inc/ogg inc/opus inc/opusfile inc/resample16 inc/soxr inc/vorbis
+	   INCLUDE_DIRS . ./inc inc/alac inc/helix-aac inc/mad inc/resample16 inc/soxr inc/vorbis inc/opus
 )
 
 if (DEFINED AAC_DISABLE_SBR)
@@ -14,7 +14,6 @@ add_prebuilt_library(libvorbisidec 	lib/libvorbisidec.a )
 add_prebuilt_library(libogg 		lib/libogg.a )
 add_prebuilt_library(libalac 		lib/libalac.a ) 
 add_prebuilt_library(libresample16 	lib/libresample16.a ) 
-add_prebuilt_library(libopusfile 	lib/libopusfile.a ) 
 add_prebuilt_library(libopus 		lib/libopus.a ) 
 
 target_link_libraries(${COMPONENT_LIB} INTERFACE libmad)
@@ -24,5 +23,4 @@ target_link_libraries(${COMPONENT_LIB} INTERFACE libvorbisidec)
 target_link_libraries(${COMPONENT_LIB} INTERFACE libogg)
 target_link_libraries(${COMPONENT_LIB} INTERFACE libalac)
 target_link_libraries(${COMPONENT_LIB} INTERFACE libresample16)
-target_link_libraries(${COMPONENT_LIB} INTERFACE libopusfile)
 target_link_libraries(${COMPONENT_LIB} INTERFACE libopus)

+ 90 - 11
components/codecs/inc/FLAC/all.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -35,8 +35,8 @@
 
 #include "export.h"
 
+#include "assert.h"
 #include "callback.h"
-#include "flac_assert.h"
 #include "format.h"
 #include "metadata.h"
 #include "ordinals.h"
@@ -52,7 +52,7 @@
  * level idea of the structure and how to find the information you
  * need.  As a prerequisite you should have at least a basic
  * knowledge of the FLAC format, documented
- * <A HREF="../format.html">here</A>.
+ * <A HREF="https://xiph.org/flac/format.html">here</A>.
  *
  * \section c_api FLAC C API
  *
@@ -64,7 +64,7 @@
  *
  * By writing a little code and linking against libFLAC, it is
  * relatively easy to add FLAC support to another program.  The
- * library is licensed under <A HREF="../license.html">Xiph's BSD license</A>.
+ * library is licensed under <A HREF="https://xiph.org/flac/license.html">Xiph's BSD license</A>.
  * Complete source code of libFLAC as well as the command-line
  * encoder and plugins is available and is a useful source of
  * examples.
@@ -97,7 +97,7 @@
  * example /usr/include/FLAC++/...).
  *
  * libFLAC++ is also licensed under
- * <A HREF="../license.html">Xiph's BSD license</A>.
+ * <A HREF="https://xiph.org/flac/license.html">Xiph's BSD license</A>.
  *
  * \section getting_started Getting Started
  *
@@ -113,7 +113,7 @@
  * functions through the links in top bar across this page.
  *
  * If you prefer a more hands-on approach, you can jump right to some
- * <A HREF="../documentation_example_code.html">example code</A>.
+ * <A HREF="https://xiph.org/flac/documentation_example_code.html">example code</A>.
  *
  * \section porting_guide Porting Guide
  *
@@ -147,7 +147,7 @@
  * library.
  *
  * Also, there are several places in the libFLAC code with comments marked
- * with "OPT:" where a #define can be changed to enable code that might be
+ * with "OPT:" where a \#define can be changed to enable code that might be
  * faster on a specific platform.  Experimenting with these can yield faster
  * binaries.
  */
@@ -159,9 +159,9 @@
  * the libraries to newer versions of FLAC.
  *
  * One simple facility for making porting easier that has been added
- * in FLAC 1.1.3 is a set of \c #defines in \c export.h of each
+ * in FLAC 1.1.3 is a set of \#defines in \c export.h of each
  * library's includes (e.g. \c include/FLAC/export.h).  The
- * \c #defines mirror the libraries'
+ * \#defines mirror the libraries'
  * <A HREF="http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning">libtool version numbers</A>,
  * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT,
  * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE.
@@ -176,7 +176,7 @@
  * #endif
  * \endcode
  *
- * The the source will work for multiple versions and the legacy code can
+ * The source will work for multiple versions and the legacy code can
  * easily be removed when the transition is complete.
  *
  * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in
@@ -321,7 +321,7 @@
  *
  * The \a bytes parameter to FLAC__StreamDecoderReadCallback,
  * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback
- * is now \c size_t instead of \c unsigned.
+ * is now \c size_t instead of \c uint32_t.
  */
 
 /** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4
@@ -357,6 +357,85 @@
  * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN
  */
 
+/** \defgroup porting_1_3_4_to_1_4_0 Porting from FLAC 1.3.4 to 1.4.0
+ *  \ingroup porting
+ *
+ *  \brief
+ *  This module describes porting from FLAC 1.3.4 to FLAC 1.4.0.
+ *
+ * \section porting_1_3_4_to_1_4_0_summary Summary
+ *
+ * Between FLAC 1.3.4 and FLAC 1.4.0, there have four breaking changes
+ * - the function get_client_data_from_decoder has been renamed to
+ *   FLAC__get_decoder_client_data
+ * - some data types in the FLAC__Frame struct have changed
+ * - all functions resizing metadata blocks now return the object
+ *   untouched if memory allocation fails, whereas previously the
+ *   handling varied and was more or less undefined
+ * - all functions accepting a filename now take UTF-8 encoded filenames
+ *   on Windows instead of filenames in the current codepage
+ *
+ * Furthermore, there have been the following additions
+ * - the functions FLAC__stream_encoder_set_limit_min_bitrate,
+ *   FLAC__stream_encoder_get_limit_min_bitrate,
+ *   FLAC::encoder::file::set_limit_min_bitrate() and
+ *   FLAC::encoder::file::get_limit_min_bitrate() have been added
+ * - Added FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA to the
+ *   FLAC__StreamDecoderErrorStatus enum
+ *
+ * \section porting_1_3_4_to_1_4_0_breaking Breaking changes
+ *
+ * The function \b get_client_data_from_decoder was added in FLAC 1.3.3
+ * but did not follow the API naming convention and was not properly
+ * exported. The function is now renamed and properly integrated as
+ * FLAC__stream_decoder_get_client_data
+ *
+ * To accomodate encoding and decoding 32-bit int PCM, some data types
+ * in the \b FLAC__frame struct were changed. Specifically, warmup
+ * in both the FLAC__Subframe_Fixed struc and the FLAC__Subframe_LPC
+ * struct is changed from FLAC__int32 to FLAC__int64. Also, value
+ * in the FLAC__Subframe_Constant is changed from FLAC__int32 to
+ * FLAC__int64. Finally, in FLAC__Subframe_Verbatim struct data is
+ * changes from a FLAC__int32 array to a union containing a FLAC__int32
+ * array and a FLAC__int64 array. Also, a new member is added,
+ * data_type, which clarifies whether the FLAC__int32 or FLAC__int64
+ * array is in use.
+ *
+ * Furthermore, the following functions now return the object untouched
+ * if memory allocation fails, whereas previously the handling varied
+ * and was more or less undefined
+ *
+ * - FLAC__metadata_object_seektable_resize_points
+ * - FLAC__metadata_object_vorbiscomment_resize_comments
+ * - FLAC__metadata_object_cuesheet_track_resize_indices
+ * - FLAC__metadata_object_cuesheet_resize_tracks
+ *
+ * The last breaking change is that all API functions taking a filename
+ * as an argument now, on Windows, must be supplied with that filename
+ * in the UTF-8 character encoding instead of using the current code
+ * page. libFLAC internally translates these UTF-8 encoded filenames to
+ * an appropriate representation to use with _wfopen. On all other
+ * systems, filename is passed to fopen without any translation, as it
+ * in libFLAC 1.3.4 and earlier.
+ *
+ * \section porting_1_3_4_to_1_4_0_additions Additions
+ *
+ * To aid in creating properly streamable FLAC files, a set of functions
+ * was added to make it possible to enfore a minimum bitrate to files
+ * created through libFLAC's stream_encoder.h interface. With this
+ * function enabled the resulting FLAC files have a minimum bitrate of
+ * 1bit/sample independent of the number of channels, i.e. 48kbit/s for
+ * 48kHz. This can be beneficial for streaming, as very low bitrates for
+ * silent sections compressed with 'constant' subframes can result in a
+ * bitrate of 1kbit/s, creating problems with clients that aren't aware
+ * of this possibility and buffer too much data.
+ *
+ * Finally, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA was added to
+ * the FLAC__StreamDecoderErrorStatus enum to signal that the decoder
+ * encountered unreadable metadata.
+ *
+ */
+
 /** \defgroup flac FLAC C API
  *
  * The FLAC C API is the interface to libFLAC, a set of structures

+ 7 - 2
components/codecs/inc/FLAC/flac_assert.h → components/codecs/inc/FLAC/assert.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,7 +34,11 @@
 #define FLAC__ASSERT_H
 
 /* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */
-#ifdef DEBUG
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+#define FLAC__ASSERT(x) if(!(x)) __builtin_abort();
+#define FLAC__ASSERT_DECLARATION(x) x
+#else
+#ifndef NDEBUG
 #include <assert.h>
 #define FLAC__ASSERT(x) assert(x)
 #define FLAC__ASSERT_DECLARATION(x) x
@@ -42,5 +46,6 @@
 #define FLAC__ASSERT(x)
 #define FLAC__ASSERT_DECLARATION(x)
 #endif
+#endif
 
 #endif

+ 8 - 8
components/codecs/inc/FLAC/callback.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2004-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -165,15 +165,15 @@ typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle);
  *  required may be set to NULL.
  *
  *  If the seek requirement for an interface is optional, you can signify that
- *  a data sorce is not seekable by setting the \a seek field to \c NULL.
+ *  a data source is not seekable by setting the \a seek field to \c NULL.
  */
 typedef struct {
-	FLAC__IOCallback_Read read;
-	FLAC__IOCallback_Write write;
-	FLAC__IOCallback_Seek seek;
-	FLAC__IOCallback_Tell tell;
-	FLAC__IOCallback_Eof eof;
-	FLAC__IOCallback_Close close;
+	FLAC__IOCallback_Read read;   /**< See FLAC__IOCallbacks */
+	FLAC__IOCallback_Write write; /**< See FLAC__IOCallbacks */
+	FLAC__IOCallback_Seek seek;   /**< See FLAC__IOCallbacks */
+	FLAC__IOCallback_Tell tell;   /**< See FLAC__IOCallbacks */
+	FLAC__IOCallback_Eof eof;     /**< See FLAC__IOCallbacks */
+	FLAC__IOCallback_Close close; /**< See FLAC__IOCallbacks */
 } FLAC__IOCallbacks;
 
 /* \} */

+ 30 - 12
components/codecs/inc/FLAC/export.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -36,7 +36,7 @@
 /** \file include/FLAC/export.h
  *
  *  \brief
- *  This module contains #defines and symbols for exporting function
+ *  This module contains \#defines and symbols for exporting function
  *  calls, and providing version information and compiled-in features.
  *
  *  See the \link flac_export export \endlink module.
@@ -46,25 +46,43 @@
  *  \ingroup flac
  *
  *  \brief
- *  This module contains #defines and symbols for exporting function
+ *  This module contains \#defines and symbols for exporting function
  *  calls, and providing version information and compiled-in features.
  *
- *  If you are compiling with MSVC and will link to the static library
- *  (libFLAC.lib) you should define FLAC__NO_DLL in your project to
- *  make sure the symbols are exported properly.
+ *  If you are compiling for Windows (with Visual Studio or MinGW for
+ *  example) and will link to the static library (libFLAC++.lib) you
+ *  should define FLAC__NO_DLL in your project to make sure the symbols
+ *  are exported properly.
  *
  * \{
  */
 
-#if defined(FLAC__NO_DLL)
-#define FLAC_API
+/** This \#define is used internally in libFLAC and its headers to make
+ * sure the correct symbols are exported when working with shared
+ * libraries. On Windows, this \#define is set to __declspec(dllexport)
+ * when compiling libFLAC into a library and to __declspec(dllimport)
+ * when the headers are used to link to that DLL. On non-Windows systems
+ * it is used to set symbol visibility.
+ *
+ * Because of this, the define FLAC__NO_DLL must be defined when linking
+ * to libFLAC statically or linking will fail.
+ */
+/* This has grown quite complicated. FLAC__NO_DLL is used by MSVC sln
+ * files and CMake, which build either static or shared. autotools can
+ * build static, shared or **both**. Therefore, DLL_EXPORT, which is set
+ * by libtool, must override FLAC__NO_DLL on building shared components
+ */
+#if defined(_WIN32)
 
-#elif defined(_MSC_VER)
+#if defined(FLAC__NO_DLL) && !(defined(DLL_EXPORT))
+#define FLAC_API
+#else
 #ifdef FLAC_API_EXPORTS
 #define	FLAC_API __declspec(dllexport)
 #else
 #define FLAC_API __declspec(dllimport)
 #endif
+#endif
 
 #elif defined(FLAC__USE_VISIBILITY_ATTR)
 #define FLAC_API __attribute__ ((visibility ("default")))
@@ -74,12 +92,12 @@
 
 #endif
 
-/** These #defines will mirror the libtool-based library version number, see
+/** These \#defines will mirror the libtool-based library version number, see
  * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning
  */
-#define FLAC_API_VERSION_CURRENT 11
+#define FLAC_API_VERSION_CURRENT 12
 #define FLAC_API_VERSION_REVISION 0 /**< see above */
-#define FLAC_API_VERSION_AGE 3 /**< see above */
+#define FLAC_API_VERSION_AGE 0 /**< see above */
 
 #ifdef __cplusplus
 extern "C" {

+ 154 - 147
components/codecs/inc/FLAC/format.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -60,7 +60,7 @@ extern "C" {
  *  structures used by the rest of the interfaces.
  *
  *  First, you should be familiar with the
- *  <A HREF="../format.html">FLAC format</A>.  Many of the values here
+ *  <A HREF="https://xiph.org/flac/format.html">FLAC format</A>.  Many of the values here
  *  follow directly from the specification.  As a user of libFLAC, the
  *  interesting parts really are the structures that describe the frame
  *  header and metadata blocks.
@@ -113,19 +113,16 @@ extern "C" {
 
 /** The maximum sample resolution permitted by libFLAC.
  *
- * \warning
  * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format.  However,
- * the reference encoder/decoder is currently limited to 24 bits because
- * of prevalent 32-bit math, so make sure and use this value when
- * appropriate.
+ * the reference encoder/decoder used to be limited to 24 bits. This
+ * value was used to signal that limit.
  */
-#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (24u)
+#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (32u)
 
 /** The maximum sample rate permitted by the format.  The value is
- *  ((2 ^ 16) - 1) * 10; see <A HREF="../format.html">FLAC format</A>
- *  as to why.
+ *  ((2 ^ 20) - 1)
  */
-#define FLAC__MAX_SAMPLE_RATE (655350u)
+#define FLAC__MAX_SAMPLE_RATE (1048575u)
 
 /** The maximum LPC order permitted by the format. */
 #define FLAC__MAX_LPC_ORDER (32u)
@@ -173,10 +170,10 @@ extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */
 /** The 32-bit integer big-endian representation of the beginning of
  *  a FLAC stream.
  */
-extern FLAC_API const unsigned FLAC__STREAM_SYNC; /* = 0x664C6143 */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */
 
 /** The length of the FLAC signature in bits. */
-extern FLAC_API const unsigned FLAC__STREAM_SYNC_LEN; /* = 32 bits */
+extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */
 
 /** The length of the FLAC signature in bytes. */
 #define FLAC__STREAM_SYNC_LENGTH (4u)
@@ -213,26 +210,26 @@ extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[];
  */
 typedef struct {
 
-	unsigned *parameters;
+	uint32_t *parameters;
 	/**< The Rice parameters for each context. */
 
-	unsigned *raw_bits;
+	uint32_t *raw_bits;
 	/**< Widths for escape-coded partitions.  Will be non-zero for escaped
 	 * partitions and zero for unescaped partitions.
 	 */
 
-	unsigned capacity_by_order;
+	uint32_t capacity_by_order;
 	/**< The capacity of the \a parameters and \a raw_bits arrays
 	 * specified as an order, i.e. the number of array elements
 	 * allocated is 2 ^ \a capacity_by_order.
 	 */
 } FLAC__EntropyCodingMethod_PartitionedRiceContents;
 
-/** Header for a Rice partitioned residual.  (c.f. <A HREF="../format.html#partitioned_rice">format specification</A>)
+/** Header for a Rice partitioned residual.  (c.f. <A HREF="https://xiph.org/flac/format.html#partitioned_rice">format specification</A>)
  */
 typedef struct {
 
-	unsigned order;
+	uint32_t order;
 	/**< The partition order, i.e. # of contexts = 2 ^ \a order. */
 
 	const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents;
@@ -240,17 +237,17 @@ typedef struct {
 
 } FLAC__EntropyCodingMethod_PartitionedRice;
 
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */
 
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER;
 /**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER;
 /**< == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */
 
-/** Header for the entropy coding method.  (c.f. <A HREF="../format.html#residual">format specification</A>)
+/** Header for the entropy coding method.  (c.f. <A HREF="https://xiph.org/flac/format.html#residual">format specification</A>)
  */
 typedef struct {
 	FLAC__EntropyCodingMethodType type;
@@ -259,7 +256,7 @@ typedef struct {
 	} data;
 } FLAC__EntropyCodingMethod;
 
-extern FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
+extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */
 
 /*****************************************************************************/
 
@@ -279,30 +276,40 @@ typedef enum {
 extern FLAC_API const char * const FLAC__SubframeTypeString[];
 
 
-/** CONSTANT subframe.  (c.f. <A HREF="../format.html#subframe_constant">format specification</A>)
+/** CONSTANT subframe.  (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_constant">format specification</A>)
  */
 typedef struct {
-	FLAC__int32 value; /**< The constant signal value. */
+	FLAC__int64 value; /**< The constant signal value. */
 } FLAC__Subframe_Constant;
 
+/** An enumeration of the possible verbatim subframe data types. */
+typedef enum {
+	FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32, /**< verbatim subframe has 32-bit int */
+	FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64 /**< verbatim subframe has 64-bit int */
+} FLAC__VerbatimSubframeDataType;
+
 
-/** VERBATIM subframe.  (c.f. <A HREF="../format.html#subframe_verbatim">format specification</A>)
+/** VERBATIM subframe.  (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_verbatim">format specification</A>)
  */
 typedef struct {
-	const FLAC__int32 *data; /**< A pointer to verbatim signal. */
+	union {
+		const FLAC__int32 *int32; /**< A FLAC__int32 pointer to verbatim signal. */
+		const FLAC__int64 *int64; /**< A FLAC__int64 pointer to verbatim signal. */
+	} data;
+	FLAC__VerbatimSubframeDataType data_type;
 } FLAC__Subframe_Verbatim;
 
 
-/** FIXED subframe.  (c.f. <A HREF="../format.html#subframe_fixed">format specification</A>)
+/** FIXED subframe.  (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_fixed">format specification</A>)
  */
 typedef struct {
 	FLAC__EntropyCodingMethod entropy_coding_method;
 	/**< The residual coding method. */
 
-	unsigned order;
+	uint32_t order;
 	/**< The polynomial order. */
 
-	FLAC__int32 warmup[FLAC__MAX_FIXED_ORDER];
+	FLAC__int64 warmup[FLAC__MAX_FIXED_ORDER];
 	/**< Warmup samples to prime the predictor, length == order. */
 
 	const FLAC__int32 *residual;
@@ -310,16 +317,16 @@ typedef struct {
 } FLAC__Subframe_Fixed;
 
 
-/** LPC subframe.  (c.f. <A HREF="../format.html#subframe_lpc">format specification</A>)
+/** LPC subframe.  (c.f. <A HREF="https://xiph.org/flac/format.html#subframe_lpc">format specification</A>)
  */
 typedef struct {
 	FLAC__EntropyCodingMethod entropy_coding_method;
 	/**< The residual coding method. */
 
-	unsigned order;
+	uint32_t order;
 	/**< The FIR order. */
 
-	unsigned qlp_coeff_precision;
+	uint32_t qlp_coeff_precision;
 	/**< Quantized FIR filter coefficient precision in bits. */
 
 	int quantization_level;
@@ -328,18 +335,18 @@ typedef struct {
 	FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER];
 	/**< FIR filter coefficients. */
 
-	FLAC__int32 warmup[FLAC__MAX_LPC_ORDER];
+	FLAC__int64 warmup[FLAC__MAX_LPC_ORDER];
 	/**< Warmup samples to prime the predictor, length == order. */
 
 	const FLAC__int32 *residual;
 	/**< The residual signal, length == (blocksize minus order) samples. */
 } FLAC__Subframe_LPC;
 
-extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */
 
 
-/** FLAC subframe structure.  (c.f. <A HREF="../format.html#subframe">format specification</A>)
+/** FLAC subframe structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#subframe">format specification</A>)
  */
 typedef struct {
 	FLAC__SubframeType type;
@@ -349,7 +356,7 @@ typedef struct {
 		FLAC__Subframe_LPC lpc;
 		FLAC__Subframe_Verbatim verbatim;
 	} data;
-	unsigned wasted_bits;
+	uint32_t wasted_bits;
 } FLAC__Subframe;
 
 /** == 1 (bit)
@@ -359,14 +366,14 @@ typedef struct {
  * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1
  * to mean something else.
  */
-extern FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN;
-extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
-extern FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN;
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */
 
-extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
-extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
-extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
-extern FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */
+extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */
 
 /*****************************************************************************/
 
@@ -406,22 +413,22 @@ typedef enum {
 extern FLAC_API const char * const FLAC__FrameNumberTypeString[];
 
 
-/** FLAC frame header structure.  (c.f. <A HREF="../format.html#frame_header">format specification</A>)
+/** FLAC frame header structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#frame_header">format specification</A>)
  */
 typedef struct {
-	unsigned blocksize;
+	uint32_t blocksize;
 	/**< The number of samples per subframe. */
 
-	unsigned sample_rate;
+	uint32_t sample_rate;
 	/**< The sample rate in Hz. */
 
-	unsigned channels;
+	uint32_t channels;
 	/**< The number of channels (== number of subframes). */
 
 	FLAC__ChannelAssignment channel_assignment;
 	/**< The channel assignment for the frame. */
 
-	unsigned bits_per_sample;
+	uint32_t bits_per_sample;
 	/**< The sample resolution. */
 
 	FLAC__FrameNumberType number_type;
@@ -443,19 +450,19 @@ typedef struct {
 	 */
 } FLAC__FrameHeader;
 
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */
 
 
-/** FLAC frame footer structure.  (c.f. <A HREF="../format.html#frame_footer">format specification</A>)
+/** FLAC frame footer structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#frame_footer">format specification</A>)
  */
 typedef struct {
 	FLAC__uint16 crc;
@@ -465,10 +472,10 @@ typedef struct {
 	 */
 } FLAC__FrameFooter;
 
-extern FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */
 
 
-/** FLAC frame structure.  (c.f. <A HREF="../format.html#frame">format specification</A>)
+/** FLAC frame structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#frame">format specification</A>)
  */
 typedef struct {
 	FLAC__FrameHeader header;
@@ -489,31 +496,31 @@ typedef struct {
 typedef enum {
 
 	FLAC__METADATA_TYPE_STREAMINFO = 0,
-	/**< <A HREF="../format.html#metadata_block_streaminfo">STREAMINFO</A> block */
+	/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_streaminfo">STREAMINFO</A> block */
 
 	FLAC__METADATA_TYPE_PADDING = 1,
-	/**< <A HREF="../format.html#metadata_block_padding">PADDING</A> block */
+	/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_padding">PADDING</A> block */
 
 	FLAC__METADATA_TYPE_APPLICATION = 2,
-	/**< <A HREF="../format.html#metadata_block_application">APPLICATION</A> block */
+	/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_application">APPLICATION</A> block */
 
 	FLAC__METADATA_TYPE_SEEKTABLE = 3,
-	/**< <A HREF="../format.html#metadata_block_seektable">SEEKTABLE</A> block */
+	/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_seektable">SEEKTABLE</A> block */
 
 	FLAC__METADATA_TYPE_VORBIS_COMMENT = 4,
-	/**< <A HREF="../format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
+	/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">VORBISCOMMENT</A> block (a.k.a. FLAC tags) */
 
 	FLAC__METADATA_TYPE_CUESHEET = 5,
-	/**< <A HREF="../format.html#metadata_block_cuesheet">CUESHEET</A> block */
+	/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_cuesheet">CUESHEET</A> block */
 
 	FLAC__METADATA_TYPE_PICTURE = 6,
-	/**< <A HREF="../format.html#metadata_block_picture">PICTURE</A> block */
+	/**< <A HREF="https://xiph.org/flac/format.html#metadata_block_picture">PICTURE</A> block */
 
 	FLAC__METADATA_TYPE_UNDEFINED = 7,
 	/**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */
 
-        FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
-        /**< No type will ever be greater than this. There is not enough room in the protocol block. */
+	FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE,
+	/**< No type will ever be greater than this. There is not enough room in the protocol block. */
 } FLAC__MetadataType;
 
 /** Maps a FLAC__MetadataType to a C string.
@@ -524,32 +531,32 @@ typedef enum {
 extern FLAC_API const char * const FLAC__MetadataTypeString[];
 
 
-/** FLAC STREAMINFO structure.  (c.f. <A HREF="../format.html#metadata_block_streaminfo">format specification</A>)
+/** FLAC STREAMINFO structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_streaminfo">format specification</A>)
  */
 typedef struct {
-	unsigned min_blocksize, max_blocksize;
-	unsigned min_framesize, max_framesize;
-	unsigned sample_rate;
-	unsigned channels;
-	unsigned bits_per_sample;
+	uint32_t min_blocksize, max_blocksize;
+	uint32_t min_framesize, max_framesize;
+	uint32_t sample_rate;
+	uint32_t channels;
+	uint32_t bits_per_sample;
 	FLAC__uint64 total_samples;
 	FLAC__byte md5sum[16];
 } FLAC__StreamMetadata_StreamInfo;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */
 
 /** The total stream length of the STREAMINFO block in bytes. */
 #define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u)
 
-/** FLAC PADDING structure.  (c.f. <A HREF="../format.html#metadata_block_padding">format specification</A>)
+/** FLAC PADDING structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_padding">format specification</A>)
  */
 typedef struct {
 	int dummy;
@@ -560,16 +567,16 @@ typedef struct {
 } FLAC__StreamMetadata_Padding;
 
 
-/** FLAC APPLICATION structure.  (c.f. <A HREF="../format.html#metadata_block_application">format specification</A>)
+/** FLAC APPLICATION structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_application">format specification</A>)
  */
 typedef struct {
 	FLAC__byte id[4];
 	FLAC__byte *data;
 } FLAC__StreamMetadata_Application;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */
 
-/** SeekPoint structure used in SEEKTABLE blocks.  (c.f. <A HREF="../format.html#seekpoint">format specification</A>)
+/** SeekPoint structure used in SEEKTABLE blocks.  (c.f. <A HREF="https://xiph.org/flac/format.html#seekpoint">format specification</A>)
  */
 typedef struct {
 	FLAC__uint64 sample_number;
@@ -579,13 +586,13 @@ typedef struct {
 	/**< The offset, in bytes, of the target frame with respect to
 	 * beginning of the first frame. */
 
-	unsigned frame_samples;
+	uint32_t frame_samples;
 	/**< The number of samples in the target frame. */
 } FLAC__StreamMetadata_SeekPoint;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */
 
 /** The total stream length of a seek point in bytes. */
 #define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u)
@@ -597,7 +604,7 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN
 extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
 
 
-/** FLAC SEEKTABLE structure.  (c.f. <A HREF="../format.html#metadata_block_seektable">format specification</A>)
+/** FLAC SEEKTABLE structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_seektable">format specification</A>)
  *
  * \note From the format specification:
  * - The seek points must be sorted by ascending sample number.
@@ -610,12 +617,12 @@ extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER;
  *   present in a stream.
  */
 typedef struct {
-	unsigned num_points;
+	uint32_t num_points;
 	FLAC__StreamMetadata_SeekPoint *points;
 } FLAC__StreamMetadata_SeekTable;
 
 
-/** Vorbis comment entry structure used in VORBIS_COMMENT blocks.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+/** Vorbis comment entry structure used in VORBIS_COMMENT blocks.  (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">format specification</A>)
  *
  *  For convenience, the APIs maintain a trailing NUL character at the end of
  *  \a entry which is not counted toward \a length, i.e.
@@ -626,10 +633,10 @@ typedef struct {
 	FLAC__byte *entry;
 } FLAC__StreamMetadata_VorbisComment_Entry;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */
 
 
-/** FLAC VORBIS_COMMENT structure.  (c.f. <A HREF="../format.html#metadata_block_vorbis_comment">format specification</A>)
+/** FLAC VORBIS_COMMENT structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block_vorbis_comment">format specification</A>)
  */
 typedef struct {
 	FLAC__StreamMetadata_VorbisComment_Entry vendor_string;
@@ -637,11 +644,11 @@ typedef struct {
 	FLAC__StreamMetadata_VorbisComment_Entry *comments;
 } FLAC__StreamMetadata_VorbisComment;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */
 
 
 /** FLAC CUESHEET track index structure.  (See the
- * <A HREF="../format.html#cuesheet_track_index">format specification</A> for
+ * <A HREF="https://xiph.org/flac/format.html#cuesheet_track_index">format specification</A> for
  * the full description of each field.)
  */
 typedef struct {
@@ -654,13 +661,13 @@ typedef struct {
 	/**< The index point number. */
 } FLAC__StreamMetadata_CueSheet_Index;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */
 
 
 /** FLAC CUESHEET track structure.  (See the
- * <A HREF="../format.html#cuesheet_track">format specification</A> for
+ * <A HREF="https://xiph.org/flac/format.html#cuesheet_track">format specification</A> for
  * the full description of each field.)
  */
 typedef struct {
@@ -673,10 +680,10 @@ typedef struct {
 	char isrc[13];
 	/**< Track ISRC.  This is a 12-digit alphanumeric code plus a trailing \c NUL byte */
 
-	unsigned type:1;
+	uint32_t type:1;
 	/**< The track type: 0 for audio, 1 for non-audio. */
 
-	unsigned pre_emphasis:1;
+	uint32_t pre_emphasis:1;
 	/**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */
 
 	FLAC__byte num_indices;
@@ -687,17 +694,17 @@ typedef struct {
 
 } FLAC__StreamMetadata_CueSheet_Track;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */
 
 
 /** FLAC CUESHEET structure.  (See the
- * <A HREF="../format.html#metadata_block_cuesheet">format specification</A>
+ * <A HREF="https://xiph.org/flac/format.html#metadata_block_cuesheet">format specification</A>
  * for the full description of each field.)
  */
 typedef struct {
@@ -713,7 +720,7 @@ typedef struct {
 	FLAC__bool is_cd;
 	/**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */
 
-	unsigned num_tracks;
+	uint32_t num_tracks;
 	/**< The number of tracks. */
 
 	FLAC__StreamMetadata_CueSheet_Track *tracks;
@@ -721,11 +728,11 @@ typedef struct {
 
 } FLAC__StreamMetadata_CueSheet;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */
 
 
 /** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */
@@ -763,7 +770,7 @@ typedef enum {
 extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[];
 
 /** FLAC PICTURE structure.  (See the
- * <A HREF="../format.html#metadata_block_picture">format specification</A>
+ * <A HREF="https://xiph.org/flac/format.html#metadata_block_picture">format specification</A>
  * for the full description of each field.)
  */
 typedef struct {
@@ -810,14 +817,14 @@ typedef struct {
 
 } FLAC__StreamMetadata_Picture;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */
 
 
 /** Structure that is used when a metadata block of unknown type is loaded.
@@ -829,9 +836,9 @@ typedef struct {
 } FLAC__StreamMetadata_Unknown;
 
 
-/** FLAC metadata block structure.  (c.f. <A HREF="../format.html#metadata_block">format specification</A>)
+/** FLAC metadata block structure.  (c.f. <A HREF="https://xiph.org/flac/format.html#metadata_block">format specification</A>)
  */
-typedef struct {
+typedef struct FLAC__StreamMetadata {
 	FLAC__MetadataType type;
 	/**< The type of the metadata block; used determine which member of the
 	 * \a data union to dereference.  If type >= FLAC__METADATA_TYPE_UNDEFINED
@@ -840,7 +847,7 @@ typedef struct {
 	FLAC__bool is_last;
 	/**< \c true if this metadata block is the last, else \a false */
 
-	unsigned length;
+	uint32_t length;
 	/**< Length, in bytes, of the block data as it appears in the stream. */
 
 	union {
@@ -857,9 +864,9 @@ typedef struct {
 	 * to use. */
 } FLAC__StreamMetadata;
 
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
-extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */
+extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */
 
 /** The total stream length of a metadata block header in bytes. */
 #define FLAC__STREAM_METADATA_HEADER_LENGTH (4u)
@@ -880,7 +887,7 @@ extern FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bit
  *    \c true if the given sample rate conforms to the specification, else
  *    \c false.
  */
-FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate);
 
 /** Tests that a blocksize at the given sample rate is valid for the FLAC
  *  subset.
@@ -892,7 +899,7 @@ FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate);
  *    \c true if the given blocksize conforms to the specification for the
  *    subset at the given sample rate, else \c false.
  */
-FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigned sample_rate);
+FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate);
 
 /** Tests that a sample rate is valid for the FLAC subset.  The subset rules
  *  for valid sample rates are slightly more complex since the rate has to
@@ -903,7 +910,7 @@ FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(unsigned blocksize, unsigne
  *    \c true if the given sample rate conforms to the specification for the
  *    subset, else \c false.
  */
-FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate);
+FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate);
 
 /** Check a Vorbis comment entry name to see if it conforms to the Vorbis
  *  comment specification.
@@ -926,14 +933,14 @@ FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *n
  *
  * \param value      A string to be checked.
  * \param length     A the length of \a value in bytes.  May be
- *                   \c (unsigned)(-1) to indicate that \a value is a plain
+ *                   \c (uint32_t)(-1) to indicate that \a value is a plain
  *                   UTF-8 NUL-terminated string.
  * \assert
  *    \code value != NULL \endcode
  * \retval FLAC__bool
  *    \c false if entry name is illegal, else \c true.
  */
-FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length);
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length);
 
 /** Check a Vorbis comment entry to see if it conforms to the Vorbis
  *  comment specification.
@@ -950,7 +957,7 @@ FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__
  * \retval FLAC__bool
  *    \c false if entry name is illegal, else \c true.
  */
-FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length);
+FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length);
 
 /** Check a seek table to see if it conforms to the FLAC specification.
  *  See the format specification for limits on the contents of the
@@ -973,10 +980,10 @@ FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_S
  * \param seek_table  A pointer to a seek table to be sorted.
  * \assert
  *    \code seek_table != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    The number of duplicate seek points converted into placeholders.
  */
-FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
+FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table);
 
 /** Check a cue sheet to see if it conforms to the FLAC specification.
  *  See the format specification for limits on the contents of the

+ 93 - 41
components/codecs/inc/FLAC/metadata.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2001-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -93,7 +93,7 @@
  *  Efficient means the whole file is rewritten at most one time, and only
  *  when necessary.  Level 1 is not efficient only in the case that you
  *  cause more than one metadata block to grow or shrink beyond what can
- *  be accomodated by padding.  In this case you should probably use level
+ *  be accommodated by padding.  In this case you should probably use level
  *  2, which allows you to edit all the metadata for a file in memory and
  *  write it out all at once.
  *
@@ -134,6 +134,11 @@ extern "C" {
  *  STREAMINFO, VORBIS_COMMENT, CUESHEET, and PICTURE blocks, requiring
  *  only a filename.
  *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
+ *
  *  They try to skip any ID3v2 tag at the head of the file.
  *
  * \{
@@ -217,13 +222,13 @@ FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__Stre
  *                    matched exactly.  Use \c NULL to mean "any
  *                    description".
  * \param max_width   The maximum width in pixels desired.  Use
- *                    \c (unsigned)(-1) to mean "any width".
+ *                    \c (uint32_t)(-1) to mean "any width".
  * \param max_height  The maximum height in pixels desired.  Use
- *                    \c (unsigned)(-1) to mean "any height".
+ *                    \c (uint32_t)(-1) to mean "any height".
  * \param max_depth   The maximum color depth in bits-per-pixel desired.
- *                    Use \c (unsigned)(-1) to mean "any depth".
+ *                    Use \c (uint32_t)(-1) to mean "any depth".
  * \param max_colors  The maximum number of colors desired.  Use
- *                    \c (unsigned)(-1) to mean "any number of colors".
+ *                    \c (uint32_t)(-1) to mean "any number of colors".
  * \assert
  *    \code filename != NULL \endcode
  *    \code picture != NULL \endcode
@@ -234,7 +239,7 @@ FLAC_API FLAC__bool FLAC__metadata_get_cuesheet(const char *filename, FLAC__Stre
  *    error, a file decoder error, or the file contained no PICTURE
  *    block, and \a *picture will be set to \c NULL.
  */
-FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, unsigned max_width, unsigned max_height, unsigned max_depth, unsigned max_colors);
+FLAC_API FLAC__bool FLAC__metadata_get_picture(const char *filename, FLAC__StreamMetadata **picture, FLAC__StreamMetadata_Picture_Type type, const char *mime_type, const FLAC__byte *description, uint32_t max_width, uint32_t max_height, uint32_t max_depth, uint32_t max_colors);
 
 /* \} */
 
@@ -387,6 +392,11 @@ FLAC_API FLAC__Metadata_SimpleIteratorStatus FLAC__metadata_simple_iterator_stat
 /** Initialize the iterator to point to the first metadata block in the
  *  given FLAC file.
  *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
+ *
  * \param iterator             A pointer to an existing iterator.
  * \param filename             The path to the FLAC file.
  * \param read_only            If \c true, the FLAC file will be opened
@@ -497,13 +507,13 @@ FLAC_API FLAC__MetadataType FLAC__metadata_simple_iterator_get_block_type(const
  *    \code iterator != NULL \endcode
  *    \a iterator has been successfully initialized with
  *    FLAC__metadata_simple_iterator_init()
- * \retval unsigned
+ * \retval uint32_t
  *    The length of the metadata block at the current iterator position.
  *    The is same length as that in the
- *    <a href="http://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>,
+ *    <a href="http://xiph.org/flhttps://xiph.org/flac/format.html#metadata_block_header">metadata block header</a>,
  *    i.e. the length of the metadata body that follows the header.
  */
-FLAC_API unsigned FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
+FLAC_API uint32_t FLAC__metadata_simple_iterator_get_block_length(const FLAC__Metadata_SimpleIterator *iterator);
 
 /** Get the application ID of the \c APPLICATION block at the current
  *  position.  This avoids reading the actual block data which can save
@@ -667,7 +677,7 @@ FLAC_API FLAC__bool FLAC__metadata_simple_iterator_delete_block(FLAC__Metadata_S
  *
  * - Create a new chain using FLAC__metadata_chain_new().  A chain is a
  *   linked list of FLAC metadata blocks.
- * - Read all metadata into the the chain from a FLAC file using
+ * - Read all metadata into the chain from a FLAC file using
  *   FLAC__metadata_chain_read() or FLAC__metadata_chain_read_ogg() and
  *   check the status.
  * - Optionally, consolidate the padding using
@@ -764,7 +774,7 @@ typedef enum {
 	FLAC__METADATA_CHAIN_STATUS_READ_WRITE_MISMATCH,
 	/**< FLAC__metadata_chain_write() was called on a chain read by
 	 *   FLAC__metadata_chain_read_with_callbacks()/FLAC__metadata_chain_read_ogg_with_callbacks(),
-	 *   or 
+	 *   or
 	 *   FLAC__metadata_chain_write_with_callbacks()/FLAC__metadata_chain_write_with_callbacks_and_tempfile()
 	 *   was called on a chain read by
 	 *   FLAC__metadata_chain_read()/FLAC__metadata_chain_read_ogg().
@@ -819,6 +829,11 @@ FLAC_API void FLAC__metadata_chain_delete(FLAC__Metadata_Chain *chain);
 FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_Chain *chain);
 
 /** Read all metadata from a FLAC file into the chain.
+ *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
  *
  * \param chain    A pointer to an existing chain.
  * \param filename The path to the FLAC file to read.
@@ -833,6 +848,11 @@ FLAC_API FLAC__Metadata_ChainStatus FLAC__metadata_chain_status(FLAC__Metadata_C
 FLAC_API FLAC__bool FLAC__metadata_chain_read(FLAC__Metadata_Chain *chain, const char *filename);
 
 /** Read all metadata from an Ogg FLAC file into the chain.
+ *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
  *
  * \note Ogg FLAC metadata data writing is not supported yet and
  * FLAC__metadata_chain_write() will fail.
@@ -1373,12 +1393,13 @@ FLAC_API FLAC__bool FLAC__metadata_object_is_equal(const FLAC__StreamMetadata *b
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, unsigned length, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetadata *object, FLAC__byte *data, uint32_t length, FLAC__bool copy);
 
 /** Resize the seekpoint array.
  *
  *  If the size shrinks, elements will truncated; if it grows, new placeholder
- *  points will be added to the end.
+ *  points will be added to the end. If this function returns false, the
+ *  object is left untouched.
  *
  * \param object          A pointer to an existing SEEKTABLE object.
  * \param new_num_points  The desired length of the array; may be \c 0.
@@ -1390,7 +1411,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_application_set_data(FLAC__StreamMetad
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, unsigned new_num_points);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMetadata *object, uint32_t new_num_points);
 
 /** Set a seekpoint in a seektable.
  *
@@ -1402,7 +1423,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_resize_points(FLAC__StreamMe
  *    \code object->type == FLAC__METADATA_TYPE_SEEKTABLE \endcode
  *    \code object->data.seek_table.num_points > point_num \endcode
  */
-FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
 
 /** Insert a seekpoint into a seektable.
  *
@@ -1416,7 +1437,7 @@ FLAC_API void FLAC__metadata_object_seektable_set_point(FLAC__StreamMetadata *ob
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, unsigned point_num, FLAC__StreamMetadata_SeekPoint point);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMetadata *object, uint32_t point_num, FLAC__StreamMetadata_SeekPoint point);
 
 /** Delete a seekpoint from a seektable.
  *
@@ -1429,7 +1450,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_insert_point(FLAC__StreamMet
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, unsigned point_num);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_delete_point(FLAC__StreamMetadata *object, uint32_t point_num);
 
 /** Check a seektable to see if it conforms to the FLAC specification.
  *  See the format specification for limits on the contents of the
@@ -1459,7 +1480,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_is_legal(const FLAC__StreamM
  * \retval FLAC__bool
  *    \c false if memory allocation fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, unsigned num);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_placeholders(FLAC__StreamMetadata *object, uint32_t num);
 
 /** Append a specific seek point template to the end of a seek table.
  *
@@ -1494,7 +1515,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_point(FLAC__
  * \retval FLAC__bool
  *    \c false if memory allocation fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], unsigned num);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC__StreamMetadata *object, FLAC__uint64 sample_numbers[], uint32_t num);
 
 /** Append a set of evenly-spaced seek point templates to the end of a
  *  seek table.
@@ -1516,7 +1537,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_points(FLAC_
  * \retval FLAC__bool
  *    \c false if memory allocation fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, unsigned num, FLAC__uint64 total_samples);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points(FLAC__StreamMetadata *object, uint32_t num, FLAC__uint64 total_samples);
 
 /** Append a set of evenly-spaced seek point templates to the end of a
  *  seek table.
@@ -1544,7 +1565,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_point
  * \retval FLAC__bool
  *    \c false if memory allocation fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, unsigned samples, FLAC__uint64 total_samples);
+FLAC_API FLAC__bool FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(FLAC__StreamMetadata *object, uint32_t samples, FLAC__uint64 total_samples);
 
 /** Sort a seek table's seek points according to the format specification,
  *  removing duplicates.
@@ -1591,7 +1612,8 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__
 /** Resize the comment array.
  *
  *  If the size shrinks, elements will truncated; if it grows, new empty
- *  fields will be added to the end.
+ *  fields will be added to the end.  If this function returns false, the
+ *  object is left untouched.
  *
  * \param object            A pointer to an existing VORBIS_COMMENT object.
  * \param new_num_comments  The desired length of the array; may be \c 0.
@@ -1603,7 +1625,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_vendor_string(FLAC__
  * \retval FLAC__bool
  *    \c false if memory allocation fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, unsigned new_num_comments);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__StreamMetadata *object, uint32_t new_num_comments);
 
 /** Sets a comment in a VORBIS_COMMENT block.
  *
@@ -1630,7 +1652,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_resize_comments(FLAC__St
  *    \c false if memory allocation fails or \a entry does not comply with the
  *    Vorbis comment specification, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
 
 /** Insert a comment in a VORBIS_COMMENT block at the given index.
  *
@@ -1660,7 +1682,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_set_comment(FLAC__Stream
  *    \c false if memory allocation fails or \a entry does not comply with the
  *    Vorbis comment specification, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, unsigned comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_insert_comment(FLAC__StreamMetadata *object, uint32_t comment_num, FLAC__StreamMetadata_VorbisComment_Entry entry, FLAC__bool copy);
 
 /** Appends a comment to a VORBIS_COMMENT block.
  *
@@ -1692,7 +1714,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_append_comment(FLAC__Str
  *  For convenience, a trailing NUL is added to the entry if it doesn't have
  *  one already.
  *
- *  Depending on the the value of \a all, either all or just the first comment
+ *  Depending on the value of \a all, either all or just the first comment
  *  whose field name(s) match the given entry's name will be replaced by the
  *  given entry.  If no comments match, \a entry will simply be appended.
  *
@@ -1733,7 +1755,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_replace_comment(FLAC__St
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, unsigned comment_num);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_delete_comment(FLAC__StreamMetadata *object, uint32_t comment_num);
 
 /** Creates a Vorbis comment entry from NUL-terminated name and value strings.
  *
@@ -1789,7 +1811,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair
  * \retval FLAC__bool
  *    \c true if the field names match, else \c false
  */
-FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, unsigned field_name_length);
+FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC__StreamMetadata_VorbisComment_Entry entry, const char *field_name, uint32_t field_name_length);
 
 /** Find a Vorbis comment with the given field name.
  *
@@ -1808,7 +1830,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_vorbiscomment_entry_matches(const FLAC
  *    The offset in the comment array of the first comment whose field
  *    name matches \a field_name, or \c -1 if no match was found.
  */
-FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, unsigned offset, const char *field_name);
+FLAC_API int FLAC__metadata_object_vorbiscomment_find_entry_from(const FLAC__StreamMetadata *object, uint32_t offset, const char *field_name);
 
 /** Remove first Vorbis comment matching the given field name.
  *
@@ -1871,7 +1893,8 @@ FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_C
 /** Resize a track's index point array.
  *
  *  If the size shrinks, elements will truncated; if it grows, new blank
- *  indices will be added to the end.
+ *  indices will be added to the end. If this function returns false, the
+ *  track object is left untouched.
  *
  * \param object           A pointer to an existing CUESHEET object.
  * \param track_num        The index of the track to modify.  NOTE: this is not
@@ -1886,7 +1909,7 @@ FLAC_API void FLAC__metadata_object_cuesheet_track_delete(FLAC__StreamMetadata_C
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, unsigned track_num, unsigned new_num_indices);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t new_num_indices);
 
 /** Insert an index point in a CUESHEET track at the given index.
  *
@@ -1909,7 +1932,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_resize_indices(FLAC__St
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num, FLAC__StreamMetadata_CueSheet_Index index);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num, FLAC__StreamMetadata_CueSheet_Index index);
 
 /** Insert a blank index point in a CUESHEET track at the given index.
  *
@@ -1933,7 +1956,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_index(FLAC__Stre
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
 
 /** Delete an index point in a CUESHEET track at the given index.
  *
@@ -1952,12 +1975,13 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_insert_blank_index(FLAC
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, unsigned track_num, unsigned index_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__StreamMetadata *object, uint32_t track_num, uint32_t index_num);
 
 /** Resize the track array.
  *
  *  If the size shrinks, elements will truncated; if it grows, new blank
- *  tracks will be added to the end.
+ *  tracks will be added to the end.  If this function returns false, the
+ *  object is left untouched.
  *
  * \param object            A pointer to an existing CUESHEET object.
  * \param new_num_tracks    The desired length of the array; may be \c 0.
@@ -1969,7 +1993,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_track_delete_index(FLAC__Stre
  * \retval FLAC__bool
  *    \c false if memory allocation error, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, unsigned new_num_tracks);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMetadata *object, uint32_t new_num_tracks);
 
 /** Sets a track in a CUESHEET block.
  *
@@ -1991,7 +2015,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_resize_tracks(FLAC__StreamMet
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
 
 /** Insert a track in a CUESHEET block at the given index.
  *
@@ -2014,7 +2038,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_set_track(FLAC__StreamMetadat
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, unsigned track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMetadata *object, uint32_t track_num, FLAC__StreamMetadata_CueSheet_Track *track, FLAC__bool copy);
 
 /** Insert a blank track in a CUESHEET block at the given index.
  *
@@ -2033,7 +2057,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_track(FLAC__StreamMeta
  * \retval FLAC__bool
  *    \c false if \a copy is \c true and malloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, unsigned track_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__StreamMetadata *object, uint32_t track_num);
 
 /** Delete a track in a CUESHEET block at the given index.
  *
@@ -2048,7 +2072,7 @@ FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_insert_blank_track(FLAC__Stre
  * \retval FLAC__bool
  *    \c false if realloc() fails, else \c true.
  */
-FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, unsigned track_num);
+FLAC_API FLAC__bool FLAC__metadata_object_cuesheet_delete_track(FLAC__StreamMetadata *object, uint32_t track_num);
 
 /** Check a cue sheet to see if it conforms to the FLAC specification.
  *  See the format specification for limits on the contents of the
@@ -2173,6 +2197,34 @@ FLAC_API FLAC__bool FLAC__metadata_object_picture_set_data(FLAC__StreamMetadata
  */
 FLAC_API FLAC__bool FLAC__metadata_object_picture_is_legal(const FLAC__StreamMetadata *object, const char **violation);
 
+
+/** Get the raw (binary) representation of a FLAC__StreamMetadata objeect.
+ *  After use, free() the returned buffer. The length of the buffer is
+ *  the length of the input metadata object plus 4 bytes for the header.
+ *
+ * \param object     A pointer to metadata block to be converted.
+ * \assert
+ *    \code object != NULL \endcode
+ * \retval FLAC__byte*
+ *    \c  NULL if there was an error, else a pointer to a buffer holding
+ *        the requested data.
+ */
+FLAC_API FLAC__byte * FLAC__metadata_object_get_raw(const FLAC__StreamMetadata *object);
+
+
+/** Turn a raw (binary) representation into a FLAC__StreamMetadata objeect.
+ *  The returned object must be deleted with FLAC__metadata_object_delete()
+ *  after use.
+ *
+ * \param buffer     A pointer to a buffer containing a binary representation
+ *                   to be converted to a FLAC__StreamMetadata object
+ * \param length     The length of the supplied buffer
+ * \retval FLAC__StreamMetadata*
+ *    \c  NULL if there was an error, else a pointer to a FLAC__StreamMetadata
+ *        holding the requested data.
+ */
+
+FLAC_API FLAC__StreamMetadata * FLAC__metadata_object_set_raw(FLAC__byte *buffer, FLAC__uint32 length);
 /* \} */
 
 #ifdef __cplusplus

+ 3 - 34
components/codecs/inc/FLAC/ordinals.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,27 +33,10 @@
 #ifndef FLAC__ORDINALS_H
 #define FLAC__ORDINALS_H
 
-#if defined(_MSC_VER) && _MSC_VER < 1600
-
-/* Microsoft Visual Studio earlier than the 2010 version did not provide
- * the 1999 ISO C Standard header file <stdint.h>.
- */
-
-typedef __int8 FLAC__int8;
-typedef unsigned __int8 FLAC__uint8;
-
-typedef __int16 FLAC__int16;
-typedef __int32 FLAC__int32;
-typedef __int64 FLAC__int64;
-typedef unsigned __int16 FLAC__uint16;
-typedef unsigned __int32 FLAC__uint32;
-typedef unsigned __int64 FLAC__uint64;
-
-#else
-
-/* For MSVC 2010 and everything else which provides <stdint.h>. */
+/* This of course assumes C99 headers */
 
 #include <stdint.h>
+#include <stdbool.h>
 
 typedef int8_t FLAC__int8;
 typedef uint8_t FLAC__uint8;
@@ -65,22 +48,8 @@ typedef uint16_t FLAC__uint16;
 typedef uint32_t FLAC__uint32;
 typedef uint64_t FLAC__uint64;
 
-#endif
-
 typedef int FLAC__bool;
 
 typedef FLAC__uint8 FLAC__byte;
 
-
-#ifdef true
-#undef true
-#endif
-#ifdef false
-#undef false
-#endif
-#ifndef __cplusplus
-#define true 1
-#define false 0
-#endif
-
 #endif

+ 47 - 23
components/codecs/inc/FLAC/stream_decoder.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -228,7 +228,7 @@ typedef enum {
 	 */
 
 	FLAC__STREAM_DECODER_ABORTED,
-	/**< The decoder was aborted by the read callback. */
+	/**< The decoder was aborted by the read or write callback. */
 
 	FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR,
 	/**< An error occurred allocating memory.  The decoder is in an invalid
@@ -422,7 +422,11 @@ extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[];
  *  could be because the decoder encountered a valid frame made by a future
  *  version of the encoder which it cannot parse, or because of a false
  *  sync making it appear as though an encountered frame was generated by
- *  a future encoder.
+ *  a future encoder. \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA is
+ *  caused by finding data that doesn't fit a metadata block (too large
+ *  or too small) or finding inconsistencies in the metadata, for example
+ *  a PICTURE block with an image that exceeds the size of the metadata
+ *  block.
  */
 typedef enum {
 
@@ -435,9 +439,12 @@ typedef enum {
 	FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH,
 	/**< The frame's data did not match the CRC in the footer. */
 
-	FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM
+	FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM,
 	/**< The decoder encountered reserved fields in use in the stream. */
 
+	FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA
+	/**< The decoder encountered a corrupted metadata block. */
+
 } FLAC__StreamDecoderErrorStatus;
 
 /** Maps a FLAC__StreamDecoderErrorStatus to a C string.
@@ -674,7 +681,7 @@ typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *
  *                  samples of length \a frame->header.blocksize.
  *                  Channels will be ordered according to the FLAC
  *                  specification; see the documentation for the
- *                  <A HREF="../format.html#frame_header">frame header</A>.
+ *                  <A HREF="https://xiph.org/flac/format.html#frame_header">frame header</A>.
  * \param  client_data  The callee's client data set through
  *                      FLAC__stream_decoder_init_*().
  * \retval FLAC__StreamDecoderWriteStatus
@@ -920,7 +927,7 @@ FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDeco
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
 FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder);
@@ -932,10 +939,10 @@ FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamD
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder);
 
 /** Get the current channel assignment in the stream being decoded.
  *  Will only be valid after decoding has started and will contain the
@@ -956,10 +963,10 @@ FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(con
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder);
 
 /** Get the current sample rate in Hz of the stream being decoded.
  *  Will only be valid after decoding has started and will contain the
@@ -968,10 +975,10 @@ FLAC_API unsigned FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDec
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder);
 
 /** Get the current blocksize of the stream being decoded.
  *  Will only be valid after decoding has started and will contain the
@@ -980,10 +987,10 @@ FLAC_API unsigned FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder
  * \param  decoder  A decoder instance to query.
  * \assert
  *    \code decoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See above.
  */
-FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
+FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder);
 
 /** Returns the decoder's current read position within the stream.
  *  The position is the byte offset from the start of the stream.
@@ -1006,6 +1013,16 @@ FLAC_API unsigned FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *
  */
 FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position);
 
+/** Return client_data from decoder.
+ *  The data pointed to by the pointer should not be modified.
+ *
+ * \param  decoder  A decoder instance.
+ * \retval const void *
+ *    The callee's client data set through FLAC__stream_decoder_init_*().
+ *    Do not modify the contents.
+ */
+FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder);
+
 /** Initialize the decoder instance to decode native FLAC streams.
  *
  *  This flavor of initialization sets up the decoder to decode from a
@@ -1184,7 +1201,7 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream(
  *                            Unless \a file is \c stdin, it will be closed
  *                            when FLAC__stream_decoder_finish() is called.
  *                            Note however that seeking will not work when
- *                            decoding from \c stdout since it is not seekable.
+ *                            decoding from \c stdin since it is not seekable.
  * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
  *                            pointer must not be \c NULL.
  * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
@@ -1234,7 +1251,7 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE(
  *                            Unless \a file is \c stdin, it will be closed
  *                            when FLAC__stream_decoder_finish() is called.
  *                            Note however that seeking will not work when
- *                            decoding from \c stdout since it is not seekable.
+ *                            decoding from \c stdin since it is not seekable.
  * \param  write_callback     See FLAC__StreamDecoderWriteCallback.  This
  *                            pointer must not be \c NULL.
  * \param  metadata_callback  See FLAC__StreamDecoderMetadataCallback.  This
@@ -1263,11 +1280,15 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE(
 /** Initialize the decoder instance to decode native FLAC files.
  *
  *  This flavor of initialization sets up the decoder to decode from a plain
- *  native FLAC file.  If POSIX fopen() semantics are not sufficient, (for
- *  example, with Unicode filenames on Windows), you must use
- *  FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
+ *  native FLAC file.  If POSIX fopen() semantics are not sufficient, you must
+ *  use FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream()
  *  and provide callbacks for the I/O.
  *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
+ *
  *  This function should be called after FLAC__stream_decoder_new() and
  *  FLAC__stream_decoder_set_*() but before any of the
  *  FLAC__stream_decoder_process_*() functions.  Will set and return the
@@ -1305,11 +1326,15 @@ FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file(
 /** Initialize the decoder instance to decode Ogg FLAC files.
  *
  *  This flavor of initialization sets up the decoder to decode from a plain
- *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient, (for
- *  example, with Unicode filenames on Windows), you must use
+ *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient, you must use
  *  FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream()
  *  and provide callbacks for the I/O.
  *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
+ *
  *  This function should be called after FLAC__stream_decoder_new() and
  *  FLAC__stream_decoder_set_*() but before any of the
  *  FLAC__stream_decoder_process_*() functions.  Will set and return the
@@ -1403,8 +1428,7 @@ FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder);
  *  and is not seekable (i.e. no seek callback was provided or the seek
  *  callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it
  *  is the duty of the client to start feeding data from the beginning of
- *  the stream on the next FLAC__stream_decoder_process() or
- *  FLAC__stream_decoder_process_interleaved() call.
+ *  the stream on the next FLAC__stream_decoder_process_*() call.
  *
  * \param  decoder  A decoder instance.
  * \assert

+ 112 - 65
components/codecs/inc/FLAC/stream_encoder.h

@@ -1,6 +1,6 @@
 /* libFLAC - Free Lossless Audio Codec library
  * Copyright (C) 2000-2009  Josh Coalson
- * Copyright (C) 2011-2014  Xiph.Org Foundation
+ * Copyright (C) 2011-2022  Xiph.Org Foundation
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -129,8 +129,8 @@ extern "C" {
  * Unlike the decoders, the stream encoder has many options that can
  * affect the speed and compression ratio.  When setting these parameters
  * you should have some basic knowledge of the format (see the
- * <A HREF="../documentation_format_overview.html">user-level documentation</A>
- * or the <A HREF="../format.html">formal description</A>).  The
+ * <A HREF="https://xiph.org/flac/documentation_format_overview.html">user-level documentation</A>
+ * or the <A HREF="https://xiph.org/flac/format.html">formal description</A>).  The
  * FLAC__stream_encoder_set_*() functions themselves do not validate the
  * values as many are interdependent.  The FLAC__stream_encoder_init_*()
  * functions will do this, so make sure to pay attention to the state
@@ -311,8 +311,7 @@ typedef enum {
 
 	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_BITS_PER_SAMPLE,
 	/**< The encoder has an invalid setting for bits-per-sample.
-	 * FLAC supports 4-32 bps but the reference encoder currently supports
-	 * only up to 24 bps.
+	 * FLAC supports 4-32 bps.
 	 */
 
 	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_SAMPLE_RATE,
@@ -331,7 +330,7 @@ typedef enum {
 	/**< The specified block size is less than the maximum LPC order. */
 
 	FLAC__STREAM_ENCODER_INIT_STATUS_NOT_STREAMABLE,
-	/**< The encoder is bound to the <A HREF="../format.html#subset">Subset</A> but other settings violate it. */
+	/**< The encoder is bound to the <A HREF="https://xiph.org/flac/format.html#subset">Subset</A> but other settings violate it. */
 
 	FLAC__STREAM_ENCODER_INIT_STATUS_INVALID_METADATA,
 	/**< The metadata input to the encoder is invalid, in one of the following ways:
@@ -554,7 +553,7 @@ typedef FLAC__StreamEncoderReadStatus (*FLAC__StreamEncoderReadCallback)(const F
  * \retval FLAC__StreamEncoderWriteStatus
  *    The callee's return status.
  */
-typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, unsigned samples, unsigned current_frame, void *client_data);
+typedef FLAC__StreamEncoderWriteStatus (*FLAC__StreamEncoderWriteCallback)(const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[], size_t bytes, uint32_t samples, uint32_t current_frame, void *client_data);
 
 /** Signature for the seek callback.
  *
@@ -675,7 +674,7 @@ typedef void (*FLAC__StreamEncoderMetadataCallback)(const FLAC__StreamEncoder *e
  * \param  client_data      The callee's client data set through
  *                          FLAC__stream_encoder_init_*().
  */
-typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
+typedef void (*FLAC__StreamEncoderProgressCallback)(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, uint32_t frames_written, uint32_t total_frames_estimate, void *client_data);
 
 
 /***********************************************************************
@@ -743,7 +742,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_ogg_serial_number(FLAC__StreamEncod
  */
 FLAC_API FLAC__bool FLAC__stream_encoder_set_verify(FLAC__StreamEncoder *encoder, FLAC__bool value);
 
-/** Set the <A HREF="../format.html#subset">Subset</A> flag.  If \c true,
+/** Set the <A HREF="https://xiph.org/flac/format.html#subset">Subset</A> flag.  If \c true,
  *  the encoder will comply with the Subset and will check the
  *  settings during FLAC__stream_encoder_init_*() to see if all settings
  *  comply.  If \c false, the settings may take advantage of the full
@@ -771,7 +770,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_streamable_subset(FLAC__StreamEncod
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the sample resolution of the input to be encoded.
  *
@@ -787,7 +786,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_channels(FLAC__StreamEncoder *encod
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the sample rate (in Hz) of the input to be encoded.
  *
@@ -799,7 +798,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_bits_per_sample(FLAC__StreamEncoder
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the compression level
  *
@@ -843,15 +842,15 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en
  *  <td>max residual partition order</td>
  *  <td>rice parameter search dist</td>
  * </tr>
- * <tr>  <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
- * <tr>  <td><b>1</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
- * <tr>  <td><b>2</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)<td>                                     <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
- * <tr>  <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)<td>                                     <td>6</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
- * <tr>  <td><b>4</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)<td>                                     <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
- * <tr>  <td><b>5</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)<td>                                     <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr>
- * <tr>  <td><b>6</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2)<td>                    <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
- * <tr>  <td><b>7</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2)<td>                    <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
- * <tr>  <td><b>8</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5);partial_tukey(2);punchout_tukey(3)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * <tr>  <td><b>0</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)</td>         <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>1</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)</td>         <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>2</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)</td>         <td>0</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>3</td> <td>0</td> </tr>
+ * <tr>  <td><b>3</b></td> <td>false</td> <td>false</td> <td>tukey(0.5)</td>         <td>6</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
+ * <tr>  <td><b>4</b></td> <td>true</td>  <td>true</td>  <td>tukey(0.5)</td>         <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>4</td> <td>0</td> </tr>
+ * <tr>  <td><b>5</b></td> <td>true</td>  <td>false</td> <td>tukey(0.5)</td>         <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>5</td> <td>0</td> </tr>
+ * <tr>  <td><b>6</b></td> <td>true</td>  <td>false</td> <td>subdivide_tukey(2)</td> <td>8</td>  <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * <tr>  <td><b>7</b></td> <td>true</td>  <td>false</td> <td>subdivide_tukey(2)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
+ * <tr>  <td><b>8</b></td> <td>true</td>  <td>false</td> <td>subdivide_tukey(2)</td> <td>12</td> <td>0</td> <td>false</td> <td>false</td> <td>false</td> <td>0</td> <td>6</td> <td>0</td> </tr>
  * </table>
  *
  * \default \c 5
@@ -862,7 +861,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_sample_rate(FLAC__StreamEncoder *en
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the blocksize to use while encoding.
  *
@@ -877,13 +876,13 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_compression_level(FLAC__StreamEncod
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_blocksize(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set to \c true to enable mid-side encoding on stereo input.  The
  *  number of channels must be 2 for this to have any effect.  Set to
  *  \c false to use only independent channel coding.
  *
- * \default \c false
+ * \default \c true
  * \param  encoder  An encoder instance to set.
  * \param  value    Flag value (see above).
  * \assert
@@ -921,7 +920,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
  * \c blackman, \c blackman_harris_4term_92db, \c connes, \c flattop,
  * \c gauss(STDDEV), \c hamming, \c hann, \c kaiser_bessel, \c nuttall,
  * \c rectangle, \c triangle, \c tukey(P), \c partial_tukey(n[/ov[/P]]),
- * \c punchout_tukey(n[/ov[/P]]), \c welch.
+ * \c punchout_tukey(n[/ov[/P]]), \c subdivide_tukey(n[/P]), \c welch.
  *
  * For \c gauss(STDDEV), STDDEV specifies the standard deviation
  * (0<STDDEV<=0.5).
@@ -948,6 +947,20 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
  * and partial_tukey(3/0.3/0.5) are all valid. ov should be smaller than 1
  * and can be negative.
  *
+ * subdivide_tukey(n) is a more efficient reimplementation of
+ * partial_tukey and punchout_tukey taken together, recycling as much data
+ * as possible. It combines all possible non-redundant partial_tukey(n)
+ * and punchout_tukey(n) up to the n specified. Specifying
+ * subdivide_tukey(3) is equivalent to specifying tukey, partial_tukey(2),
+ * partial_tukey(3) and punchout_tukey(3), specifying subdivide_tukey(5)
+ * equivalently adds partial_tukey(4), punchout_tukey(4), partial_tukey(5)
+ * and punchout_tukey(5). To be able to reuse data as much as possible,
+ * the tukey taper is taken equal for all windows, and the P specified is
+ * applied for the smallest used window. In other words,
+ * subdivide_tukey(2/0.5) results in a taper equal to that of tukey(0.25)
+ * and subdivide_tukey(5) in a taper equal to that of tukey(0.1). The
+ * default P for subdivide_tukey when none is specified is 0.5.
+ *
  * Example specifications are \c "blackman" or
  * \c "hann;triangle;tukey(0.5);tukey(0.25);tukey(0.125)"
  *
@@ -963,6 +976,8 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_loose_mid_side_stereo(FLAC__StreamE
  * floating point array in which to store the window. Also note that the
  * values of P, STDDEV and ov are locale-specific, so if the comma
  * separator specified by the locale is a comma, a comma should be used.
+ * A locale-independent way is to specify using scientific notation,
+ * e.g. 5e-1 instad of 0.5 or 0,5.
  *
  * \default \c "tukey(0.5)"
  * \param  encoder        An encoder instance to set.
@@ -977,7 +992,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *en
 
 /** Set the maximum LPC order, or \c 0 to use only the fixed predictors.
  *
- * \default \c 0
+ * \default \c 8
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
  * \assert
@@ -985,16 +1000,12 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *en
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the precision, in bits, of the quantized linear predictor
  *  coefficients, or \c 0 to let the encoder select it based on the
  *  blocksize.
  *
- * \note
- * In the current implementation, qlp_coeff_precision + bits_per_sample must
- * be less than 32.
- *
  * \default \c 0
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
@@ -1003,7 +1014,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_max_lpc_order(FLAC__StreamEncoder *
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_qlp_coeff_precision(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set to \c false to use only the specified quantized linear predictor
  *  coefficient precision, or \c true to search neighboring precision
@@ -1066,7 +1077,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_do_exhaustive_model_search(FLAC__St
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set the maximum partition order to search when coding the residual.
  *  This is used in tandem with
@@ -1081,7 +1092,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__
  *  all orders, using the mean of each context for its Rice parameter,
  *  and use the best.
  *
- * \default \c 0
+ * \default \c 5
  * \param  encoder  An encoder instance to set.
  * \param  value    See above.
  * \assert
@@ -1089,7 +1100,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_min_residual_partition_order(FLAC__
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Deprecated.  Setting this value has no effect.
  *
@@ -1101,7 +1112,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_max_residual_partition_order(FLAC__
  * \retval FLAC__bool
  *    \c false if the encoder is already initialized, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, unsigned value);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_rice_parameter_search_dist(FLAC__StreamEncoder *encoder, uint32_t value);
 
 /** Set an estimate of the total samples that will be encoded.
  *  This is merely an estimate and may be set to \c 0 if unknown.
@@ -1200,7 +1211,25 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_total_samples_estimate(FLAC__Stream
  *    \c false if the encoder is already initialized, or if
  *    \a num_blocks > 65535 if encoding to Ogg FLAC, else \c true.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, unsigned num_blocks);
+FLAC_API FLAC__bool FLAC__stream_encoder_set_metadata(FLAC__StreamEncoder *encoder, FLAC__StreamMetadata **metadata, uint32_t num_blocks);
+
+/** Set to \c true to make the encoder not output frames which contain
+ *  only constant subframes. This is beneficial for streaming
+ *  applications: very small frames can cause problems with buffering
+ *  as bitrates can drop as low 1kbit/s for CDDA audio encoded within
+ *  subset. The minimum bitrate for a FLAC file encoded with this
+ *  function used is raised to 1bit/sample (i.e. 48kbit/s for 48kHz
+ *  material).
+ *
+ * \default \c false
+ * \param  encoder  An encoder instance to set.
+ * \param  value    Flag value (see above).
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    \c false if the encoder is already initialized, else \c true.
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_set_limit_min_bitrate(FLAC__StreamEncoder *encoder, FLAC__bool value);
 
 /** Get the current encoder state.
  *
@@ -1254,7 +1283,7 @@ FLAC_API const char *FLAC__stream_encoder_get_resolved_state_string(const FLAC__
  * \assert
  *    \code encoder != NULL \endcode
  */
-FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, unsigned *frame_number, unsigned *channel, unsigned *sample, FLAC__int32 *expected, FLAC__int32 *got);
+FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__StreamEncoder *encoder, FLAC__uint64 *absolute_sample, uint32_t *frame_number, uint32_t *channel, uint32_t *sample, FLAC__int32 *expected, FLAC__int32 *got);
 
 /** Get the "verify" flag.
  *
@@ -1266,7 +1295,7 @@ FLAC_API void FLAC__stream_encoder_get_verify_decoder_error_stats(const FLAC__St
  */
 FLAC_API FLAC__bool FLAC__stream_encoder_get_verify(const FLAC__StreamEncoder *encoder);
 
-/** Get the <A HREF="../format.html#subset>Subset</A> flag.
+/** Get the <A HREF="https://xiph.org/flac/format.html#subset">Subset</A> flag.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
@@ -1281,40 +1310,40 @@ FLAC_API FLAC__bool FLAC__stream_encoder_get_streamable_subset(const FLAC__Strea
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_channels().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_channels(const FLAC__StreamEncoder *encoder);
 
 /** Get the input sample resolution setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_bits_per_sample().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_bits_per_sample(const FLAC__StreamEncoder *encoder);
 
 /** Get the input sample rate setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_sample_rate().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_sample_rate(const FLAC__StreamEncoder *encoder);
 
 /** Get the blocksize setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_blocksize().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_blocksize(const FLAC__StreamEncoder *encoder);
 
 /** Get the "mid/side stereo coding" flag.
  *
@@ -1341,20 +1370,20 @@ FLAC_API FLAC__bool FLAC__stream_encoder_get_loose_mid_side_stereo(const FLAC__S
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_max_lpc_order().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_max_lpc_order(const FLAC__StreamEncoder *encoder);
 
 /** Get the quantized linear predictor coefficient precision setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_qlp_coeff_precision().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_qlp_coeff_precision(const FLAC__StreamEncoder *encoder);
 
 /** Get the qlp coefficient precision search flag.
  *
@@ -1391,30 +1420,30 @@ FLAC_API FLAC__bool FLAC__stream_encoder_get_do_exhaustive_model_search(const FL
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_min_residual_partition_order().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_min_residual_partition_order(const FLAC__StreamEncoder *encoder);
 
 /** Get maximum residual partition order setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_max_residual_partition_order().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_max_residual_partition_order(const FLAC__StreamEncoder *encoder);
 
 /** Get the Rice parameter search distance setting.
  *
  * \param  encoder  An encoder instance to query.
  * \assert
  *    \code encoder != NULL \endcode
- * \retval unsigned
+ * \retval uint32_t
  *    See FLAC__stream_encoder_set_rice_parameter_search_dist().
  */
-FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
+FLAC_API uint32_t FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC__StreamEncoder *encoder);
 
 /** Get the previously set estimate of the total samples to be encoded.
  *  The encoder merely mimics back the value given to
@@ -1429,6 +1458,16 @@ FLAC_API unsigned FLAC__stream_encoder_get_rice_parameter_search_dist(const FLAC
  */
 FLAC_API FLAC__uint64 FLAC__stream_encoder_get_total_samples_estimate(const FLAC__StreamEncoder *encoder);
 
+/** Get the "limit_min_bitrate" flag.
+ *
+ * \param  encoder  An encoder instance to query.
+ * \assert
+ *    \code encoder != NULL \endcode
+ * \retval FLAC__bool
+ *    See FLAC__stream_encoder_set_limit_min_bitrate().
+ */
+FLAC_API FLAC__bool FLAC__stream_encoder_get_limit_min_bitrate(const FLAC__StreamEncoder *encoder);
+
 /** Initialize the encoder instance to encode native FLAC streams.
  *
  *  This flavor of initialization sets up the encoder to encode to a
@@ -1633,11 +1672,15 @@ FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_ogg_FILE(FLAC__
 /** Initialize the encoder instance to encode native FLAC files.
  *
  *  This flavor of initialization sets up the encoder to encode to a plain
- *  FLAC file.  If POSIX fopen() semantics are not sufficient (for example,
- *  with Unicode filenames on Windows), you must use
+ *  FLAC file.  If POSIX fopen() semantics are not sufficient you must use
  *  FLAC__stream_encoder_init_FILE(), or FLAC__stream_encoder_init_stream()
  *  and provide callbacks for the I/O.
  *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
+ *
  *  This function should be called after FLAC__stream_encoder_new() and
  *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
  *  or FLAC__stream_encoder_process_interleaved().
@@ -1665,11 +1708,15 @@ FLAC_API FLAC__StreamEncoderInitStatus FLAC__stream_encoder_init_file(FLAC__Stre
 /** Initialize the encoder instance to encode Ogg FLAC files.
  *
  *  This flavor of initialization sets up the encoder to encode to a plain
- *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient (for example,
- *  with Unicode filenames on Windows), you must use
+ *  Ogg FLAC file.  If POSIX fopen() semantics are not sufficient, you must use
  *  FLAC__stream_encoder_init_ogg_FILE(), or FLAC__stream_encoder_init_ogg_stream()
  *  and provide callbacks for the I/O.
  *
+ *  On Windows, filename must be a UTF-8 encoded filename, which libFLAC
+ *  internally translates to an appropriate representation to use with
+ *  _wfopen. On all other systems, filename is passed to fopen without
+ *  any translation.
+ *
  *  This function should be called after FLAC__stream_encoder_new() and
  *  FLAC__stream_encoder_set_*() but before FLAC__stream_encoder_process()
  *  or FLAC__stream_encoder_process_interleaved().
@@ -1734,7 +1781,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
  *
  *  For applications where channel order is important, channels must
  *  follow the order as described in the
- *  <A HREF="../format.html#frame_header">frame header</A>.
+ *  <A HREF="https://xiph.org/flac/format.html#frame_header">frame header</A>.
  *
  * \param  encoder  An initialized encoder instance in the OK state.
  * \param  buffer   An array of pointers to each channel's signal.
@@ -1747,7 +1794,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_finish(FLAC__StreamEncoder *encoder);
  *    encoder state with FLAC__stream_encoder_get_state() to see what
  *    went wrong.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], unsigned samples);
+FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, const FLAC__int32 * const buffer[], uint32_t samples);
 
 /** Submit data for encoding.
  *  This version allows you to supply the input data where the channels
@@ -1763,7 +1810,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, c
  *
  *  For applications where channel order is important, channels must
  *  follow the order as described in the
- *  <A HREF="../format.html#frame_header">frame header</A>.
+ *  <A HREF="https://xiph.org/flac/format.html#frame_header">frame header</A>.
  *
  * \param  encoder  An initialized encoder instance in the OK state.
  * \param  buffer   An array of channel-interleaved data (see above).
@@ -1779,7 +1826,7 @@ FLAC_API FLAC__bool FLAC__stream_encoder_process(FLAC__StreamEncoder *encoder, c
  *    encoder state with FLAC__stream_encoder_get_state() to see what
  *    went wrong.
  */
-FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], unsigned samples);
+FLAC_API FLAC__bool FLAC__stream_encoder_process_interleaved(FLAC__StreamEncoder *encoder, const FLAC__int32 buffer[], uint32_t samples);
 
 /* \} */
 

+ 2 - 1
components/codecs/inc/ogg/config_types.h

@@ -1,7 +1,7 @@
 #ifndef __CONFIG_TYPES_H__
 #define __CONFIG_TYPES_H__
 
-/* these are filled in by configure */
+/* these are filled in by configure or cmake*/
 #define INCLUDE_INTTYPES_H 1
 #define INCLUDE_STDINT_H 1
 #define INCLUDE_SYS_TYPES_H 1
@@ -21,5 +21,6 @@ typedef uint16_t ogg_uint16_t;
 typedef int32_t ogg_int32_t;
 typedef uint32_t ogg_uint32_t;
 typedef int64_t ogg_int64_t;
+typedef uint64_t ogg_uint64_t;
 
 #endif

+ 0 - 1
components/codecs/inc/ogg/ogg.h

@@ -11,7 +11,6 @@
  ********************************************************************
 
  function: toplevel libogg include
- last mod: $Id$
 
  ********************************************************************/
 #ifndef _OGG_H

+ 15 - 5
components/codecs/inc/ogg/os_types.h

@@ -10,8 +10,7 @@
  *                                                                  *
  ********************************************************************
 
- function: #ifdef jail to whip a few platforms into the UNIX ideal.
- last mod: $Id$
+ function: Define a consistent set of types on each platform.
 
  ********************************************************************/
 #ifndef _OS_TYPES_H
@@ -44,6 +43,7 @@
      typedef unsigned long long ogg_uint64_t;
 #  elif defined(__MWERKS__)
      typedef long long ogg_int64_t;
+     typedef unsigned long long ogg_uint64_t;
      typedef int ogg_int32_t;
      typedef unsigned int ogg_uint32_t;
      typedef short ogg_int16_t;
@@ -62,6 +62,7 @@
        typedef __int64 ogg_int64_t;
        typedef __int32 ogg_int32_t;
        typedef unsigned __int32 ogg_uint32_t;
+       typedef unsigned __int64 ogg_uint64_t;
        typedef __int16 ogg_int16_t;
        typedef unsigned __int16 ogg_uint16_t;
 #    endif
@@ -69,12 +70,13 @@
 
 #elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
 
-#  include <inttypes.h>
+#  include <sys/types.h>
    typedef int16_t ogg_int16_t;
-   typedef uint16_t ogg_uint16_t;
+   typedef u_int16_t ogg_uint16_t;
    typedef int32_t ogg_int32_t;
-   typedef uint32_t ogg_uint32_t;
+   typedef u_int32_t ogg_uint32_t;
    typedef int64_t ogg_int64_t;
+   typedef u_int64_t ogg_uint64_t;
 
 #elif defined(__HAIKU__)
 
@@ -85,6 +87,7 @@
    typedef int ogg_int32_t;
    typedef unsigned int ogg_uint32_t;
    typedef long long ogg_int64_t;
+   typedef unsigned long long ogg_uint64_t;
 
 #elif defined(__BEOS__)
 
@@ -95,6 +98,7 @@
    typedef int32_t ogg_int32_t;
    typedef uint32_t ogg_uint32_t;
    typedef int64_t ogg_int64_t;
+   typedef uint64_t ogg_uint64_t;
 
 #elif defined (__EMX__)
 
@@ -104,6 +108,8 @@
    typedef int ogg_int32_t;
    typedef unsigned int ogg_uint32_t;
    typedef long long ogg_int64_t;
+   typedef unsigned long long ogg_uint64_t;
+
 
 #elif defined (DJGPP)
 
@@ -112,11 +118,13 @@
    typedef int ogg_int32_t;
    typedef unsigned int ogg_uint32_t;
    typedef long long ogg_int64_t;
+   typedef unsigned long long ogg_uint64_t;
 
 #elif defined(R5900)
 
    /* PS2 EE */
    typedef long ogg_int64_t;
+   typedef unsigned long ogg_uint64_t;
    typedef int ogg_int32_t;
    typedef unsigned ogg_uint32_t;
    typedef short ogg_int16_t;
@@ -129,6 +137,7 @@
    typedef signed int ogg_int32_t;
    typedef unsigned int ogg_uint32_t;
    typedef long long int ogg_int64_t;
+   typedef unsigned long long int ogg_uint64_t;
 
 #elif defined(__TMS320C6X__)
 
@@ -138,6 +147,7 @@
    typedef signed int ogg_int32_t;
    typedef unsigned int ogg_uint32_t;
    typedef long long int ogg_int64_t;
+   typedef unsigned long long int ogg_uint64_t;
 
 #else
 

+ 2 - 2
components/codecs/inc/opus/opus.h

@@ -198,7 +198,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
  *                                     This must be one of 8000, 12000, 16000,
  *                                     24000, or 48000.
  * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
- * @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @param [in] application <tt>int</tt>: Coding mode (one of @ref OPUS_APPLICATION_VOIP, @ref OPUS_APPLICATION_AUDIO, or @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
  * @param [out] error <tt>int*</tt>: @ref opus_errorcodes
  * @note Regardless of the sampling rate and number channels selected, the Opus encoder
  * can switch to a lower audio bandwidth or number of channels if the bitrate
@@ -222,7 +222,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
  *                                      This must be one of 8000, 12000, 16000,
  *                                      24000, or 48000.
   * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
-  * @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+  * @param [in] application <tt>int</tt>: Coding mode (one of OPUS_APPLICATION_VOIP, OPUS_APPLICATION_AUDIO, or OPUS_APPLICATION_RESTRICTED_LOWDELAY)
   * @retval #OPUS_OK Success or @ref opus_errorcodes
   */
 OPUS_EXPORT int opus_encoder_init(

+ 4 - 3
components/codecs/inc/opus/opus_custom.h

@@ -104,7 +104,8 @@ typedef struct OpusCustomDecoder OpusCustomDecoder;
 /** The mode contains all the information necessary to create an
     encoder. Both the encoder and decoder need to be initialized
     with exactly the same mode, otherwise the output will be
-    corrupted.
+    corrupted. The mode MUST NOT BE DESTROYED until the encoders and
+    decoders that use it are destroyed as well.
    @brief Mode configuration
  */
 typedef struct OpusCustomMode OpusCustomMode;
@@ -178,7 +179,7 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encode
 ) OPUS_ARG_NONNULL(1);
 
 
-/** Destroys a an encoder state.
+/** Destroys an encoder state.
   * @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
   */
 OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
@@ -286,7 +287,7 @@ OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decode
     int *error
 ) OPUS_ARG_NONNULL(1);
 
-/** Destroys a an decoder state.
+/** Destroys a decoder state.
   * @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
   */
 OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);

+ 5 - 3
components/codecs/inc/opus/opus_defines.h

@@ -64,7 +64,7 @@ extern "C" {
 /**Export control for opus functions */
 
 #ifndef OPUS_EXPORT
-# if defined(WIN32)
+# if defined(_WIN32)
 #  if defined(OPUS_BUILD) && defined(DLL_EXPORT)
 #   define OPUS_EXPORT __declspec(dllexport)
 #  else
@@ -482,7 +482,8 @@ extern "C" {
   * @param[in] x <tt>opus_int32</tt>: Allowed values:
   * <dl>
   * <dt>0</dt><dd>Disable inband FEC (default).</dd>
-  * <dt>1</dt><dd>Enable inband FEC.</dd>
+  * <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
+  * <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
   * </dl>
   * @hideinitializer */
 #define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
@@ -491,7 +492,8 @@ extern "C" {
   * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
   * <dl>
   * <dt>0</dt><dd>Inband FEC disabled (default).</dd>
-  * <dt>1</dt><dd>Inband FEC enabled.</dd>
+  * <dt>1</dt><dd>Inband FEC enabled. If the packet loss rate is sufficiently high, Opus will automatically switch to SILK even at high rates to enable use of that FEC.</dd>
+  * <dt>2</dt><dd>Inband FEC enabled, but does not necessarily switch to SILK if we have music.</dd>
   * </dl>
   * @hideinitializer */
 #define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)

+ 78 - 91
components/codecs/inc/opusfile/opusfile.h

@@ -6,7 +6,7 @@
  * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING.       *
  *                                                                  *
  * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012           *
- * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * by the Xiph.Org Foundation and contributors https://xiph.org/    *
  *                                                                  *
  ********************************************************************
 
@@ -28,7 +28,7 @@
     reference
     <tt><a href="https://www.xiph.org/ogg/doc/libogg/reference.html">libogg</a></tt>
     and
-    <tt><a href="https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/index.html">libopus</a></tt>
+    <tt><a href="https://opus-codec.org/docs/opus_api-1.3.1/">libopus</a></tt>
     libraries.
 
    <tt>libopusfile</tt> provides several sets of built-in routines for
@@ -58,7 +58,7 @@
     it is stored in the header to allow you to resample to it after decoding
     (the <tt>libopusfile</tt> API does not currently provide a resampler,
     but the
-    <a href="http://www.speex.org/docs/manual/speex-manual/node7.html#SECTION00760000000000000000">the
+    <a href="https://www.speex.org/docs/manual/speex-manual/node7.html#SECTION00760000000000000000">the
     Speex resampler</a> is a good choice if you need one).
    In general, if you are playing back the audio, you should leave it at
     48&nbsp;kHz, provided your audio hardware supports it.
@@ -68,7 +68,7 @@
 
    Opus files can contain anywhere from 1 to 255 channels of audio.
    The channel mappings for up to 8 channels are the same as the
-    <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+    <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
     mappings</a>.
    A special stereo API can convert everything to 2 channels, making it simple
     to support multichannel files in an application which only has stereo
@@ -147,18 +147,18 @@ typedef struct OggOpusFile       OggOpusFile;
 /**@endcond*/
 
 /**\defgroup error_codes Error Codes*/
-/*@{*/
+/**@{*/
 /**\name List of possible error codes
    Many of the functions in this library return a negative error code when a
     function fails.
    This list provides a brief explanation of the common errors.
    See each individual function for more details on what a specific error code
     means in that context.*/
-/*@{*/
+/**@{*/
 
 /**A request did not succeed.*/
 #define OP_FALSE         (-1)
-/*Currently not used externally.*/
+/**Currently not used externally.**/
 #define OP_EOF           (-2)
 /**There was a hole in the page sequence numbers (e.g., a page was corrupt or
     missing).*/
@@ -185,7 +185,7 @@ typedef struct OggOpusFile       OggOpusFile;
 #define OP_EBADHEADER    (-133)
 /**The ID header contained an unrecognized version number.*/
 #define OP_EVERSION      (-134)
-/*Currently not used at all.*/
+/**Currently not used at all.**/
 #define OP_ENOTAUDIO     (-135)
 /**An audio packet failed to decode properly.
    This is usually caused by a multistream Ogg packet where the durations of
@@ -200,11 +200,11 @@ typedef struct OggOpusFile       OggOpusFile;
 /**The first or last granule position of a link failed basic validity checks.*/
 #define OP_EBADTIMESTAMP (-139)
 
-/*@}*/
-/*@}*/
+/**@}*/
+/**@}*/
 
 /**\defgroup header_info Header Information*/
-/*@{*/
+/**@{*/
 
 /**The maximum number of channels in an Ogg Opus stream.*/
 #define OPUS_CHANNEL_COUNT_MAX (255)
@@ -284,7 +284,7 @@ struct OpusHead{
    A particular tag may occur more than once, and order is significant.
    The character set encoding for the strings is always UTF-8, but the tag
     names are limited to ASCII, and treated as case-insensitive.
-   See <a href="http://www.xiph.org/vorbis/doc/v-comment.html">the Vorbis
+   See <a href="https://www.xiph.org/vorbis/doc/v-comment.html">the Vorbis
     comment header specification</a> for details.
 
    In filling in this structure, <tt>libopusfile</tt> will null-terminate the
@@ -311,7 +311,7 @@ struct OpusTags{
 };
 
 /**\name Picture tag image formats*/
-/*@{*/
+/**@{*/
 
 /**The MIME type was not recognized, or the image data did not match the
     declared MIME type.*/
@@ -325,7 +325,7 @@ struct OpusTags{
 /**The image is a GIF.*/
 #define OP_PIC_FORMAT_GIF     (3)
 
-/*@}*/
+/**@}*/
 
 /**The contents of a METADATA_BLOCK_PICTURE tag.*/
 struct OpusPictureTag{
@@ -398,7 +398,7 @@ struct OpusPictureTag{
    These can be used to query the headers returned by <tt>libopusfile</tt>, or
     to parse Opus headers from sources other than an Ogg Opus stream, provided
     they use the same format.*/
-/*@{*/
+/**@{*/
 
 /**Parses the contents of the ID header packet of an Ogg Opus stream.
    \param[out] _head Returns the contents of the parsed packet.
@@ -671,12 +671,12 @@ void opus_picture_tag_init(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
    \param _pic The #OpusPictureTag structure to clear.*/
 void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
 
-/*@}*/
+/**@}*/
 
-/*@}*/
+/**@}*/
 
 /**\defgroup url_options URL Reading Options*/
-/*@{*/
+/**@{*/
 /**\name URL reading options
    Options for op_url_stream_create() and associated functions.
    These allow you to provide proxy configuration parameters, skip SSL
@@ -685,7 +685,7 @@ void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
     times, only the value specified by the last occurrence has an effect
     (unless otherwise specified).
    They may be expanded in the future.*/
-/*@{*/
+/**@{*/
 
 /**@cond PRIVATE*/
 
@@ -698,7 +698,7 @@ void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
 #define OP_HTTP_PROXY_PASS_REQUEST            (6720)
 #define OP_GET_SERVER_INFO_REQUEST            (6784)
 
-#define OP_URL_OPT(_request) ((_request)+(char *)0)
+#define OP_URL_OPT(_request) ((char *)(_request))
 
 /*These macros trigger compilation errors or warnings if the wrong types are
    provided to one of the URL options.*/
@@ -843,11 +843,11 @@ void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1);
 #define OP_GET_SERVER_INFO(_info) \
  OP_URL_OPT(OP_GET_SERVER_INFO_REQUEST),OP_CHECK_SERVER_INFO_PTR(_info)
 
-/*@}*/
-/*@}*/
+/**@}*/
+/**@}*/
 
 /**\defgroup stream_callbacks Abstract Stream Reading Interface*/
-/*@{*/
+/**@{*/
 /**\name Functions for reading from streams
    These functions define the interface used to read from and seek in a stream
     of data.
@@ -856,7 +856,7 @@ void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1);
    These functions also include some convenience routines for working with
     standard <code>FILE</code> pointers, complete streams stored in a single
     block of memory, or URLs.*/
-/*@{*/
+/**@{*/
 
 /**Reads up to \a _nbytes bytes of data from \a _stream.
    \param      _stream The stream to read from.
@@ -1034,18 +1034,18 @@ OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
 OP_WARN_UNUSED_RESULT void *op_url_stream_create(OpusFileCallbacks *_cb,
  const char *_url,...) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
 
-/*@}*/
-/*@}*/
+/**@}*/
+/**@}*/
 
 /**\defgroup stream_open_close Opening and Closing*/
-/*@{*/
+/**@{*/
 /**\name Functions for opening and closing streams
 
    These functions allow you to test a stream to see if it is Opus, open it,
     and close it.
    Several flavors are provided for each of the built-in stream types, plus a
     more general version which takes a set of application-provided callbacks.*/
-/*@{*/
+/**@{*/
 
 /**Test to see if this is an Opus stream.
    For good results, you will need at least 57 bytes (for a pure Opus-only
@@ -1159,20 +1159,16 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
                          This value will be passed verbatim as the first
                           argument to all of the callbacks.
    \param _cb            The callbacks with which to access the stream.
-                         <code><a href="#op_read_func">read()</a></code> must
-                          be implemented.
-                         <code><a href="#op_seek_func">seek()</a></code> and
-                          <code><a href="#op_tell_func">tell()</a></code> may
-                          be <code>NULL</code>, or may always return -1 to
-                          indicate a stream is unseekable, but if
-                          <code><a href="#op_seek_func">seek()</a></code> is
-                          implemented and succeeds on a particular stream, then
-                          <code><a href="#op_tell_func">tell()</a></code> must
-                          also.
-                         <code><a href="#op_close_func">close()</a></code> may
-                          be <code>NULL</code>, but if it is not, it will be
-                          called when the \c OggOpusFile is destroyed by
-                          op_free().
+                         \ref op_read_func "read()" must be implemented.
+                         \ref op_seek_func "seek()" and \ref op_tell_func
+                          "tell()" may be <code>NULL</code>, or may always
+                          return -1 to indicate a stream is unseekable, but if
+                          \ref op_seek_func "seek()" is implemented and
+                          succeeds on a particular stream, then \ref
+                          op_tell_func "tell()" must also.
+                         \ref op_close_func "close()" may be <code>NULL</code>,
+                          but if it is not, it will be called when the \c
+                          OggOpusFile is destroyed by op_free().
                          It will not be called if op_open_callbacks() fails
                           with an error.
    \param _initial_data  An initial buffer of data from the start of the
@@ -1183,10 +1179,8 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
                           stream to be opened, even if it is unseekable.
    \param _initial_bytes The number of bytes in \a _initial_data.
                          If the stream is seekable, its current position (as
-                          reported by
-                          <code><a href="#opus_tell_func">tell()</a></code>
-                          at the start of this function) must be equal to
-                          \a _initial_bytes.
+                          reported by \ref op_tell_func "tell()" at the start
+                          of this function) must be equal to \a _initial_bytes.
                          Otherwise, seeking to absolute positions will
                           generate inconsistent results.
    \param[out] _error    Returns 0 on success, or a failure code on error.
@@ -1206,11 +1200,10 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
                             implemented, such as an unsupported channel
                             family.</dd>
                            <dt>#OP_EINVAL</dt>
-                           <dd><code><a href="#op_seek_func">seek()</a></code>
-                            was implemented and succeeded on this source, but
-                            <code><a href="#op_tell_func">tell()</a></code>
-                            did not, or the starting position indicator was
-                            not equal to \a _initial_bytes.</dd>
+                           <dd>\ref op_seek_func "seek()" was implemented and
+                            succeeded on this source, but \ref op_tell_func
+                            "tell()" did not, or the starting position
+                            indicator was not equal to \a _initial_bytes.</dd>
                            <dt>#OP_ENOTFORMAT</dt>
                            <dd>The stream contained a link that did not have
                             any logical Opus streams in it.</dd>
@@ -1341,20 +1334,16 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
                          This value will be passed verbatim as the first
                           argument to all of the callbacks.
    \param _cb            The callbacks with which to access the stream.
-                         <code><a href="#op_read_func">read()</a></code> must
-                          be implemented.
-                         <code><a href="#op_seek_func">seek()</a></code> and
-                          <code><a href="#op_tell_func">tell()</a></code> may
-                          be <code>NULL</code>, or may always return -1 to
-                          indicate a stream is unseekable, but if
-                          <code><a href="#op_seek_func">seek()</a></code> is
-                          implemented and succeeds on a particular stream, then
-                          <code><a href="#op_tell_func">tell()</a></code> must
-                          also.
-                         <code><a href="#op_close_func">close()</a></code> may
-                          be <code>NULL</code>, but if it is not, it will be
-                          called when the \c OggOpusFile is destroyed by
-                          op_free().
+                         \ref op_read_func "read()" must be implemented.
+                         \ref op_seek_func "seek()" and \ref op_tell_func
+                          "tell()" may be <code>NULL</code>, or may always
+                          return -1 to indicate a stream is unseekable, but if
+                          \ref op_seek_func "seek()" is implemented and
+                          succeeds on a particular stream, then \ref
+                          op_tell_func "tell()" must also.
+                         \ref op_close_func "close()" may be <code>NULL</code>,
+                          but if it is not, it will be called when the \c
+                          OggOpusFile is destroyed by op_free().
                          It will not be called if op_open_callbacks() fails
                           with an error.
    \param _initial_data  An initial buffer of data from the start of the
@@ -1367,9 +1356,8 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
    \param _initial_bytes The number of bytes in \a _initial_data.
                          If the stream is seekable, its current position (as
                           reported by
-                          <code><a href="#opus_tell_func">tell()</a></code>
-                          at the start of this function) must be equal to
-                          \a _initial_bytes.
+                          \ref op_tell_func "tell()" at the start of this
+                          function) must be equal to \a _initial_bytes.
                          Otherwise, seeking to absolute positions will
                           generate inconsistent results.
    \param[out] _error    Returns 0 on success, or a failure code on error.
@@ -1418,11 +1406,11 @@ int op_test_open(OggOpusFile *_of) OP_ARG_NONNULL(1);
    \param _of The \c OggOpusFile to free.*/
 void op_free(OggOpusFile *_of);
 
-/*@}*/
-/*@}*/
+/**@}*/
+/**@}*/
 
 /**\defgroup stream_info Stream Information*/
-/*@{*/
+/**@{*/
 /**\name Functions for obtaining information about streams
 
    These functions allow you to get basic information about a stream, including
@@ -1437,18 +1425,17 @@ void op_free(OggOpusFile *_of);
     streams returned by op_test_callbacks() or one of the associated
     convenience functions.
    Their documention will indicate so explicitly.*/
-/*@{*/
+/**@{*/
 
 /**Returns whether or not the stream being read is seekable.
    This is true if
    <ol>
-   <li>The <code><a href="#op_seek_func">seek()</a></code> and
-    <code><a href="#op_tell_func">tell()</a></code> callbacks are both
-    non-<code>NULL</code>,</li>
-   <li>The <code><a href="#op_seek_func">seek()</a></code> callback was
-    successfully executed at least once, and</li>
-   <li>The <code><a href="#op_tell_func">tell()</a></code> callback was
-    successfully able to report the position indicator afterwards.</li>
+   <li>The \ref op_seek_func "seek()" and \ref op_tell_func "tell()"
+    callbacks are both non-<code>NULL</code>,</li>
+   <li>The \ref op_seek_func "seek()" callback was successfully executed at
+    least once, and</li>
+   <li>The \ref op_tell_func "tell()" callback was successfully able to report
+    the position indicator afterwards.</li>
    </ol>
    This function may be called on partially-opened streams.
    \param _of The \c OggOpusFile whose seekable status is to be returned.
@@ -1638,11 +1625,11 @@ opus_int64 op_raw_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
    \retval #OP_EINVAL The stream was only partially open.*/
 ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
 
-/*@}*/
-/*@}*/
+/**@}*/
+/**@}*/
 
 /**\defgroup stream_seeking Seeking*/
-/*@{*/
+/**@{*/
 /**\name Functions for seeking in Opus streams
 
    These functions let you seek in Opus streams, if the underlying stream
@@ -1667,7 +1654,7 @@ ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
     values as would be obtained by decoding the stream straight through.
    However, such differences are expected to be smaller than the loss
     introduced by Opus's lossy compression.*/
-/*@{*/
+/**@{*/
 
 /**Seek to a byte offset relative to the <b>compressed</b> data.
    This also scans packets to update the PCM cursor.
@@ -1702,11 +1689,11 @@ int op_raw_seek(OggOpusFile *_of,opus_int64 _byte_offset) OP_ARG_NONNULL(1);
                          seeking to the target destination was impossible.*/
 int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
 
-/*@}*/
-/*@}*/
+/**@}*/
+/**@}*/
 
 /**\defgroup stream_decoding Decoding*/
-/*@{*/
+/**@{*/
 /**\name Functions for decoding audio data
 
    These functions retrieve actual decoded audio data from the stream.
@@ -1744,7 +1731,7 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
    If you are reading from an <https:> URL (particularly if seeking is not
     supported), you should make sure to check for this error and warn the user
     appropriately.*/
-/*@{*/
+/**@{*/
 
 /**Indicates that the decoding callback should produce signed 16-bit
     native-endian output samples.*/
@@ -1890,7 +1877,7 @@ void op_set_dither_enabled(OggOpusFile *_of,int _enabled) OP_ARG_NONNULL(1);
                           signed native-endian 16-bit values at 48&nbsp;kHz
                           with a nominal range of <code>[-32768,32767)</code>.
                          Multiple channels are interleaved using the
-                          <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+                          <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
                           channel ordering</a>.
                          This must have room for at least \a _buf_size values.
    \param      _buf_size The number of values that can be stored in \a _pcm.
@@ -1972,7 +1959,7 @@ OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of,
                           signed floats at 48&nbsp;kHz with a nominal range of
                           <code>[-1.0,1.0]</code>.
                          Multiple channels are interleaved using the
-                          <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+                          <a href="https://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810004.3.9">Vorbis
                           channel ordering</a>.
                          This must have room for at least \a _buf_size floats.
    \param      _buf_size The number of floats that can be stored in \a _pcm.
@@ -2150,8 +2137,8 @@ OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of,
 OP_WARN_UNUSED_RESULT int op_read_float_stereo(OggOpusFile *_of,
  float *_pcm,int _buf_size) OP_ARG_NONNULL(1);
 
-/*@}*/
-/*@}*/
+/**@}*/
+/**@}*/
 
 # if OP_GNUC_PREREQ(4,0)
 #  pragma GCC visibility pop

BIN
components/codecs/lib/libFLAC.a


BIN
components/codecs/lib/libogg.a


BIN
components/codecs/lib/libopus.a


BIN
components/codecs/lib/libopusfile.a


+ 1 - 1
components/display/core/gds_default_if.h

@@ -11,7 +11,7 @@ bool GDS_I2CInit( int PortNumber, int SDA, int SCL, int speed );
 bool GDS_I2CAttachDevice( struct GDS_Device* Device, int Width, int Height, int I2CAddress, int RSTPin, int BacklightPin );
 
 bool GDS_SPIInit( int SPI, int DC );
-bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin );
+bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int Speed, int BacklightPin, int Mode );
 
 #ifdef __cplusplus
 }

+ 2 - 1
components/display/core/ifaces/default_if_spi.c

@@ -34,7 +34,7 @@ bool GDS_SPIInit( int SPI, int DC ) {
     return true;
 }
 
-bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed ) {
+bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int CSPin, int RSTPin, int BackLightPin, int Speed, int Mode ) {
     spi_device_interface_config_t SPIDeviceConfig = { };
     spi_device_handle_t SPIDevice;
 
@@ -48,6 +48,7 @@ bool GDS_SPIAttachDevice( struct GDS_Device* Device, int Width, int Height, int
     SPIDeviceConfig.clock_speed_hz = Speed > 0 ? Speed : SPI_MASTER_FREQ_8M;
     SPIDeviceConfig.spics_io_num = CSPin;
     SPIDeviceConfig.queue_size = 1;
+    SPIDeviceConfig.mode = Mode;
 	SPIDeviceConfig.flags = SPI_DEVICE_NO_DUMMY;
 	if (Device->SPIParams) Device->SPIParams(SPIDeviceConfig.clock_speed_hz, &SPIDeviceConfig.mode, 
 											 &SPIDeviceConfig.cs_ena_pretrans, &SPIDeviceConfig.cs_ena_posttrans);

+ 3 - 2
components/display/display.c

@@ -119,14 +119,15 @@ void display_init(char *welcome) {
 		
 			ESP_LOGI(TAG, "Display is I2C on port %u", address);
 		} else if (strcasestr(config, "SPI") && spi_system_host != -1) {
-			int CS_pin = -1, speed = 0;
+			int CS_pin = -1, speed = 0, mode = 0;
 		
 			PARSE_PARAM(config, "cs", '=', CS_pin);
 			PARSE_PARAM(config, "speed", '=', speed);
+			PARSE_PARAM(config, "mode", '=', mode);
 		
 			init = true;
 			GDS_SPIInit( spi_system_host, spi_system_dc_gpio );
-			GDS_SPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed );
+			GDS_SPIAttachDevice( display, width, height, CS_pin, RST_pin, backlight_pin, speed, mode );
 				
 			ESP_LOGI(TAG, "Display is SPI host %u with cs:%d", spi_system_host, CS_pin);
 		} else {

+ 25 - 16
components/driver_bt/bt_app_core.c

@@ -83,25 +83,26 @@ static void bt_app_task_handler(void *arg)
 	
 	esp_bt_controller_mem_release(ESP_BT_MODE_BLE);
     esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
-	
-    if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
-        ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
-        goto exit;
-    }
+	if (esp_bt_controller_get_status() == ESP_BT_CONTROLLER_STATUS_IDLE ) {
+        if ((err = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
+            ESP_LOGE(TAG, "%s initialize controller failed: %s\n", __func__, esp_err_to_name(err));
+            goto exit;
+        }
 
-    if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
-        ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
-		goto exit;
-    }
+        if ((err = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK) {
+            ESP_LOGE(TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(err));
+            goto exit;
+        }
 
-    if ((err = esp_bluedroid_init()) != ESP_OK) {
-        ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
-		goto exit;
-    }
+        if ((err = esp_bluedroid_init()) != ESP_OK) {
+            ESP_LOGE(TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(err));
+            goto exit;
+        }
 
-    if ((err = esp_bluedroid_enable()) != ESP_OK) {
-        ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
-		goto exit;
+        if ((err = esp_bluedroid_enable()) != ESP_OK) {
+            ESP_LOGE(TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(err));
+            goto exit;
+        }
     }
 	
 	/* Bluetooth device name, connection mode and profile set up */
@@ -114,6 +115,14 @@ static void bt_app_task_handler(void *arg)
     esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
 #endif
 	
+    /*
+     * Set default parameters for Legacy Pairing
+     * Use variable pin, input pin code when pairing
+     */
+    esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
+    esp_bt_pin_code_t pin_code;
+    esp_bt_gap_set_pin(pin_type, 0, pin_code);
+	
 	running = true;
 	
 	while (running) {

+ 1 - 1
components/driver_bt/bt_app_sink.c

@@ -136,7 +136,7 @@ const static actrls_t controls = {
 	NULL, NULL,			// rew, fwd
 	bt_prev, bt_next,	// prev, next
 	NULL, NULL, NULL, NULL, // left, right, up, down
-	NULL, NULL, NULL, NULL, NULL, NULL, // pre1-6
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // pre1-10
 	bt_volume_down, bt_volume_up, bt_toggle// knob left, knob_right, knob push
 };
 

+ 2 - 2
components/driver_bt/bt_app_source.c

@@ -672,9 +672,9 @@ static void filter_inquiry_scan_result(esp_bt_gap_cb_param_t *param)
     	ESP_LOGV(TAG,"--Invalid class of device. Skipping.\n");
     	return;
     }
-    else if (!(esp_bt_gap_get_cod_srvc(cod) & ESP_BT_COD_SRVC_RENDERING))
+    else if (!(esp_bt_gap_get_cod_srvc(cod) & (ESP_BT_COD_SRVC_RENDERING | ESP_BT_COD_SRVC_AUDIO)))
     {
-    	ESP_LOGV(TAG,"--Not a rendering device. Skipping.\n");
+    	ESP_LOGV(TAG,"--Not a rendering or audio device. Skipping.\n");
     	return;
     }
 

+ 3 - 3
components/platform_config/platform_config.c

@@ -121,7 +121,7 @@ void config_start_timer(){
 nvs_type_t  config_get_item_type(cJSON * entry){
 	if(entry==NULL){
 		ESP_LOGE(TAG,"null pointer received!");
-		return true;
+		return 0;
 	}
 	cJSON * item_type = cJSON_GetObjectItemCaseSensitive(entry, "type");
 	if(item_type ==NULL ) {
@@ -142,7 +142,7 @@ cJSON * config_set_value_safe(nvs_type_t nvs_type, const char *key,  const void
 		return NULL;
 	}
 
-	cJSON * existing = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
+cJSON * existing = cJSON_GetObjectItemCaseSensitive(nvs_json, key);
 	if(existing !=NULL && nvs_type == NVS_TYPE_STR && config_get_item_type(existing) != NVS_TYPE_STR  ) {
 		ESP_LOGW(TAG, "Storing numeric value from string");
 		numvalue = atof((char *)value);
@@ -634,7 +634,7 @@ cJSON * config_alloc_get_cjson(const char *key){
 	}
 	return conf_json;
 }
-esp_err_t config_set_cjson_str(const char *key, cJSON *value){
+esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value){
 	char * value_str = cJSON_PrintUnformatted(value);
 	if(value_str==NULL){
 		ESP_LOGE(TAG, "Unable to print cJSON for key [%s]", key);

+ 1 - 1
components/platform_config/platform_config.h

@@ -53,7 +53,7 @@ void config_init();
 void * config_alloc_get_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size);
 void * config_alloc_get_str(const char *key, char *lead, char *fallback);
 cJSON * config_alloc_get_cjson(const char *key);
-esp_err_t config_set_cjson_str(const char *key, cJSON *value);
+esp_err_t config_set_cjson_str_and_free(const char *key, cJSON *value);
 void config_get_uint16t_from_str(const char *key, uint16_t *value, uint16_t default_value);
 void config_delete_key(const char *key);
 void config_set_default(nvs_type_t type, const char *key, void * default_value, size_t blob_size);

+ 1 - 1
components/platform_console/app_squeezelite/CMakeLists.txt

@@ -1,7 +1,7 @@
 idf_build_get_property(idf_path IDF_PATH)
 idf_component_register( SRCS cmd_squeezelite.c 
 						INCLUDE_DIRS . 
-						PRIV_REQUIRES spi_flash bootloader_support  partition_table bootloader_support console codecs squeezelite newlib pthread tools platform_config display tools)
+						PRIV_REQUIRES spi_flash bootloader_support  partition_table bootloader_support console codecs squeezelite newlib pthread tools platform_config display tools services)
 						
 
 target_link_libraries(${COMPONENT_LIB} INTERFACE "-Wl,--undefined=feof")

+ 21 - 18
components/platform_console/app_squeezelite/cmd_squeezelite.c

@@ -12,6 +12,7 @@
 #include "platform_config.h"
 #include "esp_app_format.h"
 #include "tools.h"
+#include "messaging.h"
 
 extern esp_err_t process_recovery_ota(const char * bin_url, char * bin_buffer, uint32_t length);
 static const char * TAG = "squeezelite_cmd";
@@ -39,7 +40,8 @@ const __attribute__((section(".rodata_desc"))) esp_app_desc_t esp_app_desc = {
 #endif
 };
 
-extern int main(int argc, char **argv);
+extern int squeezelite_main(int argc, char **argv);
+
 static int launchsqueezelite(int argc, char **argv);
 
 /** Arguments used by 'squeezelite' function */
@@ -53,31 +55,32 @@ static struct {
 } thread_parms ;
 
 #define ADDITIONAL_SQUEEZELITE_ARGS 5
-static void squeezelite_thread(void *arg){
+static void squeezelite_thread(void *arg){  
 	ESP_LOGV(TAG ,"Number of args received: %u",thread_parms.argc );
 	ESP_LOGV(TAG ,"Values:");
     for(int i = 0;i<thread_parms.argc; i++){
     	ESP_LOGV(TAG ,"     %s",thread_parms.argv[i]);
     }
+    ESP_LOGI(TAG ,"Calling squeezelite");
+    int ret = squeezelite_main(thread_parms.argc, thread_parms.argv);
+        
+    cmd_send_messaging("cfg-audio-tmpl",ret > 1 ?  MESSAGING_ERROR : MESSAGING_WARNING,"squeezelite exited with error code %d\n", ret);
+
+    if (ret == 1) {
+        int wait = 60;
+        wait_for_commit();
+        cmd_send_messaging("cfg-audio-tmpl",MESSAGING_ERROR,"Rebooting in %d sec\n", wait);
+        vTaskDelay( pdMS_TO_TICKS(wait * 1000));
+        esp_restart();
+    } else {
+		cmd_send_messaging("cfg-audio-tmpl",MESSAGING_ERROR,"Correct command line and reboot\n");
+        vTaskSuspend(NULL);
+    }
 
-	ESP_LOGI(TAG ,"Calling squeezelite");
-	main(thread_parms.argc,thread_parms.argv);
-	ESP_LOGV(TAG ,"Exited from squeezelite's main(). Freeing argv structure.");
+	ESP_LOGV(TAG, "Exited from squeezelite's main(). Freeing argv structure.");
 
-	for(int i=0;i<thread_parms.argc;i++){
-		ESP_LOGV(TAG ,"Freeing char buffer for parameter %u", i+1);
-		free(thread_parms.argv[i]);
-	}
-	ESP_LOGV(TAG ,"Freeing argv pointer");
+	for(int i=0;i<thread_parms.argc;i++) free(thread_parms.argv[i]);
 	free(thread_parms.argv);
-	
-	ESP_LOGE(TAG, "Exited from squeezelite thread, something's wrong ... rebooting (wait 30s for user to take action)");
-	if(!wait_for_commit()){
-		ESP_LOGW(TAG,"Unable to commit configuration. ");
-	}
-
-	vTaskDelay( pdMS_TO_TICKS( 30*1000 ) );
-    esp_restart();
 }
 
 static int launchsqueezelite(int argc, char **argv) {

+ 25 - 16
components/platform_console/cmd_config.c

@@ -602,8 +602,9 @@ static int is_valid_gpio_number(int gpio, const char * name, FILE *f, bool manda
 	}
 	return 0;
 }
+
+#ifdef CONFIG_CSPOT_SINK
 static int do_cspot_config(int argc, char **argv){
-	char * name = NULL;
     int nerrors = arg_parse_msg(argc, argv,(struct arg_hdr **)&cspot_args);
     if (nerrors != 0) {
         return 1;
@@ -620,32 +621,37 @@ static int do_cspot_config(int argc, char **argv){
 	cJSON * cspot_config = config_alloc_get_cjson("cspot_config");
 	if(!cspot_config){
 		nerrors++;
-		fprintf(f,"error: Unable to get cspot config.\n");
+		fprintf(f,"error: Unable to get default cspot config.\n");
 	}
-	else {
-		cjson_update_string(&cspot_config,cspot_args.deviceName->hdr.longopts,cspot_args.deviceName->count>0?cspot_args.deviceName->sval[0]:NULL);
-//		cjson_update_number(&cspot_config,cspot_args.volume->hdr.longopts,cspot_args.volume->count>0?cspot_args.volume->ival[0]:0);
-		cjson_update_number(&cspot_config,cspot_args.bitrate->hdr.longopts,cspot_args.bitrate->count>0?cspot_args.bitrate->ival[0]:0);
+	if(cspot_args.deviceName->count>0){
+		cjson_update_string(&cspot_config,cspot_args.deviceName->hdr.longopts,cspot_args.deviceName->sval[0]);
 	}
+	if(cspot_args.bitrate->count>0){
+		cjson_update_number(&cspot_config,cspot_args.bitrate->hdr.longopts,cspot_args.bitrate->ival[0]);
+	}	
 	
 	if(!nerrors ){
 		fprintf(f,"Storing cspot parameters.\n");
-		nerrors+=(config_set_cjson_str("cspot_config",cspot_config) !=ESP_OK);
+		nerrors+=(config_set_cjson_str_and_free("cspot_config",cspot_config) !=ESP_OK);
 	}
-	if(nerrors==0){
-		fprintf(f,"Device name changed to %s\n",name);
+	if(nerrors==0 ){
+		if(cspot_args.deviceName->count>0){
+			fprintf(f,"Device name changed to %s\n",cspot_args.deviceName->sval[0]);
+		}
+		if(cspot_args.bitrate->count>0){
+			fprintf(f,"Bitrate changed to %u\n",cspot_args.bitrate->ival[0]);
+		}
 	}
 	if(!nerrors ){
 		fprintf(f,"Done.\n");
 	}
-	FREE_AND_NULL(name);
 	fflush (f);
 	cmd_send_messaging(argv[0],nerrors>0?MESSAGING_ERROR:MESSAGING_INFO,"%s", buf);
 	fclose(f);
 	FREE_AND_NULL(buf);
 	return nerrors;
 }
-
+#endif
 
 static int do_ledvu_cmd(int argc, char **argv){
 	ledvu_struct_t ledvu={  .type = "WS2812", .gpio = -1, .length = 0};
@@ -800,6 +806,7 @@ cJSON * known_model_cb(){
 	}
 	return values;
 }
+#ifdef CONFIG_CSPOT_SINK
 cJSON * cspot_cb(){
 	cJSON * values = cJSON_CreateObject();
 	if(!values){
@@ -819,13 +826,11 @@ cJSON * cspot_cb(){
 	if(cspot_values){
 		cJSON_AddNumberToObject(values,cspot_args.bitrate->hdr.longopts,cJSON_GetNumberValue(cspot_values));
 	}
-	// cspot_values = cJSON_GetObjectItem(cspot_config,cspot_args.volume->hdr.longopts);
-	// if(cspot_values){
-	// 	cJSON_AddNumberToObject(values,cspot_args.volume->hdr.longopts,cJSON_GetNumberValue(cspot_values));
-	// }
+
 	cJSON_Delete(cspot_config);
 	return values;
 }
+#endif
 cJSON * i2s_cb(){
 	cJSON * values = cJSON_CreateObject();
 
@@ -1247,7 +1252,7 @@ static void register_known_templates_config(){
     cmd_to_json_with_cb(&cmd,&known_model_cb);
     ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
 }
-
+#ifdef CONFIG_CSPOT_SINK
 static void register_cspot_config(){
 	cspot_args.deviceName = arg_str1(NULL,"deviceName","","Device Name");
 	cspot_args.bitrate = arg_int1(NULL,"bitrate","96|160|320","Streaming Bitrate (kbps)");
@@ -1263,6 +1268,7 @@ static void register_cspot_config(){
 	cmd_to_json_with_cb(&cmd,&cspot_cb);
 	ESP_ERROR_CHECK(esp_console_cmd_register(&cmd));
 }
+#endif
 static void register_i2s_config(void){
 	i2s_args.model_name = arg_str1(NULL,"model_name",STR_OR_BLANK(get_dac_list()),"DAC Model Name");
 	i2s_args.clear = arg_lit0(NULL, "clear", "Clear configuration");
@@ -1422,8 +1428,11 @@ static void register_squeezelite_config(void){
 void register_config_cmd(void){
 	if(!is_dac_config_locked()){
 	 	 register_known_templates_config();
+	
 	}
+#ifdef CONFIG_CSPOT_SINK	
 	register_cspot_config();
+#endif	
 	register_audio_config();
 //	register_squeezelite_config();
 	register_bt_source_config();

+ 12 - 0
components/platform_console/cmd_i2ctools.c

@@ -101,6 +101,7 @@ static struct {
 	struct arg_int *reset;
 	struct arg_lit *clear;
 	struct arg_lit *invert;
+	struct arg_int *mode;
 	struct arg_end *end;
 } i2cdisp_args;
 
@@ -377,6 +378,13 @@ static int do_i2c_set_display(int argc, char **argv)
 		}
 		/* Check "--cs" option */
 		nerrors +=is_output_gpio(i2cdisp_args.cs,f,&config.CS_pin, false);
+	    /* Check "--mode" option */
+		if (i2cdisp_args.mode->count) {
+			config.mode=i2cdisp_args.mode->ival[0];
+		}
+		else {
+			config.mode = 0;
+		}
 	}
 
 	nerrors +=is_output_gpio(i2cdisp_args.reset,f,&config.RST_pin, false);
@@ -964,6 +972,9 @@ cJSON * i2c_set_display_cb(){
 		cJSON_AddBoolToObject(values,"hf",conf->hflip);
 		cJSON_AddBoolToObject(values,"vf",conf->vflip);
 		cJSON_AddBoolToObject(values,"invert",conf->invert);
+		if(conf->mode>=0){
+			cJSON_AddNumberToObject(values,"mode",conf->mode);
+		}	
 	}
 	return values;
 }
@@ -986,6 +997,7 @@ static void register_i2c_set_display(){
 	i2cdisp_args.rotate = 	arg_lit0("r", "rotate", "Rotate 180 degrees");
 	i2cdisp_args.invert = 	arg_lit0("i", "invert", "Invert colors");
 	i2cdisp_args.clear = 	arg_lit0(NULL, "clear", "clear configuration and return");
+	i2cdisp_args.mode = 	arg_int0("m", "mode", "<n>","SPI Only. Transaction Line Mode (Default 0)");
 	i2cdisp_args.end = 		arg_end(8);
 	const esp_console_cmd_t i2c_set_display= {
 		.command = CFG_TYPE_HW("display"),

+ 0 - 19
components/platform_console/cmd_system.c

@@ -69,7 +69,6 @@ static void register_deep_sleep();
 static void register_light_sleep();
 static void register_factory_boot();
 static void register_restart_ota();
-static void register_update_certs();
 static void register_set_services();
 #if WITH_TASKS_INFO
 static void register_tasks();
@@ -86,7 +85,6 @@ void register_system()
     register_restart();
     register_deep_sleep();
     register_light_sleep();
-    register_update_certs();
     register_factory_boot();
     register_restart_ota();
 #if WITH_TASKS_INFO
@@ -562,23 +560,6 @@ static void register_tasks()
 
 #endif // WITH_TASKS_INFO
 
-extern esp_err_t update_certificates(bool force);
-static int force_update_cert(int argc, char **argv){
-	return update_certificates(true);
-}
-
-static void register_update_certs()
-{
-    const esp_console_cmd_t cmd = {
-        .command = "update_certificates",
-        .help = "Force updating the certificates from binary",
-        .hint = NULL,
-        .func = &force_update_cert,
-    };
-    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
-}
-
-
 
 /** 'deep_sleep' command puts the chip into deep sleep mode */
 

+ 4 - 0
components/raop/dmap_parser.c

@@ -50,6 +50,7 @@ static const dmap_field dmap_fields[] = {
 	{ "abar",    DMAP_DICT, DMAP_STR,  "daap.browseartistlisting" },
 	{ "abcp",    DMAP_DICT, DMAP_STR,  "daap.browsecomposerlisting" },
 	{ "abgn",    DMAP_DICT, DMAP_STR,  "daap.browsegenrelisting" },
+#ifdef DMAP_FULL        
 	{ "abpl",    DMAP_UINT, 0,         "daap.baseplaylist" },
 	{ "abro",    DMAP_DICT, 0,         "daap.databasebrowse" },
 	{ "adbs",    DMAP_DICT, 0,         "daap.databasesongs" },
@@ -256,10 +257,12 @@ static const dmap_field dmap_fields[] = {
 	{ "meia",    DMAP_UINT, 0,         "dmap.itemdateadded" },
 	{ "meip",    DMAP_UINT, 0,         "dmap.itemdateplayed" },
 	{ "mext",    DMAP_UINT, 0,         "dmap.objectextradata" },
+#endif    
 	{ "miid",    DMAP_UINT, 0,         "dmap.itemid" },
 	{ "mikd",    DMAP_UINT, 0,         "dmap.itemkind" },
 	{ "mimc",    DMAP_UINT, 0,         "dmap.itemcount" },
 	{ "minm",    DMAP_STR,  0,         "dmap.itemname" },
+#ifdef DMAP_FULL    
 	{ "mlcl",    DMAP_DICT, DMAP_DICT, "dmap.listing" },
 	{ "mlid",    DMAP_UINT, 0,         "dmap.sessionid" },
 	{ "mlit",    DMAP_ITEM, 0,         "dmap.listingitem" },
@@ -314,6 +317,7 @@ static const dmap_field dmap_fields[] = {
 	{ "prat",    DMAP_UINT, 0,         "dpap.imagerating" },
 	{ "pret",    DMAP_DICT, 0,         "dpap.retryids" },
 	{ "pwth",    DMAP_UINT, 0,         "dpap.imagepixelwidth" }
+#endif    
 };
 static const size_t dmap_field_count = sizeof(dmap_fields) / sizeof(dmap_field);
 

+ 1 - 1
components/raop/raop.c

@@ -959,7 +959,7 @@ static int base64_decode(const char *str, void *data)
 /*----------------------------------------------------------------------------*/
 static void on_dmap_string(void *ctx, const char *code, const char *name, const char *buf, size_t len) {
 	struct metadata_s *metadata = (struct metadata_s *) ctx;
-
+    // to gain space, most of the code have been removed from dmap_parser.c (define DMAP_FULL)
 	if (!strcasecmp(code, "asar")) metadata->artist = strndup(buf, len);
 	else if (!strcasecmp(code, "asal")) metadata->album = strndup(buf, len);
 	else if (!strcasecmp(code, "minm")) metadata->title = strndup(buf, len);

+ 1 - 1
components/raop/raop_sink.c

@@ -90,7 +90,7 @@ const static actrls_t controls = {
 	NULL, NULL,							// rew, fwd
 	raop_prev, raop_next,				// prev, next
 	NULL, NULL, NULL, NULL, // left, right, up, down
-	NULL, NULL, NULL, NULL, NULL, NULL, // pre1-6
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, // pre1-10
 	raop_volume_down, raop_volume_up, raop_toggle// knob left, knob_right, knob push
 };
 

+ 27 - 23
components/raop/rtp.c

@@ -71,7 +71,8 @@ static log_level 	*loglevel = &raop_loglevel;
 //#define __RTP_STORE
 
 // default buffer size
-#define BUFFER_FRAMES 	( (150 * RAOP_SAMPLE_RATE * 2) / (352 * 100) )
+#define BUFFER_FRAMES_MAX 	((RAOP_SAMPLE_RATE * 10) / 352 )
+#define BUFFER_FRAMES_MIN 	( (150 * RAOP_SAMPLE_RATE * 2) / (352 * 100) )
 #define MAX_PACKET       1408
 #define MIN_LATENCY		11025
 #define MAX_LATENCY   	( (120 * RAOP_SAMPLE_RATE * 2) / 100 )
@@ -86,14 +87,15 @@ static log_level 	*loglevel = &raop_loglevel;
 enum { DATA = 0, CONTROL, TIMING };
 
 static const u8_t silence_frame[MAX_PACKET] = { 0 };
+uint32_t buffer_frames = ((150 * RAOP_SAMPLE_RATE * 2) / (352 * 100));
 
 typedef u16_t seq_t;
-typedef struct audio_buffer_entry {   // decoded audio packets
-	int ready;
+typedef struct __attribute__((__packed__)) audio_buffer_entry {   // decoded audio packets
 	u32_t rtptime, last_resend;
 	s16_t *data;
-	int len;
-	bool allocated;
+    u16_t len;    
+    u8_t ready;
+    u8_t allocated;
 } abuf_t;
 
 typedef struct rtp_s {
@@ -133,7 +135,7 @@ typedef struct rtp_s {
 	u32_t resent_req, resent_rec;	// total resent + recovered frames
 	u32_t silent_frames;	// total silence frames
 	u32_t discarded;
-	abuf_t audio_buffer[BUFFER_FRAMES];
+	abuf_t audio_buffer[BUFFER_FRAMES_MAX];
 	seq_t ab_read, ab_write;
 	pthread_mutex_t ab_mutex;
 #ifdef WIN32
@@ -152,7 +154,7 @@ typedef struct rtp_s {
 } rtp_t;
 
 
-#define BUFIDX(seqno) ((seq_t)(seqno) % BUFFER_FRAMES)
+#define BUFIDX(seqno) ((seq_t)(seqno) % buffer_frames)
 static void 	buffer_alloc(abuf_t *audio_buffer, int size, uint8_t *buf, size_t buf_size);
 static void 	buffer_release(abuf_t *audio_buffer);
 static void 	buffer_reset(abuf_t *audio_buffer);
@@ -373,25 +375,27 @@ void rtp_record(rtp_t *ctx, unsigned short seqno, unsigned rtptime) {
 
 /*---------------------------------------------------------------------------*/
 static void buffer_alloc(abuf_t *audio_buffer, int size, uint8_t *buf, size_t buf_size) {
-	int i;
-	for (i = 0; i < BUFFER_FRAMES; i++) {
-		if (buf && buf_size >= size) {
-			audio_buffer[i].data = (s16_t*) buf;
-			audio_buffer[i].allocated = false;
-			buf += size;
-			buf_size -= size;
-		} else {
-			audio_buffer[i].allocated = true;
-			audio_buffer[i].data = malloc(size);
-		}
-		audio_buffer[i].ready = 0;
+    for (buffer_frames = 0; buf && buf_size >= size && buffer_frames < BUFFER_FRAMES_MAX; buffer_frames++) {
+    	audio_buffer[buffer_frames].data = (s16_t*) buf;
+		audio_buffer[buffer_frames].allocated = 0;
+        audio_buffer[buffer_frames].ready = 0;
+        buf += size;
+        buf_size -= size;
+    }    
+    
+    LOG_INFO("allocated %d buffers (min=%d) from buffer of %zu bytes", buffer_frames, BUFFER_FRAMES_MIN, buf_size + buffer_frames * size);
+    
+    for(; buffer_frames < BUFFER_FRAMES_MIN; buffer_frames++) {
+		audio_buffer[buffer_frames].data = malloc(size);        
+		audio_buffer[buffer_frames].allocated = 1;
+		audio_buffer[buffer_frames].ready = 0;
 	}
 }
 
 /*---------------------------------------------------------------------------*/
 static void buffer_release(abuf_t *audio_buffer) {
 	int i;
-	for (i = 0; i < BUFFER_FRAMES; i++) {
+	for (i = 0; i < buffer_frames; i++) {
 		if (audio_buffer[i].allocated) free(audio_buffer[i].data);
 	}
 }
@@ -399,7 +403,7 @@ static void buffer_release(abuf_t *audio_buffer) {
 /*---------------------------------------------------------------------------*/
 static void buffer_reset(abuf_t *audio_buffer) {
 	int i;
-	for (i = 0; i < BUFFER_FRAMES; i++) audio_buffer[i].ready = 0;
+	for (i = 0; i < buffer_frames; i++) audio_buffer[i].ready = 0;
 }
 
 /*---------------------------------------------------------------------------*/
@@ -411,7 +415,7 @@ static int seq_order(seq_t a, seq_t b) {
 }
 
 /*---------------------------------------------------------------------------*/
-static void alac_decode(rtp_t *ctx, s16_t *dest, char *buf, int len, int *outsize) {
+static void alac_decode(rtp_t *ctx, s16_t *dest, char *buf, int len, u16_t *outsize) {
 	unsigned char iv[16];
 	int aeslen;
 	assert(len<=MAX_PACKET);
@@ -803,7 +807,7 @@ static bool rtp_request_resend(rtp_t *ctx, seq_t first, seq_t last) {
 	unsigned char req[8];    // *not* a standard RTCP NACK
 
 	// do not request silly ranges (happens in case of network large blackouts)
-	if (seq_order(last, first) || last - first > BUFFER_FRAMES / 2) return false;
+	if (seq_order(last, first) || last - first > buffer_frames / 2) return false;
 	
 	ctx->resent_req += (seq_t) (last - first) + 1;
 

+ 7 - 0
components/services/accessors.c

@@ -374,6 +374,10 @@ esp_err_t config_display_set(const display_config_t * config){
 			snprintf(config_buffer2,buffer_size,"%s,speed=%i",config_buffer,config->speed);
 			strcpy(config_buffer,config_buffer2);
 		}
+		if(config->mode >=0 && strcasecmp("SPI",config->type)==0){
+			snprintf(config_buffer2,buffer_size,"%s,mode=%i",config_buffer,config->mode);
+			strcpy(config_buffer,config_buffer2);
+		}
 		snprintf(config_buffer2,buffer_size,"%s,driver=%s%s%s%s",config_buffer,config->drivername,config->hflip?",HFlip":"",config->vflip?",VFlip":"",config->rotate?",rotate":"");
 		strcpy(config_buffer,config_buffer2);
 		log_send_messaging(MESSAGING_INFO,"Updating display configuration to %s",config_buffer);
@@ -487,6 +491,7 @@ const display_config_t * config_display_get(){
 		.rotate = false,
 		.invert = false,
 		.colorswap = 0,
+		.mode = 0,
 	};
 	char *config = config_alloc_get(NVS_TYPE_STR, "display_config");
 	if (!config) {
@@ -506,6 +511,8 @@ const display_config_t * config_display_get(){
 	PARSE_PARAM(config, "address", '=', dstruct.address);
 	PARSE_PARAM(config, "cs", '=', dstruct.CS_pin);
 	PARSE_PARAM(config, "speed", '=', dstruct.speed);
+	PARSE_PARAM(config, "back", '=', dstruct.back);
+	PARSE_PARAM(config, "mode", '=', dstruct.mode);
 
 	if (strstr(config, "I2C") ) dstruct.type=i2c_name_type;
 	if (strstr(config, "SPI") ) dstruct.type=spi_name_type;

+ 1 - 0
components/services/accessors.h

@@ -33,6 +33,7 @@ typedef struct {
 	bool rotate;
 	bool invert;
 	int colorswap;
+	int mode;
 } display_config_t;
 
 typedef struct eth_config_struct {

+ 1 - 1
components/services/audio_controls.c

@@ -60,7 +60,7 @@ static const actrls_config_map_t actrls_config_map[] =
 static const char * actrls_action_s[ ] = { EP(ACTRLS_POWER),EP(ACTRLS_VOLUP),EP(ACTRLS_VOLDOWN),EP(ACTRLS_TOGGLE),EP(ACTRLS_PLAY),
 									EP(ACTRLS_PAUSE),EP(ACTRLS_STOP),EP(ACTRLS_REW),EP(ACTRLS_FWD),EP(ACTRLS_PREV),EP(ACTRLS_NEXT),
 									EP(BCTRLS_UP),EP(BCTRLS_DOWN),EP(BCTRLS_LEFT),EP(BCTRLS_RIGHT), 
-									EP(BCTRLS_PS1),EP(BCTRLS_PS2),EP(BCTRLS_PS3),EP(BCTRLS_PS4),EP(BCTRLS_PS5),EP(BCTRLS_PS6),
+									EP(BCTRLS_PS0),EP(BCTRLS_PS1),EP(BCTRLS_PS2),EP(BCTRLS_PS3),EP(BCTRLS_PS4),EP(BCTRLS_PS5),EP(BCTRLS_PS6),EP(BCTRLS_PS7),EP(BCTRLS_PS8),EP(BCTRLS_PS9),
 									EP(KNOB_LEFT),EP(KNOB_RIGHT),EP(KNOB_PUSH),
 									""} ;
 									

+ 1 - 1
components/services/audio_controls.h

@@ -14,7 +14,7 @@
 typedef enum { 	ACTRLS_NONE = -1, ACTRLS_POWER,ACTRLS_VOLUP, ACTRLS_VOLDOWN, ACTRLS_TOGGLE, ACTRLS_PLAY, 
 				ACTRLS_PAUSE, ACTRLS_STOP, ACTRLS_REW, ACTRLS_FWD, ACTRLS_PREV, ACTRLS_NEXT, 
 				BCTRLS_UP, BCTRLS_DOWN, BCTRLS_LEFT, BCTRLS_RIGHT, 
-				BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,
+				BCTRLS_PS0,BCTRLS_PS1,BCTRLS_PS2,BCTRLS_PS3,BCTRLS_PS4,BCTRLS_PS5,BCTRLS_PS6,BCTRLS_PS7,BCTRLS_PS8,BCTRLS_PS9,
 				KNOB_LEFT, KNOB_RIGHT, KNOB_PUSH,
 				ACTRLS_REMAP, ACTRLS_MAX 
 		} actrls_action_e;

+ 3 - 1
components/services/buttons.c

@@ -415,7 +415,7 @@ bool create_rotary(void *id, int A, int B, int SW, int long_press, rotary_handle
 	// create companion button if rotary has a switch
 	if (SW != -1) button_create(id, SW, BUTTON_LOW, true, 0, rotary_button_handler, long_press, -1);
 	
-	ESP_LOGI(TAG, "Creating rotary encoder A:%d B:%d, SW:%d", A, B, SW);
+	ESP_LOGI(TAG, "Created rotary encoder A:%d B:%d, SW:%d", A, B, SW);
 	
 	return true;
 }	
@@ -432,5 +432,7 @@ bool create_infrared(int gpio, infrared_handler handler) {
 	common_task_init();
 	xRingbufferAddToQueueSetRead(infrared.rb, common_queue_set);
 	
+	ESP_LOGI(TAG, "Created infrared receiver using GPIO %u", gpio);	
+	
 	return (infrared.rb != NULL);
 }	

+ 8 - 3
components/services/messaging.c

@@ -219,18 +219,23 @@ esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_m
 		}
 		return ESP_LOG_DEBUG;
 	}
+    
 void messaging_post_message(messaging_types type,messaging_classes msg_class, const char *fmt, ...){
+    va_list va;
+	va_start(va, fmt);
+    vmessaging_post_message(type, msg_class, fmt, va);
+    va_end(va);
+}
+    
+void vmessaging_post_message(messaging_types type,messaging_classes msg_class, const char *fmt, va_list va){    
 	single_message_t * message=NULL;
 	size_t msg_size=0;
 	size_t ln =0;
 	messaging_list_t * cur=&top;
-	va_list va;
-	va_start(va, fmt);
 	ln = vsnprintf(NULL, 0, fmt, va)+1;
 	msg_size = sizeof(single_message_t)+ln;
 	message = (single_message_t *)malloc_init_external(msg_size);
 	vsprintf(message->message, fmt, va);
-	va_end(va);
 	message->msg_size = msg_size;
 	message->type = type;
 	message->msg_class = msg_class;

+ 1 - 0
components/services/messaging.h

@@ -34,6 +34,7 @@ cJSON *  messaging_retrieve_messages(RingbufHandle_t buf_handle);
 messaging_handle_t messaging_register_subscriber(uint8_t max_count, char * name);
 esp_err_t messaging_post_to_queue(messaging_handle_t subscriber_handle, single_message_t * message, size_t message_size);
 void messaging_post_message(messaging_types type,messaging_classes msg_class, const char * fmt, ...);
+void vmessaging_post_message(messaging_types type,messaging_classes msg_class, const char *fmt, va_list va);
 cJSON *  messaging_retrieve_messages(RingbufHandle_t buf_handle);
 single_message_t *  messaging_retrieve_message(RingbufHandle_t buf_handle);
 void log_send_messaging(messaging_types msgtype,const char *fmt, ...);

+ 10 - 4
components/spotify/CMakeLists.txt

@@ -1,20 +1,26 @@
 # this must be set *before* idf_component_register
-set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD 20)
 
 idf_component_register(
 		SRC_DIRS . 
-		INCLUDE_DIRS . "cspot/include" "cspot/bell/include"
+		INCLUDE_DIRS . "cspot/include"
 		PRIV_REQUIRES mbedtls mdns nvs_flash platform_config services esp_http_server tools codecs
 		LDFRAGMENTS "linker.lf"
 )
 
+		#INCLUDE_DIRS . "cspot/include" "cspot/bell/include"
+
 add_definitions(-Wno-unused-variable -Wno-unused-const-variable -Wchar-subscripts -Wunused-label -Wmaybe-uninitialized -Wmisleading-indentation)
 
 set(BELL_DISABLE_CODECS ON)
 set(BELL_DISABLE_SINKS ON)
+set(BELL_DISABLE_FMT ON)
+set(BELL_DISABLE_REGEX ON)
+set(BELL_ONLY_CJSON ON)
 set(CSPOT_TARGET_ESP32 ON)
-# becase CMake is so broken, the cache set below overrides a normal "set" for the first build
-set(BELL_EXTERNAL_TREMOR "idf::codecs" CACHE STRING "provide own codecs")
+
+# because CMake is so broken, the cache set below overrides a normal "set" for the first build
+set(BELL_EXTERNAL_VORBIS "idf::codecs" CACHE STRING "provide own codecs")
 set(BELL_EXTERNAL_CJSON "idf::json" CACHE STRING "provide own CJSON")
 
 add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/cspot ${CMAKE_CURRENT_BINARY_DIR}/cspot)

+ 425 - 335
components/spotify/Shim.cpp

@@ -1,388 +1,478 @@
-/* 
+/*
  *  This software is released under the MIT License.
  *  https://opensource.org/licenses/MIT
  *
  */
 
-#include <stdio.h>
-#include <string.h>
-#include <inttypes.h>
-#include "sdkconfig.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/task.h"
-#include "esp_system.h"
-#include "esp_wifi.h"
-#include "esp_event.h"
-#include "esp_log.h"
-#include "esp_http_server.h"
-
-#include <ConstantParameters.h>
+#include <string>
+#include <streambuf>
 #include <Session.h>
-#include <SpircController.h>
-#include <MercuryManager.h>
-#include <ZeroconfAuthenticator.h>
+#include <PlainConnection.h>
+#include <memory>
+#include <vector>
+#include <iostream>
+#include <inttypes.h>
+#include <fstream>
+#include <stdarg.h>
 #include <ApResolve.h>
-#include <HTTPServer.h>
-#include "ConfigJSON.h"
+
+#include "MDNSService.h"
+#include "SpircHandler.h"
+#include "LoginBlob.h"
+#include "CentralAudioBuffer.h"
 #include "Logger.h"
+#include "Utils.h"
 
-#include "platform_config.h"
-#include "tools.h"
+#include "esp_http_server.h"
 #include "cspot_private.h"
 #include "cspot_sink.h"
-#include "Shim.h"
+#include "platform_config.h"
+#include "tools.h"
 
-extern "C" {
-	httpd_handle_t get_http_server(int *port);
-	static esp_err_t handlerWrapper(httpd_req_t *req);
-};
+static class cspotPlayer *player;
 
-#define CSPOT_STACK_SIZE (8*1024)
+/****************************************************************************************
+ * Chunk manager class (task)
+ */
 
-static const char *TAG = "cspot";
+class chunkManager : public bell::Task {
+public:
+    std::atomic<bool> isRunning = true;
+    std::atomic<bool> isPaused = true;
+    std::atomic<bool> discard = true;
+    chunkManager(std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer, std::function<void()> trackHandler,
+                 std::function<void(const uint8_t*, size_t)> dataHandler);
+    void teardown();
+
+private:
+    std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer;
+    std::function<void()> trackHandler;
+    std::function<void(const uint8_t*, size_t)> dataHandler;
+    std::mutex runningMutex;
+
+    void runTask() override;
+};
 
-// using a global is pretty ugly, but it's easier with all Lambda below
-static EXT_RAM_ATTR struct cspot_s {
-	char name[32];
-	cspot_cmd_cb_t cHandler;
-	cspot_data_cb_t dHandler;
-	TaskHandle_t TaskHandle;
-    std::shared_ptr<LoginBlob> blob;
-} cspot;
+chunkManager::chunkManager(std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer,
+                            std::function<void()> trackHandler, std::function<void(const uint8_t*, size_t)> dataHandler)
+    : bell::Task("chunker", 4 * 1024, 0, 0) {
+    this->centralAudioBuffer = centralAudioBuffer;
+    this->trackHandler = trackHandler;
+    this->dataHandler = dataHandler;
+    startTask();
+}
 
-std::shared_ptr<ConfigJSON> configMan;
-std::shared_ptr<NVSFile> file;
-std::shared_ptr<MercuryManager> mercuryManager;
-std::shared_ptr<SpircController> spircController;
+void chunkManager::teardown() {
+    isRunning = false;
+    std::scoped_lock lock(runningMutex);
+}
 
-/****************************************************************************************
- * Main task (could it be deleted after spirc has started?)
- */
-static void cspotTask(void *pvParameters) {
-	char configName[] = "cspot_config";
-	std::string jsonConfig;	
-	
-    // Config file
-    file = std::make_shared<NVSFile>();
-	configMan = std::make_shared<ConfigJSON>(configName, file);
-   
-	// We might have no config at all
-	if (!file->readFile(configName, jsonConfig) || !jsonConfig.length()) {
-		ESP_LOGW(TAG, "Cannot load config, using default");
-		
-		configMan->deviceName = cspot.name;
-		configMan->format = AudioFormat_OGG_VORBIS_160;
-		configMan->volume = 32767;
-
-		configMan->save();	
-	}
-	
-	// safely load config now
-	configMan->load();
-	if (!configMan->deviceName.length()) configMan->deviceName = cspot.name;
-	ESP_LOGI(TAG, "Started CSpot with %s (bitrate %d)", configMan->deviceName.c_str(), configMan->format == AudioFormat_OGG_VORBIS_320 ? 320 : (configMan->format == AudioFormat_OGG_VORBIS_160 ? 160 : 96));
-
-	// All we do here is notify the task to start the mercury loop
-    auto createPlayerCallback = [](std::shared_ptr<LoginBlob> blob) {
-		// TODO: handle/refuse that another user takes ownership
-		cspot.blob = blob;
-		xTaskNotifyGive(cspot.TaskHandle);
-    };
-
-	int port;
-	httpd_handle_t server = get_http_server(&port);
-	auto httpServer = std::make_shared<ShimHTTPServer>(server, port);
-
-    auto authenticator = std::make_shared<ZeroconfAuthenticator>(createPlayerCallback, httpServer);
-	authenticator->registerHandlers();
-
-	// wait to be notified and have a mercury loop
-	while (1) {
-		ulTaskNotifyTake(pdFALSE, portMAX_DELAY);
-
-        auto session = std::make_unique<Session>();
-        session->connectWithRandomAp();
-        auto token = session->authenticate(cspot.blob);
-
-        ESP_LOGI(TAG, "Creating Spotify (using CSpot) player");
-		
-        // Auth successful
-        if (token.size() > 0 && cspot.cHandler(CSPOT_SETUP, 44100)) {
-			auto audioSink = std::make_shared<ShimAudioSink>();
-
-            mercuryManager = std::make_shared<MercuryManager>(std::move(session));
-            mercuryManager->startTask();
-
-            spircController = std::make_shared<SpircController>(mercuryManager, cspot.blob->username, audioSink);
-
-			spircController->setEventHandler([](CSpotEvent &event) {
-ESP_LOGI(TAG, "Getting Spotify event %d ", (int) event.eventType);				
-            switch (event.eventType) {
-            case CSpotEventType::TRACK_INFO: {
-                TrackInfo track = std::get<TrackInfo>(event.data);
-				cspot.cHandler(CSPOT_TRACK, 44100, track.duration, track.artist.c_str(), 
-							   track.album.c_str(), track.name.c_str(), track.imageUrl.c_str());
-                break;
-            }
-            case CSpotEventType::PLAY_PAUSE: {
-                bool isPaused = std::get<bool>(event.data);
-				if (isPaused) cspot.cHandler(CSPOT_PAUSE);
-				else cspot.cHandler(CSPOT_PLAY, false);
-                break;
-            }
-			case CSpotEventType::PLAYBACK_START:
-				cspot.cHandler(CSPOT_PLAY, (int) std::get<bool>(event.data));
-				break;
-			case CSpotEventType::LOAD:
-				cspot.cHandler(CSPOT_LOAD, std::get<int>(event.data), -1);
-				break;
-			case CSpotEventType::SEEK:
-				cspot.cHandler(CSPOT_SEEK, std::get<int>(event.data));
-				break;
-			case CSpotEventType::DISC:
-				cspot.cHandler(CSPOT_DISC);				
-				spircController->stopPlayer();
-				mercuryManager->stop();
-				break;
-			case CSpotEventType::PREV:
-			case CSpotEventType::NEXT:
-				cspot.cHandler(CSPOT_FLUSH);
-                break;
-			/*
-			// we use volume from sink which is a 16 bits value
-			case CSpotEventType::VOLUME: {
-                int volume = std::get<int>(event.data);
-				cspot.cHandler(CSPOT_VOLUME, volume);
-				ESP_LOGW(TAG, "cspot volume : %d", volume);
-                break;
-            }
-			*/
-            default:
-                break;
-            }
-			});
+void chunkManager::runTask() {
+    std::scoped_lock lock(runningMutex);
+    size_t lastHash = 0;
 
-            mercuryManager->reconnectedCallback = []() {
-                return spircController->subscribe();
-            };
+    while (isRunning) {
 
-            mercuryManager->handleQueue();
-        
-			// release controllers
-			mercuryManager.reset();
-			spircController.reset();
-		}
+        if (isPaused) {
+            BELL_SLEEP_MS(100);
+            continue;
+        }
 
-		// release auth blob and flush files
-		cspot.blob.reset();
-		file->flush();
+        auto chunk = centralAudioBuffer->readChunk();
 
-		ESP_LOGI(TAG, "Shutting down CSpot player");
-	}
+        if (!chunk || chunk->pcmSize == 0) {
+            BELL_SLEEP_MS(50);
+            continue;
+        }
 
-	// we should not be here
-	vTaskDelete(NULL);
+        // receiving first chunk of new track from Spotify server
+        if (lastHash != chunk->trackHash) {
+            CSPOT_LOG(info, "hash update %x => %x", lastHash, chunk->trackHash);
+            lastHash = chunk->trackHash;
+            discard = false;
+            trackHandler();
+        }
+
+        if (!discard) dataHandler(chunk->pcmData, chunk->pcmSize);
+    }
 }
 
 /****************************************************************************************
- * API to create and start a cspot instance
+ * Player's main class  & task
  */
-struct cspot_s* cspot_create(const char *name, cspot_cmd_cb_t cmd_cb, cspot_data_cb_t data_cb) {
-	static DRAM_ATTR StaticTask_t xTaskBuffer __attribute__ ((aligned (4)));
-	static EXT_RAM_ATTR StackType_t xStack[CSPOT_STACK_SIZE] __attribute__ ((aligned (4)));
 
-	bell::setDefaultLogger();
-	
-	cspot.cHandler = cmd_cb;
-	cspot.dHandler = data_cb;
-	strncpy(cspot.name, name, sizeof(cspot.name) - 1);
-    cspot.TaskHandle = xTaskCreateStatic(&cspotTask, "cspot", CSPOT_STACK_SIZE, NULL, CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT - 2, xStack, &xTaskBuffer);
-	
-	return &cspot;
-}
+class cspotPlayer : public bell::Task {
+private:
+    std::string name;
+    bell::WrappedSemaphore clientConnected;
+    std::shared_ptr<bell::CentralAudioBuffer> centralAudioBuffer;
 
-/****************************************************************************************
- * Commands sent by local buttons/actions
- */
-bool cspot_cmd(struct cspot_s* ctx, cspot_event_t event, void *param) {
-	// we might have not controller left
-	if (!spircController.use_count()) return false;
-
-	switch(event) {
-		case CSPOT_PREV:
-			spircController->prevSong();
-			break;
-		case CSPOT_NEXT:
-			spircController->nextSong();
-			break;
-		case CSPOT_TOGGLE:
-			spircController->playToggle();
-			break;
-		case CSPOT_PAUSE:
-			spircController->setPause(true);
-			break;
-		case CSPOT_PLAY:
-			spircController->setPause(false);
-			break;
-		case CSPOT_DISC:
-			spircController->disconnect();
-			break;
-		case CSPOT_STOP:
-			spircController->stopPlayer();
-			break;
-		case CSPOT_VOLUME_UP:
-			spircController->adjustVolume(MAX_VOLUME / 100 + 1);
-			break;
-		case CSPOT_VOLUME_DOWN:
-			spircController->adjustVolume(-(MAX_VOLUME / 100 + 1));
-			break;
-		default:
-			break;
-	}
+    int startOffset, volume = 0, bitrate = 160;
+    httpd_handle_t serverHandle;
+    int serverPort;
+    cspot_cmd_cb_t cmdHandler;
+    cspot_data_cb_t dataHandler;
 
-	return true;
+    std::shared_ptr<cspot::LoginBlob> blob;
+    std::unique_ptr<cspot::SpircHandler> spirc;
+    std::unique_ptr<chunkManager> chunker;
+
+    void eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event);
+    void trackHandler(void);
+
+    void runTask();
+
+public:
+    typedef enum {TRACK_INIT, TRACK_NOTIFY, TRACK_STREAM, TRACK_END} TrackStatus;
+    std::atomic<TrackStatus> trackStatus = TRACK_INIT;
+
+    cspotPlayer(const char*, httpd_handle_t, int, cspot_cmd_cb_t, cspot_data_cb_t);
+    esp_err_t handleGET(httpd_req_t *request);
+    esp_err_t handlePOST(httpd_req_t *request);
+    void command(cspot_event_t event);
+};
+
+cspotPlayer::cspotPlayer(const char* name, httpd_handle_t server, int port, cspot_cmd_cb_t cmdHandler, cspot_data_cb_t dataHandler) :
+                        bell::Task("playerInstance", 32 * 1024, 0, 0),
+                        serverHandle(server), serverPort(port),
+                        cmdHandler(cmdHandler), dataHandler(dataHandler) {
+
+    cJSON *item, *config = config_alloc_get_cjson("cspot_config");
+    if ((item = cJSON_GetObjectItem(config, "volume")) != NULL) volume = item->valueint;
+    if ((item = cJSON_GetObjectItem(config, "bitrate")) != NULL) bitrate = item->valueint;
+    if ((item = cJSON_GetObjectItem(config, "deviceName") ) != NULL) this->name = item->valuestring;
+    else this->name = name;
+    cJSON_Delete(config);
+
+    if (bitrate != 96 && bitrate != 160 && bitrate != 320) bitrate = 160;
 }
 
-/****************************************************************************************
- * AudioSink class to push data to squeezelite backend (decode_external)
- */
-void ShimAudioSink::volumeChanged(uint16_t volume) {
-	cspot.cHandler(CSPOT_VOLUME, volume);
+extern "C" {
+    static esp_err_t handleGET(httpd_req_t *request) {
+        return player->handleGET(request);
+    }
+
+    static esp_err_t handlePOST(httpd_req_t *request) {
+        return player->handlePOST(request);
+    }
 }
 
-void ShimAudioSink::feedPCMFrames(const uint8_t *data, size_t bytes) {	
-	cspot.dHandler(data, bytes);
+esp_err_t cspotPlayer::handleGET(httpd_req_t *request) {
+    std::string body = this->blob->buildZeroconfInfo();
+
+    if (body.size() == 0) {
+        CSPOT_LOG(info, "cspot empty blob's body on GET");
+        return ESP_ERR_HTTPD_INVALID_REQ;
+    }
+
+    httpd_resp_set_hdr(request, "Content-type", "application/json");
+    httpd_resp_send(request, body.c_str(), body.size());
+
+    return ESP_OK;
 }
 
-/****************************************************************************************
- * NVSFile class to store config
- */
-bool NVSFile::readFile(std::string filename, std::string &fileContent) {
-	auto search = files.find(filename);
+esp_err_t cspotPlayer::handlePOST(httpd_req_t *request) {
+    cJSON* response= cJSON_CreateObject(); 
+    //see https://developer.spotify.com/documentation/commercial-hardware/implementation/guides/zeroconf
+
+    if (cmdHandler(CSPOT_BUSY)) {
+        cJSON_AddNumberToObject(response, "status", 101);
+        cJSON_AddStringToObject(response, "statusString", "OK");
+        cJSON_AddNumberToObject(response, "spotifyError", 0);
+
+        // get body if any (add '\0' at the end if used as string)
+        if (request->content_len) {
+            char* body = (char*) calloc(1, request->content_len + 1);
+            int size = httpd_req_recv(request, body, request->content_len);
+
+            // I know this is very crude and unsafe...
+            url_decode(body);
+            char *key = strtok(body, "&");
+
+            std::map<std::string, std::string> queryMap;
+
+            while (key) {
+                char *value = strchr(key, '=');
+                *value++ = '\0';
+                queryMap[key] = value;
+                key = strtok(NULL, "&");
+            };
+
+            free(body);
+
+            // Pass user's credentials to the blob and give the token
+            blob->loadZeroconfQuery(queryMap);
+            clientConnected.give();
+        }
+    } else {
+        cJSON_AddNumberToObject(response, "status", 202);
+        cJSON_AddStringToObject(response, "statusString", "ERROR-LOGIN-FAILED");
+        cJSON_AddNumberToObject(response, "spotifyError", 0);
+        
+        CSPOT_LOG(info, "sink is busy, can't accept request");
+    }
+
+    char *responseStr = cJSON_PrintUnformatted(response);
+    cJSON_Delete(response);
     
-	// cache 
-	if (search == files.end()) {
-		char *content = (char*) config_alloc_get(NVS_TYPE_STR, filename.c_str());
-		if (!content) return false;
-		fileContent = content;
-		free(content);
-	} else {
-		fileContent = search->second;
-	}
+    httpd_resp_set_hdr(request, "Content-type", "application/json");
+    esp_err_t rc = httpd_resp_send(request, responseStr, strlen(responseStr));
+    free(responseStr);
 
-	return true;
+    return rc;
 }
 
-bool NVSFile::writeFile(std::string filename, std::string fileContent) {
-    auto search = files.find(filename);
-
-	files[filename] = fileContent;    
-	if (search == files.end()) return (ESP_OK == config_set_value(NVS_TYPE_STR, filename.c_str(), fileContent.c_str()));
-	return true;
+void cspotPlayer::eventHandler(std::unique_ptr<cspot::SpircHandler::Event> event) {
+    switch (event->eventType) {
+    case cspot::SpircHandler::EventType::PLAYBACK_START: {
+        chunker->discard = true;
+        centralAudioBuffer->clearBuffer();
+
+        // we are not playing anymore
+        trackStatus = TRACK_INIT;
+        // memorize position for when track's beginning will be detected
+        startOffset = std::get<int>(event->data);
+        // Spotify servers do not send volume at connection
+        spirc->setRemoteVolume(volume);
+
+        cmdHandler(CSPOT_START, 44100);
+        CSPOT_LOG(info, "(re)start playing");
+        break;
+    }
+    case cspot::SpircHandler::EventType::PLAY_PAUSE: {
+        bool pause = std::get<bool>(event->data);
+        cmdHandler(pause ? CSPOT_PAUSE : CSPOT_PLAY);
+        chunker->isPaused = pause;
+        break;
+    }
+    case cspot::SpircHandler::EventType::TRACK_INFO: {
+        auto trackInfo = std::get<cspot::CDNTrackStream::TrackInfo>(event->data);
+        cmdHandler(CSPOT_TRACK_INFO, trackInfo.duration, startOffset, trackInfo.artist.c_str(),
+                       trackInfo.album.c_str(), trackInfo.name.c_str(), trackInfo.imageUrl.c_str());
+        spirc->updatePositionMs(startOffset);
+        startOffset = 0;
+        break;
+    }
+    case cspot::SpircHandler::EventType::NEXT:
+    case cspot::SpircHandler::EventType::PREV:
+    case cspot::SpircHandler::EventType::FLUSH: {
+        // FLUSH is sent when there is no next, just clean everything
+        centralAudioBuffer->clearBuffer();
+        cmdHandler(CSPOT_FLUSH);
+        break;
+    }
+    case cspot::SpircHandler::EventType::DISC:
+        centralAudioBuffer->clearBuffer();
+        cmdHandler(CSPOT_DISC);
+        chunker->teardown();
+        break;
+    case cspot::SpircHandler::EventType::SEEK: {
+        centralAudioBuffer->clearBuffer();
+        cmdHandler(CSPOT_SEEK, std::get<int>(event->data));
+        break;
+    }
+    case cspot::SpircHandler::EventType::DEPLETED:
+        trackStatus = TRACK_END;
+        CSPOT_LOG(info, "playlist ended, no track left to play");
+        break;
+    case cspot::SpircHandler::EventType::VOLUME:
+        volume = std::get<int>(event->data);
+        cmdHandler(CSPOT_VOLUME, volume);
+        break;
+    default:
+        break;
+    }
 }
 
-bool NVSFile::flush() {
-	esp_err_t err = ESP_OK;
+void cspotPlayer::trackHandler(void) {
+    // this is just informative
+    auto trackInfo = spirc->getTrackPlayer()->getCurrentTrackInfo();
+    uint32_t remains;
+    cmdHandler(CSPOT_QUERY_REMAINING, &remains);
+    CSPOT_LOG(info, "next track <%s> will play in %d ms", trackInfo.name.c_str(), remains);
 
-	for (auto it = files.begin(); it != files.end(); ++it) {
-		err |= config_set_value(NVS_TYPE_STR, it->first.c_str(), it->second.c_str());
-	}
-	return (err == ESP_OK);
+    // inform sink of track beginning
+    trackStatus = TRACK_NOTIFY;
+    cmdHandler(CSPOT_TRACK_MARK);
 }
 
-/****************************************************************************************
- * Shim HTTP server for spirc
- */
-static esp_err_t handlerWrapper(httpd_req_t *req) {
-	std::unique_ptr<bell::HTTPRequest> request = std::make_unique<bell::HTTPRequest>();
-	char *query = NULL, *body = NULL;
-	bell::httpHandler *handler = (bell::httpHandler*) req->user_ctx;
-	size_t query_len = httpd_req_get_url_query_len(req);
-
-	request->connection = httpd_req_to_sockfd(req);
-
-	// get body if any (add '\0' at the end if used as string)
-	if (req->content_len) {
-		body = (char*) calloc(1, req->content_len + 1);
-		int size = httpd_req_recv(req, body, req->content_len);
-		request->body = body;
-		ESP_LOGD(TAG,"wrapper received body %d/%d", size, req->content_len);
+void cspotPlayer::command(cspot_event_t event) {
+    if (!spirc) return;
+
+    // switch...case consume a ton of extra .rodata
+    switch (event) {
+    // nextSong/previousSong come back through cspot::event as a FLUSH
+    case CSPOT_PREV:
+        spirc->previousSong();
+        break;
+    case CSPOT_NEXT:
+        spirc->nextSong();
+        break;
+    // setPause comes back through cspot::event with PLAY/PAUSE
+    case CSPOT_TOGGLE:
+        spirc->setPause(!chunker->isPaused);
+        break;
+    case CSPOT_STOP:
+    case CSPOT_PAUSE:
+        spirc->setPause(true);
+        break;
+    case CSPOT_PLAY:
+        spirc->setPause(false);
+        break;
+    // calling spirc->disconnect() might have been logical but it does not
+    // generate any cspot::event, so we need to manually force exiting player
+    // loop through chunker which will eventually do the disconnect
+    case CSPOT_DISC:
+        cmdHandler(CSPOT_DISC);
+        chunker->teardown();
+        break;
+    // spirc->setRemoteVolume does not generate a cspot::event so call cmdHandler
+    case CSPOT_VOLUME_UP:
+        volume += (UINT16_MAX / 50);
+        volume = std::min(volume, UINT16_MAX);
+        cmdHandler(CSPOT_VOLUME, volume);
+        spirc->setRemoteVolume(volume);
+        break;
+    case CSPOT_VOLUME_DOWN:
+        volume -= (UINT16_MAX / 50);
+        volume = std::max(volume, 0);
+        cmdHandler(CSPOT_VOLUME, volume);
+        spirc->setRemoteVolume(volume);
+        break;
+    default:
+        break;
 	}
-
-	// parse query if any (can be in body as well for url-encoded)
-	if (query_len) {
-		query = (char*) malloc(query_len + 1);
-		httpd_req_get_url_query_str(req, query, query_len + 1);
-	} else if (body && strchr(body, '&')) {
-		query = body;
-		body = NULL;
-	}	
-		
-	// I know this is very crude and unsafe...
-	url_decode(query);
-	char *key = strtok(query, "&");
-
-	while (key) {
-		char *value = strchr(key, '=');
-		*value++ = '\0';
-		request->queryParams[key] = value;
-		ESP_LOGD(TAG,"wrapper received key:%s value:%s", key, value);
-		key = strtok(NULL, "&");
-	};
-
-	if (query) free(query);
-	if (body) free(body);
-	
-	/*
-	 This is a strange construct as the C++ handler will call the ShimHTTPSer::respond 
-	 and then we'll return. So we can't obtain the response to be sent, as esp_http_server
-	 normally expects, instead respond() will use raw socket and close connection
-	*/
-	(*handler)(std::move(request));
-
-	return ESP_OK;
 }
 
-void ShimHTTPServer::registerHandler(bell::RequestType requestType, const std::string &routeUrl, bell::httpHandler handler, bool readDataToStr) {
-	httpd_uri_t request = { 
-		.uri = routeUrl.c_str(), 
-		.method = (requestType == bell::RequestType::GET ? HTTP_GET : HTTP_POST),
-		.handler = handlerWrapper,
+void cspotPlayer::runTask() {
+    httpd_uri_t request = {
+		.uri = "/spotify_info",
+		.method = HTTP_GET,
+		.handler = ::handleGET,
 		.user_ctx = NULL,
 	};
 
-	// find the first free spot and register handler
-	for (int i = 0; i < sizeof(uriHandlers)/sizeof(bell::httpHandler); i++) {
-		if (!uriHandlers[i]) {
-			uriHandlers[i] = handler;
-			request.user_ctx = uriHandlers + i;
-			httpd_register_uri_handler(serverHandle, &request);
-			break;	
-		}
-	}
-		
-	if (!request.user_ctx) ESP_LOGW(TAG, "Cannot add handler for %s", routeUrl.c_str());
+    // register GET and POST handler for built-in server
+    httpd_register_uri_handler(serverHandle, &request);
+    request.method = HTTP_POST;
+    request.handler = ::handlePOST;
+    httpd_register_uri_handler(serverHandle, &request);
+
+    // construct blob for that player
+    blob = std::make_unique<cspot::LoginBlob>(name);
+
+    // Register mdns service, for spotify to find us
+    bell::MDNSService::registerService( blob->getDeviceName(), "_spotify-connect", "_tcp", "", serverPort,
+            { {"VERSION", "1.0"}, {"CPath", "/spotify_info"}, {"Stack", "SP"} });
+
+                                static int count = 0;
+    // gone with the wind...
+    while (1) {
+        clientConnected.wait();
+
+        CSPOT_LOG(info, "Spotify client connected for %s", name.c_str());
+
+        centralAudioBuffer = std::make_shared<bell::CentralAudioBuffer>(32);
+        auto ctx = cspot::Context::createFromBlob(blob);
+
+        if (bitrate == 320) ctx->config.audioFormat = AudioFormat_OGG_VORBIS_320;
+        else if (bitrate == 96) ctx->config.audioFormat = AudioFormat_OGG_VORBIS_96;
+        else ctx->config.audioFormat = AudioFormat_OGG_VORBIS_160;
+
+        ctx->session->connectWithRandomAp();
+        auto token = ctx->session->authenticate(blob);
+
+        // Auth successful
+        if (token.size() > 0) {
+            spirc = std::make_unique<cspot::SpircHandler>(ctx);
+
+            // set call back to calculate a hash on trackId
+            spirc->getTrackPlayer()->setDataCallback(
+                [this](uint8_t* data, size_t bytes, std::string_view trackId, size_t sequence) {
+                    return centralAudioBuffer->writePCM(data, bytes, sequence);
+            });
+
+            // set event (PLAY, VOLUME...) handler
+            spirc->setEventHandler(
+                [this](std::unique_ptr<cspot::SpircHandler::Event> event) {
+                    eventHandler(std::move(event));
+            });
+
+            // Start handling mercury messages
+            ctx->session->startTask();
+
+            // Create a player, pass the tack handler
+            chunker = std::make_unique<chunkManager>(centralAudioBuffer,
+                [this](void) {
+                    return trackHandler();
+                },
+                [this](const uint8_t* data, size_t bytes) {
+                    return dataHandler(data, bytes);
+            });
+
+            // set volume at connection
+            cmdHandler(CSPOT_VOLUME, volume);
+
+            // exit when player has stopped (received a DISC)
+            while (chunker->isRunning) {
+                ctx->session->handlePacket();
+
+                // low-accuracy polling events
+                if (trackStatus == TRACK_NOTIFY) {
+                    // inform Spotify that next track has started (don't need to be super accurate)
+                    uint32_t started;
+                    cmdHandler(CSPOT_QUERY_STARTED, &started);
+                    if (started) {
+                        CSPOT_LOG(info, "next track's audio has reached DAC");
+                        spirc->notifyAudioReachedPlayback();
+                        trackStatus = TRACK_STREAM;
+                    }
+                } else if (trackStatus == TRACK_END) {
+                    // wait for end of last track
+                    uint32_t remains;
+                    cmdHandler(CSPOT_QUERY_REMAINING, &remains);
+                    if (!remains) {
+                        CSPOT_LOG(info, "last track finished");
+                        trackStatus = TRACK_INIT;
+                        cmdHandler(CSPOT_STOP);
+                        spirc->setPause(true);
+                    }
+                }
+            }
+
+            spirc->disconnect();
+            spirc.reset();
+
+            CSPOT_LOG(info, "disconnecting player %s", name.c_str());
+        }
+
+        // we want to release memory ASAP and for sure
+        centralAudioBuffer.reset();
+        ctx.reset();
+        token.clear();
+        
+        // update volume when we disconnect
+        cJSON *config = config_alloc_get_cjson("cspot_config");
+        cJSON_DeleteItemFromObject(config, "volume");
+        cJSON_AddNumberToObject(config, "volume", volume);
+        config_set_cjson_str_and_free("cspot_config", config);
+    }
+}
+
+/****************************************************************************************
+ * API to create and start a cspot instance
+ */
+struct cspot_s* cspot_create(const char *name, httpd_handle_t server, int port, cspot_cmd_cb_t cmd_cb, cspot_data_cb_t data_cb) {
+	bell::setDefaultLogger();
+    player = new cspotPlayer(name, server, port, cmd_cb, data_cb);
+    player->startTask();
+	return (cspot_s*) player;
 }
 
-void ShimHTTPServer::respond(const bell::HTTPResponse &response) {
-	char *buf;
-	size_t len = asprintf(&buf, "HTTP/1.1 %d OK\r\n"
-			"Server: SQUEEZEESP32\r\n"
-			"Connection: close\r\n"		
-			"Content-type: %s\r\n"		
-			"Content-length: %d\r\n"	
-			"Access-Control-Allow-Origin: *\r\n"
-			"Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS\r\n"
-			"Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token\r\n"
-			"\r\n%s", 
-			response.status, response.contentType.c_str(), 
-			response.body.size(), response.body.c_str()
-	);
-
-	// use raw socket send and close connection
-	httpd_socket_send(serverHandle, response.connectionFd, buf, len, 0);
-	free(buf);
-	
-	// we want to close the socket due to the strange construct
-	httpd_sess_trigger_close(serverHandle, response.connectionFd);
+/****************************************************************************************
+ * Commands sent by local buttons/actions
+ */
+bool cspot_cmd(struct cspot_s* ctx, cspot_event_t event, void *param) {
+    player->command(event);
+	return true;
 }

+ 0 - 49
components/spotify/Shim.h

@@ -1,49 +0,0 @@
-/* 
- *  This software is released under the MIT License.
- *  https://opensource.org/licenses/MIT
- *
- */
-
-#pragma once
-
-#include <vector>
-#include <iostream>
-#include <map>
-#include "AudioSink.h"
-#include "FileHelper.h"
-#include "BaseHTTPServer.h"
-#include <stdio.h>
-#include <string.h>
-#include <sys/unistd.h>
-#include <sys/stat.h>
-#include "esp_err.h"
-#include "esp_http_server.h"
-#include "esp_log.h"
-
-class ShimAudioSink : public AudioSink {
-public:
-	ShimAudioSink(void) { softwareVolumeControl = false; }
-    void feedPCMFrames(const uint8_t *data, size_t bytes);
-	virtual void volumeChanged(uint16_t volume);
-};
-
-class NVSFile : public FileHelper {
-private:
-	std::map<std::string, std::string> files;
-
-public:
-    bool readFile(std::string filename, std::string &fileContent);
-    bool writeFile(std::string filename, std::string fileContent);
-	bool flush();
-};
-
-class ShimHTTPServer : public bell::BaseHTTPServer {    
-private:
-	httpd_handle_t serverHandle;
-	bell::httpHandler uriHandlers[4];
-	
-public:
-   ShimHTTPServer(httpd_handle_t server, int port) { serverHandle = server; serverPort = port; }
-   void registerHandler(bell::RequestType requestType, const std::string &, bell::httpHandler, bool readDataToStr = false);
-   void respond(const bell::HTTPResponse &);
-};

+ 0 - 17
components/spotify/cspot/CMakeLists.txt

@@ -16,11 +16,6 @@ endif()
 # Main library sources
 file(GLOB SOURCES "src/*.cpp" "src/*.c")
 
-if(WIN32)
-    list(APPEND SOURCES "mdnssvc/mdns.c" "mdnssvc/mdnsd.c")
-    list(APPEND EXTRA_INCLUDES "mdnssvc")
-endif()	
-
 # Use externally specified bell library or the submodule
 if(CSPOT_EXTERNAL_BELL)
     list(APPEND EXTRA_LIBS ${CSPOT_EXTERNAL_BELL})
@@ -29,24 +24,12 @@ else()
     list(APPEND EXTRA_LIBS bell)
 endif()
 
-# Add Apple Bonjour compatibility library for Linux
-if(UNIX AND NOT APPLE)
-    list(APPEND EXTRA_LIBS dns_sd)
-    # TODO: migrate from this to native linux mDNS
-endif()
-
 # Build protobuf code
-if(0)
 set(NANOPB_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}")
 file(GLOB PROTOS protobuf/*.proto)
 nanopb_generate_cpp(PROTO_SRCS PROTO_HDRS RELPATH ${CMAKE_CURRENT_SOURCE_DIR} ${PROTOS})
 add_custom_target(generate_proto_sources DEPENDS ${PROTO_SRCS} ${PROTO_HDRS})
 set_source_files_properties(${PROTO_SRCS} ${PROTO_HDRS} PROPERTIES GENERATED TRUE)
-else()
-list(APPEND SOURCES "protobuf/authentication.pb.c" "protobuf/keyexchange.pb.c" "protobuf/mercury.pb.c" "protobuf/metadata.pb.c" "protobuf/spirc.pb.c")
-list(APPEND EXTRA_INCLUDES ".")
-message(WARNING "NOT GENERATING PROTOBUF")
-endif()
 
 add_library(cspot STATIC ${SOURCES} ${PROTO_SRCS})
 # PUBLIC to propagate includes from bell to cspot dependents

+ 3 - 0
components/spotify/cspot/README.md

@@ -0,0 +1,3 @@
+# Base CSpot library
+
+CSpot Spotify-Connect receiver library further integrated in ../targets/

+ 2 - 0
components/spotify/cspot/bell/.clangd

@@ -0,0 +1,2 @@
+CompileFlags:
+   CompilationDatabase: example/build      # Search build/ directory for compile_commands.json

+ 52 - 0
components/spotify/cspot/bell/.github/workflows/c-cpp.yml

@@ -0,0 +1,52 @@
+name: C/C++ CI
+
+on: [push, pull_request]
+
+jobs:
+  build:
+    strategy:
+        matrix:
+          os: [macos-latest, ubuntu-latest]
+        fail-fast: false
+    runs-on:  ${{ matrix.os }}
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        submodules: recursive
+        
+    - name: Install Protoc
+      uses: arduino/setup-protoc@v1
+      with:
+        repo-token: ${{ secrets.GITHUB_TOKEN }} # https://github.com/arduino/setup-protoc/issues/6
+        
+    - name: Setup cmake
+      uses: jwlawson/actions-setup-cmake@v1.4
+      with:
+        cmake-version: '3.18.x'
+
+    - name: Install avachi libraries (mDNS), mbedtls and asound
+      run: sudo apt-get install libavahi-compat-libdnssd-dev libasound2-dev libmbedtls-dev
+      if: ${{ matrix.os == 'ubuntu-latest' }}
+      
+    - name: Install openssl on macos
+      run: |
+        brew install mbedtls@3
+        brew link --force mbedtls@3
+        brew install portaudio
+        brew link --force portaudio
+        export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/Cellar/portaudio/19.6.0/lib/pkgconfig"
+        pkg-config --modversion portaudio-2.0
+        echo "PKG_CONFIG_PATH=$PKG_CONFIG_PATH" >> $GITHUB_ENV
+      if: ${{ matrix.os == 'macos-latest' }}
+      
+    - name: Install python dependencies
+      run: python3 -m pip install --upgrade pip setuptools wheel
+      
+    - name: Install grpcio-tools
+      run: sudo pip3 install grpcio-tools
+      
+    - name: cmake
+      run: mkdir -p build && cd build && cmake ..
+      
+    - name: make
+      run: cd build && make

+ 2 - 1
components/spotify/cspot/bell/.gitignore

@@ -22,7 +22,6 @@
 *.pch
 
 # Libraries
-*.lib
 *.a
 *.la
 *.lo
@@ -124,3 +123,5 @@ Temporary Items
 # End of https://www.toptal.com/developers/gitignore/api/c,c++,cmake,macos
 
 build/
+__history/
+*.bak

+ 9 - 10
components/spotify/cspot/bell/.gitmodules

@@ -1,10 +1,9 @@
-[submodule "tremor"]
-	path = tremor
-	url = https://gitlab.xiph.org/xiph/tremor.git
-	branch = lowmem
-[submodule "cJSON"]
-	path = cJSON
-	url = https://github.com/DaveGamble/cJSON
-[submodule "nanopb"]
-	path = nanopb
-	url = https://github.com/nanopb/nanopb
+[submodule "external/lws"]
+	path = external/lws
+	url = https://github.com/warmcat/libwebsockets
+[submodule "external/nlohmann_json"]
+	path = external/nlohmann_json
+	url = https://github.com/nlohmann/json
+[submodule "external/mdnssvc"]
+	path = external/mdnssvc
+	url = https://github.com/philippe44/mdnssvc

+ 65 - 0
components/spotify/cspot/bell/.vscode/settings.json

@@ -0,0 +1,65 @@
+{
+    "files.associations": {
+        "array": "cpp",
+        "atomic": "cpp",
+        "bit": "cpp",
+        "*.tcc": "cpp",
+        "bitset": "cpp",
+        "cctype": "cpp",
+        "chrono": "cpp",
+        "clocale": "cpp",
+        "cmath": "cpp",
+        "compare": "cpp",
+        "concepts": "cpp",
+        "condition_variable": "cpp",
+        "cstdarg": "cpp",
+        "cstddef": "cpp",
+        "cstdint": "cpp",
+        "cstdio": "cpp",
+        "cstdlib": "cpp",
+        "cstring": "cpp",
+        "ctime": "cpp",
+        "cwchar": "cpp",
+        "cwctype": "cpp",
+        "deque": "cpp",
+        "map": "cpp",
+        "set": "cpp",
+        "string": "cpp",
+        "unordered_map": "cpp",
+        "vector": "cpp",
+        "exception": "cpp",
+        "algorithm": "cpp",
+        "functional": "cpp",
+        "iterator": "cpp",
+        "memory": "cpp",
+        "memory_resource": "cpp",
+        "numeric": "cpp",
+        "optional": "cpp",
+        "random": "cpp",
+        "ratio": "cpp",
+        "regex": "cpp",
+        "string_view": "cpp",
+        "system_error": "cpp",
+        "tuple": "cpp",
+        "type_traits": "cpp",
+        "utility": "cpp",
+        "fstream": "cpp",
+        "initializer_list": "cpp",
+        "iosfwd": "cpp",
+        "iostream": "cpp",
+        "istream": "cpp",
+        "limits": "cpp",
+        "mutex": "cpp",
+        "new": "cpp",
+        "numbers": "cpp",
+        "ostream": "cpp",
+        "semaphore": "cpp",
+        "sstream": "cpp",
+        "stdexcept": "cpp",
+        "stop_token": "cpp",
+        "streambuf": "cpp",
+        "thread": "cpp",
+        "typeinfo": "cpp",
+        "cinttypes": "cpp"
+    }
+}

+ 181 - 107
components/spotify/cspot/bell/CMakeLists.txt

@@ -11,23 +11,32 @@ option(BELL_CODEC_VORBIS "Support tremor Vorbis codec" ON)
 option(BELL_CODEC_ALAC "Support Apple ALAC codec" ON)
 option(BELL_CODEC_OPUS "Support Opus codec" ON)
 option(BELL_DISABLE_SINKS "Disable all built-in audio sink implementations" OFF)
+
 # These are default OFF, as they're OS-dependent (ESP32 sinks are always enabled - no external deps)
 option(BELL_SINK_ALSA "Enable ALSA audio sink" OFF)
 option(BELL_SINK_PORTAUDIO "Enable PortAudio sink" OFF)
+
 # cJSON wrapper
-option(BELL_DISABLE_CJSON "Disable cJSON and JSONObject completely" OFF)
+option(BELL_ONLY_CJSON "Use only cJSON, not Nlohmann")
 set(BELL_EXTERNAL_CJSON "" CACHE STRING "External cJSON library target name, optional")
 
-if(BELL_EXTERNAL_MBEDTLS)
-    set(MbedTLS_DIR ${BELL_EXTERNAL_MBEDTLS})
-    message(STATUS "Setting local mbedtls ${MbedTLS_DIR}")
-endif()
+# vorbis
+set(BELL_EXTERNAL_VORBIS "" CACHE STRING "External Vorbis library target name, optional")
+option(BELL_VORBIS_FLOAT "Use floating point Vorbis API" OFF)
+
+# fmt & regex
+option(BELL_DISABLE_FMT "Don't use std::fmt (saves space)" OFF)
+option(BELL_DISABLE_REGEX "Don't use std::regex (saves space)" OFF)
+
+# disable json tests
+set(JSON_BuildTests OFF CACHE INTERNAL "")
 
 # Backwards compatibility with deprecated options
 if(BELL_USE_ALSA)
     message(WARNING "Deprecated Bell options used, replace BELL_USE_ALSA with BELL_SINK_ALSA")
     set(BELL_SINK_ALSA ${BELL_USE_ALSA})
 endif()
+
 if(BELL_USE_PORTAUDIO)
     message(WARNING "Deprecated Bell options used, replace BELL_USE_PORTAUDIO with BELL_SINK_PORTAUDIO")
     set(BELL_SINK_PORTAUDIO ${BELL_USE_PORTAUDIO})
@@ -35,6 +44,7 @@ endif()
 
 message(STATUS "Bell options:")
 message(STATUS "    Disable all codecs: ${BELL_DISABLE_CODECS}")
+
 if(NOT BELL_DISABLE_CODECS)
     message(STATUS "    - AAC audio codec: ${BELL_CODEC_AAC}")
     message(STATUS "    - MP3 audio codec: ${BELL_CODEC_MP3}")
@@ -42,51 +52,77 @@ if(NOT BELL_DISABLE_CODECS)
     message(STATUS "    - Opus audio codec: ${BELL_CODEC_OPUS}")
     message(STATUS "    - ALAC audio codec: ${BELL_CODEC_ALAC}")
 endif()
+
 message(STATUS "    Disable built-in audio sinks: ${BELL_DISABLE_SINKS}")
+message(STATUS "    Use Vorbis float version: ${BELL_VORBIS_FLOAT}")
+
 if(NOT BELL_DISABLE_SINKS)
     message(STATUS "    - ALSA sink: ${BELL_SINK_ALSA}")
     message(STATUS "    - PortAudio sink: ${BELL_SINK_PORTAUDIO}")
 endif()
-message(STATUS "    Disable cJSON and JSONObject: ${BELL_DISABLE_CJSON}")
+
+message(STATUS "    Use cJSON only: ${BELL_ONLY_CJSON}")
+message(STATUS "    Disable Fmt: ${BELL_DISABLE_FMT}")
+message(STATUS "    Disable Regex: ${BELL_DISABLE_REGEX}")
 
 # Include nanoPB library
-set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/nanopb/extra")
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/external/nanopb/extra")
 find_package(Nanopb REQUIRED)
+message(${NANOPB_INCLUDE_DIRS})
 list(APPEND EXTRA_INCLUDES ${NANOPB_INCLUDE_DIRS})
 
 # CMake options
 set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_CXX_STANDARD_REQUIRED 20)
 set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
-set(AUDIO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/audio")
+
+set(AUDIO_CODEC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/audio-codec")
+set(AUDIO_CONTAINERS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/audio-containers")
+set(AUDIO_DSP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/audio-dsp")
+set(AUDIO_SINKS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/audio-sinks")
+set(IO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/io")
+set(PLATFORM_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/platform")
+set(UTILITIES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/main/utilities")
+
 add_definitions("-DUSE_DEFAULT_STDLIB=1")
 
 # Main library sources
-file(GLOB SOURCES "src/*.cpp" "src/*.c" "nanopb/*.c")
-list(APPEND EXTRA_INCLUDES "include/platform")
-list(APPEND EXTRA_INCLUDES "include/audio/container")
+file(GLOB SOURCES
+    "external/nanopb/*.c"
+    "main/utilities/*.cpp" "main/utilities/*.c"
+    "main/io/*.cpp" "main/io/*.c"
+)
+
+list(REMOVE_ITEM SOURCES "${IO_DIR}/BellTar.cpp" "${IO_DIR}/BellHTTPServer.cpp")
+
+list(APPEND EXTRA_INCLUDES "main/audio-codec/include")
+list(APPEND EXTRA_INCLUDES "main/audio-dsp/include")
+list(APPEND EXTRA_INCLUDES "main/audio-sinks/include")
+list(APPEND EXTRA_INCLUDES "main/io/include")
+list(APPEND EXTRA_INCLUDES "main/utilities/include")
+list(APPEND EXTRA_INCLUDES "main/platform")
 
 # Add platform specific sources
 if(ESP_PLATFORM)
-    file(GLOB ESP_PLATFORM_SOURCES "src/platform/esp/*.cpp" "src/platform/esp/*.c" "src/asm/biquad_f32_ae32.S")
+    file(GLOB ESP_PLATFORM_SOURCES "main/platform/esp/*.cpp" "main/platform/esp/*.c" "main/asm/biquad_f32_ae32.S")
     list(APPEND SOURCES ${ESP_PLATFORM_SOURCES})
 endif()
-if(UNIX)
-    file(GLOB UNIX_PLATFORM_SOURCES "src/platform/unix/*.cpp" "src/platform/unix/*.c")
-    list(APPEND SOURCES ${UNIX_PLATFORM_SOURCES})
-endif()
+
 if(APPLE)
-    file(GLOB APPLE_PLATFORM_SOURCES "src/platform/apple/*.cpp" "src/platform/apple/*.c")
+    file(GLOB APPLE_PLATFORM_SOURCES "main/platform/apple/*.cpp" "main/platform/apple/*.c")
     list(APPEND SOURCES ${APPLE_PLATFORM_SOURCES})
     list(APPEND EXTRA_INCLUDES "/usr/local/opt/mbedtls@3/include")
 endif()
+
 if(UNIX AND NOT APPLE)
-    file(GLOB LINUX_PLATFORM_SOURCES "src/platform/linux/*.cpp" "src/platform/linux/*.c")
+    file(GLOB LINUX_PLATFORM_SOURCES "main/platform/linux/*.cpp" "main/platform/linux/*.c")
     list(APPEND SOURCES ${LINUX_PLATFORM_SOURCES})
 endif()
+
 if(WIN32)
-    file(GLOB WIN32_PLATFORM_SOURCES "src/platform/win32/*.cpp" "src/platform/win32/*.c")
+    file(GLOB WIN32_PLATFORM_SOURCES "main/platform/win32/*.cpp" "main/platform/win32/*.c")
     list(APPEND SOURCES ${WIN32_PLATFORM_SOURCES})
-    list(APPEND EXTRA_INCLUDES "include/platform/win32")    
+    list(APPEND EXTRA_INCLUDES "main/platform/win32")
 endif()
 
 # A hack to make Opus keep quiet
@@ -96,90 +132,75 @@ function(message)
     endif()
 endfunction()
 
+
 if(ESP_PLATFORM)
-    list(APPEND EXTRA_LIBS idf::mbedtls idf::pthread idf::mdns)
-    add_definitions(-Wunused-const-variable -Wchar-subscripts -Wunused-label -Wmaybe-uninitialized -Wmisleading-indentation)
+    list(APPEND EXTRA_LIBS idf::mdns idf::mbedtls idf::pthread idf::driver idf::lwip)
+    add_definitions(-Wunused-const-variable -Wchar-subscripts -Wunused-label -Wmaybe-uninitialized -Wmisleading-indentation -Wno-stringop-overflow -Wno-error=format -Wno-format -Wno-stringop-overread -Wno-stringop-overflow)
 else()
     find_package(Threads REQUIRED)
-    set(THREADS_PREFER_PTHREAD_FLAG ON)
-    list(APPEND EXTRA_LIBS Threads::Threads)
-    
     find_package(MbedTLS REQUIRED)
-    get_target_property(MBEDTLS_INFO MbedTLS::mbedtls INTERFACE_INCLUDE_DIRECTORIES)
-    list(APPEND EXTRA_INCLUDES ${MBEDTLS_INFO})
-
-    # try to handle mbedtls when not system-wide installed      
-    if(BELL_EXTERNAL_MBEDTLS)
-        if(MSVC)
-            set(MBEDTLS_RELEASE "RELEASE" CACHE STRING "local mbedtls version")
-        else()
-            set(MBEDTLS_RELEASE "NOCONFIG" CACHE STRING "local mbedtls version")
-        endif()
-        message(STATUS "using local mbedtls version ${MBEDTLS_RELEASE}")        
-        get_target_property(MBEDTLS_INFO MbedTLS::mbedtls IMPORTED_LOCATION_${MBEDTLS_RELEASE})
-        list(APPEND EXTRA_LIBS ${MBEDTLS_INFO})
-        get_target_property(MBEDTLS_INFO MbedTLS::mbedx509 IMPORTED_LOCATION_${MBEDTLS_RELEASE})
-        list(APPEND EXTRA_LIBS ${MBEDTLS_INFO})
-        get_target_property(MBEDTLS_INFO MbedTLS::mbedcrypto IMPORTED_LOCATION_${MBEDTLS_RELEASE})
-        list(APPEND EXTRA_LIBS ${MBEDTLS_INFO})
-    else()  
-        list(APPEND EXTRA_LIBS mbedtls mbedcrypto mbedx509)
-    endif() 
-    
+    list(APPEND EXTRA_INCLUDES ${MBEDTLS_INCLUDE_DIRS})
+    set(THREADS_PREFER_PTHREAD_FLAG ON)
+    list(APPEND EXTRA_LIBS ${MBEDTLS_LIBRARIES} Threads::Threads)
+
     if(MSVC)
-        add_compile_definitions(NOMINMAX _CRT_SECURE_NO_WARNINGS)
+        add_compile_definitions(NOMINMAX _CRT_SECURE_NO_WARNINGS _USE_MATH_DEFINES)
         add_definitions(/wd4068 /wd4244 /wd4018 /wd4101 /wd4102 /wd4142)
-    endif() 
+    endif()
 endif()
 
 if(NOT BELL_DISABLE_CODECS)
-	file(GLOB EXTRA_SOURCES "src/audio/container/*.cpp")
-	list(APPEND SOURCES "${EXTRA_SOURCES}")
-    list(APPEND SOURCES "${AUDIO_DIR}/codec/DecoderGlobals.cpp")
-    list(APPEND SOURCES "${AUDIO_DIR}/codec/BaseCodec.cpp")
-    list(APPEND SOURCES "${AUDIO_DIR}/codec/AudioCodecs.cpp")
-    list(APPEND EXTRA_INCLUDES "include/audio/codec")
+    file(GLOB EXTRA_SOURCES "main/audio-containers/*.cpp" "main/audio-codec/*.cpp" "main/audio-codec/*.c" "main/audio-dsp/*.cpp" "main/audio-dsp/*.c")
+
+    list(APPEND SOURCES "${EXTRA_SOURCES}")
+    list(APPEND SOURCES "${AUDIO_CODEC_DIR}/DecoderGlobals.cpp")
+    list(APPEND SOURCES "${AUDIO_CODEC_DIR}/BaseCodec.cpp")
+    list(APPEND SOURCES "${AUDIO_CODEC_DIR}/AudioCodecs.cpp")
+    list(APPEND EXTRA_INCLUDES "main/audio-containers/include")
+
     # AAC-LC codec
     if(BELL_CODEC_AAC)
-        file(GLOB LIBHELIX_AAC_SOURCES "libhelix-aac/*.c")
+        file(GLOB LIBHELIX_AAC_SOURCES "external/libhelix-aac/*.c")
         list(APPEND LIBHELIX_SOURCES ${LIBHELIX_AAC_SOURCES})
-        list(APPEND EXTRA_INCLUDES "libhelix-aac")
-        list(APPEND SOURCES "${AUDIO_DIR}/codec/AACDecoder.cpp")
+        list(APPEND EXTRA_INCLUDES "external/libhelix-aac")
+        list(APPEND SOURCES "${AUDIO_CODEC_DIR}/AACDecoder.cpp")
         list(APPEND CODEC_FLAGS "-DBELL_CODEC_AAC")
     endif()
+
     # MP3 codec
     if(BELL_CODEC_MP3)
-        file(GLOB LIBHELIX_MP3_SOURCES "libhelix-mp3/*.c")
+        file(GLOB LIBHELIX_MP3_SOURCES "external/libhelix-mp3/*.c")
         list(APPEND LIBHELIX_SOURCES ${LIBHELIX_MP3_SOURCES})
-        list(APPEND EXTRA_INCLUDES "libhelix-mp3")
-        list(APPEND SOURCES "${AUDIO_DIR}/codec/MP3Decoder.cpp")
+        list(APPEND EXTRA_INCLUDES "external/libhelix-mp3")
+        list(APPEND SOURCES "${AUDIO_CODEC_DIR}/MP3Decoder.cpp")
         list(APPEND CODEC_FLAGS "-DBELL_CODEC_MP3")
     endif()
 
     # MP3 codec
-    if(BELL_CODEC_ALAC)
-        file(GLOB ALAC_SOURCES "alac/*.c" "alac/*.cpp")
-        list(APPEND ALAC_SOURCES ${ALAC_SOURCES})
-        list(APPEND EXTRA_INCLUDES "alac")
-        # list(APPEND SOURCES "${AUDIO_DIR}/codec/ALACDecoder.cpp")
-        list(APPEND CODEC_FLAGS "-DBELL_CODEC_ALAC")
-    endif()
+    # if(BELL_CODEC_ALAC)
+    #     file(GLOB ALAC_SOURCES "external/alac/*.c" "external/alac/*.cpp")
+    #     list(APPEND ALAC_SOURCES ${ALAC_SOURCES})
+    #     list(APPEND EXTRA_INCLUDES "external/alac")
+
+    #     # list(APPEND SOURCES "${AUDIO_DIR}/codec/ALACDecoder.cpp")
+    #     list(APPEND CODEC_FLAGS "-DBELL_CODEC_ALAC")
+    # endif()
+
     # libhelix Cygwin workaround
     if(CYGWIN)
         # Both Cygwin and ESP are Unix-like so this seems to work (or, at least, compile)
-        set_source_files_properties("${AUDIO_DIR}/codec/DecoderGlobals.cpp" ${LIBHELIX_SOURCES} PROPERTIES COMPILE_FLAGS "-DESP_PLATFORM")
+        set_source_files_properties("${AUDIO_CODEC_DIR}/DecoderGlobals.cpp" ${LIBHELIX_SOURCES} PROPERTIES COMPILE_FLAGS "-DESP_PLATFORM")
     endif()
+
     list(APPEND SOURCES ${LIBHELIX_SOURCES})
     list(APPEND SOURCES ${ALAC_SOURCES})
+
     # Vorbis codec
     if(BELL_CODEC_VORBIS)
-        file(GLOB TREMOR_SOURCES "tremor/*.c")
-        list(REMOVE_ITEM TREMOR_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tremor/ivorbisfile_example.c")
-        list(APPEND SOURCES ${TREMOR_SOURCES})
-        list(APPEND EXTRA_INCLUDES "tremor")
-        list(APPEND SOURCES "${AUDIO_DIR}/codec/VorbisDecoder.cpp")
+        list(APPEND SOURCES "${AUDIO_CODEC_DIR}/VorbisDecoder.cpp")
         list(APPEND CODEC_FLAGS "-DBELL_CODEC_VORBIS")
-    endif()
+    endif() 
+    
     # Opus codec
     if(BELL_CODEC_OPUS)
         set(OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF CACHE BOOL "")
@@ -187,72 +208,125 @@ if(NOT BELL_DISABLE_CODECS)
         set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF CACHE BOOL "")
         set(OPUS_INSTALL_PKG_CONFIG_MODULE OFF)
         set(MESSAGE_QUIET ON)
-        add_subdirectory("opus")
+        add_subdirectory("external/opus")
         unset(MESSAGE_QUIET)
         target_compile_options(opus PRIVATE "-O3")
         list(APPEND EXTRA_LIBS Opus::opus)
-        list(APPEND SOURCES "${AUDIO_DIR}/codec/OPUSDecoder.cpp")
+        list(APPEND SOURCES "${AUDIO_CODEC_DIR}/OPUSDecoder.cpp")
         list(APPEND CODEC_FLAGS -DBELL_CODEC_OPUS)
     endif()
+    
     # Enable global codecs
     string(REPLACE ";" " " CODEC_FLAGS "${CODEC_FLAGS}")
-    set_source_files_properties("${AUDIO_DIR}/codec/AudioCodecs.cpp" PROPERTIES COMPILE_FLAGS "${CODEC_FLAGS}")
-elseif(BELL_EXTERNAL_TREMOR) 	
-    list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_TREMOR})
+    set_source_files_properties("${AUDIO_CODEC_DIR}/AudioCodecs.cpp" PROPERTIES COMPILE_FLAGS "${CODEC_FLAGS}")
+else()  
+    list(REMOVE_ITEM SOURCES "${IO_DIR}/EncodedAudioStream.cpp")
+endif() 
+
+if(NOT BELL_EXTERNAL_VORBIS STREQUAL "")
+    message(STATUS "Using external Vorbis codec ${BELL_EXTERNAL_VORBIS}")
+    list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_VORBIS})
+else()  
+    file(GLOB TREMOR_SOURCES "external/tremor/*.c")
+    list(REMOVE_ITEM TREMOR_SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/external/tremor/ivorbisfile_example.c")
+    list(APPEND SOURCES ${TREMOR_SOURCES})
+    list(APPEND EXTRA_INCLUDES "external/tremor")
 endif()
 
 if(NOT BELL_DISABLE_SINKS)
     set(PLATFORM "unix")
+
     if(ESP_PLATFORM)
         set(PLATFORM "esp")
     endif()
+
     # Add all built-in audio sinks
-    file(GLOB SINK_SOURCES "${AUDIO_DIR}/sinks/${PLATFORM}/*.cpp" "${AUDIO_DIR}/sinks/${PLATFORM}/*.c")
-    list(APPEND EXTRA_INCLUDES "include/audio/sinks/${PLATFORM}")
+    file(GLOB SINK_SOURCES "${AUDIO_SINKS_DIR}/${PLATFORM}/*.cpp" "${AUDIO_SINKS_DIR}/${PLATFORM}/*.c")
+    list(APPEND EXTRA_INCLUDES "main/audio-sinks/include/${PLATFORM}")
+
     # Find ALSA if required, else remove the sink
     if(BELL_SINK_ALSA)
         find_package(ALSA REQUIRED)
         list(APPEND EXTRA_INCLUDES ${ALSA_INCLUDE_DIRS})
         list(APPEND EXTRA_LIBS ${ALSA_LIBRARIES})
     else()
-        list(REMOVE_ITEM SINK_SOURCES "${AUDIO_DIR}/sinks/unix/ALSAAudioSink.cpp")
+        list(REMOVE_ITEM SINK_SOURCES "${AUDIO_SINKS_DIR}/unix/ALSAAudioSink.cpp")
     endif()
+
     # Find PortAudio if required, else remove the sink
     if(BELL_SINK_PORTAUDIO)
-        if(WIN32)
-            list(APPEND EXTRA_INCLUDES "portaudio/include")
-            if(NOT "${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
-                list(APPEND EXTRA_LIBS "${CMAKE_CURRENT_SOURCE_DIR}/portaudio/portaudio_win32.lib")
-            else()
-                list(APPEND EXTRA_LIBS "${CMAKE_CURRENT_SOURCE_DIR}/portaudio/portaudio_x64.lib")
-            endif()
-        else()
-            find_package(portaudio REQUIRED)
-            list(APPEND EXTRA_INCLUDES ${PORTAUDIO_INCLUDE_DIRS})
-            list(APPEND EXTRA_LIBS ${PORTAUDIO_LIBRARIES})
-        endif()
+        find_package(Portaudio REQUIRED)
+        list(APPEND EXTRA_INCLUDES ${PORTAUDIO_INCLUDE_DIRS})
+        list(APPEND EXTRA_LIBS ${PORTAUDIO_LIBRARIES})
     else()
-        list(REMOVE_ITEM SINK_SOURCES "${AUDIO_DIR}/sinks/unix/PortAudioSink.cpp")
+        list(REMOVE_ITEM SINK_SOURCES "${AUDIO_SINKS_DIR}/unix/PortAudioSink.cpp")
     endif()
+
     list(APPEND SOURCES ${SINK_SOURCES})
 endif()
 
-if(BELL_DISABLE_CJSON)
-    list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/src/JSONObject.cpp")
-else()
-    if(BELL_EXTERNAL_CJSON)
-        list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_CJSON})
+if(NOT BELL_ONLY_CJSON)
+    add_subdirectory(external/nlohmann_json)
+    list(APPEND EXTRA_LIBS nlohmann_json::nlohmann_json)
+endif()	
+
+if(BELL_EXTERNAL_CJSON)
+	list(APPEND EXTRA_LIBS ${BELL_EXTERNAL_CJSON})
+else()	
+	list(APPEND SOURCES "external/cJSON/cJSON.c")
+    list(APPEND EXTRA_INCLUDES "external/cJSON")
+endif()	
+
+if (NOT BELL_DISABLE_FMT)
+    list(APPEND EXTRA_INCLUDES "external/fmt/include")
+endif()
+
+if(WIN32 OR UNIX)
+    list(APPEND SOURCES "external/mdnssvc/mdns.c" "external/mdnssvc/mdnsd.c")
+    list(APPEND EXTRA_INCLUDES "external/mdnssvc")
+endif() 
+
+# file(GLOB CIVET_SRC "external/civetweb/*.c" "external/civetweb/*.inl" "external/civetweb/*.cpp")
+
+# list(APPEND SOURCES ${CIVET_SRC})
+# list(APPEND EXTRA_INCLUDES "external/civetweb/include") 
+
+add_library(bell STATIC ${SOURCES})
+
+# Add Apple Bonjour compatibility library for Linux
+if(UNIX AND NOT APPLE)
+    if (BELL_DISABLE_AVAHI)
+        add_compile_definitions(BELL_DISABLE_AVAHI)
     else()
-        list(APPEND SOURCES "cJSON/cJSON.c")
-        list(APPEND EXTRA_INCLUDES "cJSON")
+        list(APPEND EXTRA_LIBS avahi-client avahi-common)
     endif()
 endif()
 
-add_library(bell STATIC ${SOURCES})
 # PUBLIC to propagate esp-idf includes to bell dependents
 target_link_libraries(bell PUBLIC ${EXTRA_LIBS})
-target_include_directories(bell PUBLIC "include" ${EXTRA_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
-target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC)
-if(WIN32)
-    target_compile_definitions(bell PUBLIC PB_NO_STATIC_ASSERT)
+target_include_directories(bell PUBLIC ${EXTRA_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
+target_compile_definitions(bell PUBLIC PB_ENABLE_MALLOC FMT_HEADER_ONLY)
+
+if(BELL_DISABLE_CODECS)
+    target_compile_definitions(bell PUBLIC BELL_DISABLE_CODECS)
 endif() 
+
+if(BELL_VORBIS_FLOAT)
+    target_compile_definitions(bell PUBLIC BELL_VORBIS_FLOAT)
+endif() 
+
+if(BELL_DISABLE_FMT)
+	target_compile_definitions(bell PUBLIC BELL_DISABLE_FMT)
+endif()
+
+if(BELL_DISABLE_REGEX)
+    target_compile_definitions(bell PUBLIC BELL_DISABLE_REGEX)
+endif()	
+
+if(BELL_ONLY_CJSON)
+    target_compile_definitions(bell PUBLIC BELL_ONLY_CJSON)
+endif()	
+
+if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+    target_compile_definitions(bell PUBLIC PB_NO_STATIC_ASSERT)
+endif()

+ 0 - 9
components/spotify/cspot/bell/README.md

@@ -1,9 +0,0 @@
-# bell
-
-Core audio utils library used in cspot and euphonium projects.
-
-Implemented utilities:
-
-- HTTPServer
-- Crypto (openssl and mbedtls backed)
-- Semaphore implementations

+ 0 - 163
components/spotify/cspot/bell/cJSON/Makefile

@@ -1,163 +0,0 @@
-CJSON_OBJ = cJSON.o
-UTILS_OBJ = cJSON_Utils.o
-CJSON_LIBNAME = libcjson
-UTILS_LIBNAME = libcjson_utils
-CJSON_TEST = cJSON_test
-
-CJSON_TEST_SRC = cJSON.c test.c
-
-LDLIBS = -lm
-
-LIBVERSION = 1.7.15
-CJSON_SOVERSION = 1
-UTILS_SOVERSION = 1
-
-CJSON_SO_LDFLAG=-Wl,-soname=$(CJSON_LIBNAME).so.$(CJSON_SOVERSION)
-UTILS_SO_LDFLAG=-Wl,-soname=$(UTILS_LIBNAME).so.$(UTILS_SOVERSION)
-
-PREFIX ?= /usr/local
-INCLUDE_PATH ?= include/cjson
-LIBRARY_PATH ?= lib
-
-INSTALL_INCLUDE_PATH = $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH)
-INSTALL_LIBRARY_PATH = $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH)
-
-INSTALL ?= cp -a
-
-CC = gcc -std=c89
-
-# validate gcc version for use fstack-protector-strong
-MIN_GCC_VERSION = "4.9"
-GCC_VERSION := "`$(CC) -dumpversion`"
-IS_GCC_ABOVE_MIN_VERSION := $(shell expr "$(GCC_VERSION)" ">=" "$(MIN_GCC_VERSION)")
-ifeq "$(IS_GCC_ABOVE_MIN_VERSION)" "1"
-    CFLAGS += -fstack-protector-strong
-else
-    CFLAGS += -fstack-protector
-endif
-
-PIC_FLAGS = -fPIC
-R_CFLAGS = $(PIC_FLAGS) -pedantic -Wall -Werror -Wstrict-prototypes -Wwrite-strings -Wshadow -Winit-self -Wcast-align -Wformat=2 -Wmissing-prototypes -Wstrict-overflow=2 -Wcast-qual -Wc++-compat -Wundef -Wswitch-default -Wconversion $(CFLAGS)
-
-uname := $(shell sh -c 'uname -s 2>/dev/null || echo false')
-
-#library file extensions
-SHARED = so
-STATIC = a
-
-## create dynamic (shared) library on Darwin (base OS for MacOSX and IOS)
-ifeq (Darwin, $(uname))
-	SHARED = dylib
-	CJSON_SO_LDFLAG = ""
-	UTILS_SO_LDFLAG = ""
-endif
-
-#cJSON library names
-CJSON_SHARED = $(CJSON_LIBNAME).$(SHARED)
-CJSON_SHARED_VERSION = $(CJSON_LIBNAME).$(SHARED).$(LIBVERSION)
-CJSON_SHARED_SO = $(CJSON_LIBNAME).$(SHARED).$(CJSON_SOVERSION)
-CJSON_STATIC = $(CJSON_LIBNAME).$(STATIC)
-
-#cJSON_Utils library names
-UTILS_SHARED = $(UTILS_LIBNAME).$(SHARED)
-UTILS_SHARED_VERSION = $(UTILS_LIBNAME).$(SHARED).$(LIBVERSION)
-UTILS_SHARED_SO = $(UTILS_LIBNAME).$(SHARED).$(UTILS_SOVERSION)
-UTILS_STATIC = $(UTILS_LIBNAME).$(STATIC)
-
-SHARED_CMD = $(CC) -shared -o
-
-.PHONY: all shared static tests clean install
-
-all: shared static tests
-
-shared: $(CJSON_SHARED) $(UTILS_SHARED)
-
-static: $(CJSON_STATIC) $(UTILS_STATIC)
-
-tests: $(CJSON_TEST)
-
-test: tests
-	./$(CJSON_TEST)
-
-.c.o:
-	$(CC) -c $(R_CFLAGS) $<
-
-#tests
-#cJSON
-$(CJSON_TEST): $(CJSON_TEST_SRC) cJSON.h
-	$(CC) $(R_CFLAGS) $(CJSON_TEST_SRC)  -o $@ $(LDLIBS) -I.
-
-#static libraries
-#cJSON
-$(CJSON_STATIC): $(CJSON_OBJ)
-	$(AR) rcs $@ $<
-#cJSON_Utils
-$(UTILS_STATIC): $(UTILS_OBJ)
-	$(AR) rcs $@ $<
-
-#shared libraries .so.1.0.0
-#cJSON
-$(CJSON_SHARED_VERSION): $(CJSON_OBJ)
-	$(CC) -shared -o $@ $< $(CJSON_SO_LDFLAG) $(LDFLAGS)
-#cJSON_Utils
-$(UTILS_SHARED_VERSION): $(UTILS_OBJ)
-	$(CC) -shared -o $@ $< $(CJSON_OBJ) $(UTILS_SO_LDFLAG) $(LDFLAGS)
-
-#objects
-#cJSON
-$(CJSON_OBJ): cJSON.c cJSON.h
-#cJSON_Utils
-$(UTILS_OBJ): cJSON_Utils.c cJSON_Utils.h cJSON.h
-
-
-#links .so -> .so.1 -> .so.1.0.0
-#cJSON
-$(CJSON_SHARED_SO): $(CJSON_SHARED_VERSION)
-	ln -s $(CJSON_SHARED_VERSION) $(CJSON_SHARED_SO)
-$(CJSON_SHARED): $(CJSON_SHARED_SO)
-	ln -s $(CJSON_SHARED_SO) $(CJSON_SHARED)
-#cJSON_Utils
-$(UTILS_SHARED_SO): $(UTILS_SHARED_VERSION)
-	ln -s $(UTILS_SHARED_VERSION) $(UTILS_SHARED_SO)
-$(UTILS_SHARED): $(UTILS_SHARED_SO)
-	ln -s $(UTILS_SHARED_SO) $(UTILS_SHARED)
-
-#install
-#cJSON
-install-cjson:
-	mkdir -p $(INSTALL_LIBRARY_PATH) $(INSTALL_INCLUDE_PATH)
-	$(INSTALL) cJSON.h $(INSTALL_INCLUDE_PATH)
-	$(INSTALL) $(CJSON_SHARED) $(CJSON_SHARED_SO) $(CJSON_SHARED_VERSION) $(INSTALL_LIBRARY_PATH)
-#cJSON_Utils
-install-utils: install-cjson
-	$(INSTALL) cJSON_Utils.h $(INSTALL_INCLUDE_PATH)
-	$(INSTALL) $(UTILS_SHARED) $(UTILS_SHARED_SO) $(UTILS_SHARED_VERSION) $(INSTALL_LIBRARY_PATH)
-
-install: install-cjson install-utils
-
-#uninstall
-#cJSON
-uninstall-cjson: uninstall-utils
-	$(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED)
-	$(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED_VERSION)
-	$(RM) $(INSTALL_LIBRARY_PATH)/$(CJSON_SHARED_SO)
-	$(RM) $(INSTALL_INCLUDE_PATH)/cJSON.h
-	
-#cJSON_Utils
-uninstall-utils:
-	$(RM) $(INSTALL_LIBRARY_PATH)/$(UTILS_SHARED)
-	$(RM) $(INSTALL_LIBRARY_PATH)/$(UTILS_SHARED_VERSION)
-	$(RM) $(INSTALL_LIBRARY_PATH)/$(UTILS_SHARED_SO)
-	$(RM) $(INSTALL_INCLUDE_PATH)/cJSON_Utils.h
-
-remove-dir:
-	$(if $(wildcard $(INSTALL_LIBRARY_PATH)/*.*),,rmdir $(INSTALL_LIBRARY_PATH))
-	$(if $(wildcard $(INSTALL_INCLUDE_PATH)/*.*),,rmdir $(INSTALL_INCLUDE_PATH))
-
-uninstall: uninstall-utils uninstall-cjson remove-dir
-
-clean:
-	$(RM) $(CJSON_OBJ) $(UTILS_OBJ) #delete object files
-	$(RM) $(CJSON_SHARED) $(CJSON_SHARED_VERSION) $(CJSON_SHARED_SO) $(CJSON_STATIC) #delete cJSON
-	$(RM) $(UTILS_SHARED) $(UTILS_SHARED_VERSION) $(UTILS_SHARED_SO) $(UTILS_STATIC) #delete cJSON_Utils
-	$(RM) $(CJSON_TEST)  #delete test

+ 0 - 71
components/spotify/cspot/bell/cJSON/tests/unity/examples/example_1/makefile

@@ -1,71 +0,0 @@
-# ==========================================
-#   Unity Project - A Test Framework for C
-#   Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
-#   [Released under MIT License. Please refer to license.txt for details]
-# ==========================================
-
-#We try to detect the OS we are running on, and adjust commands as needed
-ifeq ($(OS),Windows_NT)
-  ifeq ($(shell uname -s),) # not in a bash-like shell
-	CLEANUP = del /F /Q
-	MKDIR = mkdir
-  else # in a bash-like shell, like msys
-	CLEANUP = rm -f
-	MKDIR = mkdir -p
-  endif
-	TARGET_EXTENSION=.exe
-else
-	CLEANUP = rm -f
-	MKDIR = mkdir -p
-	TARGET_EXTENSION=.out
-endif
-
-C_COMPILER=gcc
-ifeq ($(shell uname -s), Darwin)
-C_COMPILER=clang
-endif
-
-UNITY_ROOT=../..
-
-CFLAGS=-std=c89
-CFLAGS += -Wall
-CFLAGS += -Wextra
-CFLAGS += -Wpointer-arith
-CFLAGS += -Wcast-align
-CFLAGS += -Wwrite-strings
-CFLAGS += -Wswitch-default
-CFLAGS += -Wunreachable-code
-CFLAGS += -Winit-self
-CFLAGS += -Wmissing-field-initializers
-CFLAGS += -Wno-unknown-pragmas
-CFLAGS += -Wstrict-prototypes
-CFLAGS += -Wundef
-CFLAGS += -Wold-style-definition
-
-TARGET_BASE1=test1
-TARGET_BASE2=test2
-TARGET1 = $(TARGET_BASE1)$(TARGET_EXTENSION)
-TARGET2 = $(TARGET_BASE2)$(TARGET_EXTENSION)
-SRC_FILES1=$(UNITY_ROOT)/src/unity.c src/ProductionCode.c  test/TestProductionCode.c  test/test_runners/TestProductionCode_Runner.c
-SRC_FILES2=$(UNITY_ROOT)/src/unity.c src/ProductionCode2.c test/TestProductionCode2.c test/test_runners/TestProductionCode2_Runner.c
-INC_DIRS=-Isrc -I$(UNITY_ROOT)/src
-SYMBOLS=
-
-all: clean default
-
-default: $(SRC_FILES1) $(SRC_FILES2)
-	$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) -o $(TARGET1)
-	$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES2) -o $(TARGET2)
-	- ./$(TARGET1)
-	./$(TARGET2)
-
-test/test_runners/TestProductionCode_Runner.c: test/TestProductionCode.c
-	ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/TestProductionCode.c  test/test_runners/TestProductionCode_Runner.c
-test/test_runners/TestProductionCode2_Runner.c: test/TestProductionCode2.c
-	ruby $(UNITY_ROOT)/auto/generate_test_runner.rb test/TestProductionCode2.c test/test_runners/TestProductionCode2_Runner.c
-
-clean:
-	$(CLEANUP) $(TARGET1) $(TARGET2)
-
-ci: CFLAGS += -Werror
-ci: default

+ 0 - 70
components/spotify/cspot/bell/cJSON/tests/unity/examples/example_2/makefile

@@ -1,70 +0,0 @@
-# ==========================================
-#   Unity Project - A Test Framework for C
-#   Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
-#   [Released under MIT License. Please refer to license.txt for details]
-# ==========================================
-
-#We try to detect the OS we are running on, and adjust commands as needed
-ifeq ($(OS),Windows_NT)
-  ifeq ($(shell uname -s),) # not in a bash-like shell
-	CLEANUP = del /F /Q
-	MKDIR = mkdir
-  else # in a bash-like shell, like msys
-	CLEANUP = rm -f
-	MKDIR = mkdir -p
-  endif
-	TARGET_EXTENSION=.exe
-else
-	CLEANUP = rm -f
-	MKDIR = mkdir -p
-	TARGET_EXTENSION=.out
-endif
-
-C_COMPILER=gcc
-ifeq ($(shell uname -s), Darwin)
-C_COMPILER=clang
-endif
-
-UNITY_ROOT=../..
-
-CFLAGS=-std=c99
-CFLAGS += -Wall
-CFLAGS += -Wextra
-CFLAGS += -Wpointer-arith
-CFLAGS += -Wcast-align
-CFLAGS += -Wwrite-strings
-CFLAGS += -Wswitch-default
-CFLAGS += -Wunreachable-code
-CFLAGS += -Winit-self
-CFLAGS += -Wmissing-field-initializers
-CFLAGS += -Wno-unknown-pragmas
-CFLAGS += -Wstrict-prototypes
-CFLAGS += -Wundef
-CFLAGS += -Wold-style-definition
-
-TARGET_BASE1=all_tests
-TARGET1 = $(TARGET_BASE1)$(TARGET_EXTENSION)
-SRC_FILES1=\
-  $(UNITY_ROOT)/src/unity.c \
-  $(UNITY_ROOT)/extras/fixture/src/unity_fixture.c \
-  src/ProductionCode.c \
-  src/ProductionCode2.c \
-  test/TestProductionCode.c \
-  test/TestProductionCode2.c \
-  test/test_runners/TestProductionCode_Runner.c \
-  test/test_runners/TestProductionCode2_Runner.c \
-  test/test_runners/all_tests.c
-INC_DIRS=-Isrc -I$(UNITY_ROOT)/src -I$(UNITY_ROOT)/extras/fixture/src
-SYMBOLS=
-
-all: clean default
-
-default:
-	$(C_COMPILER) $(CFLAGS) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES1) -o $(TARGET1)
-	- ./$(TARGET1) -v
-
-clean:
-	$(CLEANUP) $(TARGET1)
-
-ci: CFLAGS += -Werror
-ci: default

+ 35 - 0
components/spotify/cspot/bell/cmake/FindMbedTLS.cmake

@@ -0,0 +1,35 @@
+if(BELL_EXTERNAL_MBEDTLS)
+    set(MbedTLS_DIR ${BELL_EXTERNAL_MBEDTLS})
+    message(STATUS "Using config mode, setting local mbedtls ${MbedTLS_DIR}")
+
+	find_package(MbedTLS REQUIRED CONFIG)
+	
+	get_target_property(MBEDTLS_INCLUDE_DIRS MbedTLS::mbedtls INTERFACE_INCLUDE_DIRECTORIES)
+
+    if(MSVC)
+        set(MBEDTLS_RELEASE "RELEASE" CACHE STRING "local mbedtls version")
+    else()
+        set(MBEDTLS_RELEASE "NOCONFIG" CACHE STRING "local mbedtls version")
+    endif()
+    
+    get_target_property(MBEDTLS_INFO MbedTLS::mbedtls IMPORTED_LOCATION_${MBEDTLS_RELEASE})
+    set(MBEDTLS_LIBRARIES ${MBEDTLS_INFO})
+    get_target_property(MBEDTLS_INFO MbedTLS::mbedx509 IMPORTED_LOCATION_${MBEDTLS_RELEASE})
+    list(APPEND MBEDTLS_LIBRARIES ${MBEDTLS_INFO})
+    get_target_property(MBEDTLS_INFO MbedTLS::mbedcrypto IMPORTED_LOCATION_${MBEDTLS_RELEASE})
+    list(APPEND MBEDTLS_LIBRARIES ${MBEDTLS_INFO})
+else()
+	find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
+
+find_library(MBEDTLS_LIBRARY mbedtls)
+find_library(MBEDX509_LIBRARY mbedx509)
+find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
+
+set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(MbedTLS DEFAULT_MSG
+    MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+
+	mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+endif()

+ 63 - 0
components/spotify/cspot/bell/cmake/Findportaudio.cmake

@@ -0,0 +1,63 @@
+#  PORTAUDIO_FOUND - system has libportaudio
+#  PORTAUDIO_INCLUDE_DIRS - the libportaudio include directory
+#  PORTAUDIO_LIBRARIES - Link these to use libportaudio
+
+if (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)
+  # in cache already
+  set(PORTAUDIO_FOUND TRUE)
+else (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)
+  if(WIN32)
+	set(PORTAUDIO_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/portaudio/include")
+
+    if(NOT "${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
+	  set(PORTAUDIO_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/external/portaudio/portaudio_win32.lib")	  
+    else()
+      set(PORTAUDIO_LIBRARY "${CMAKE_CURRENT_SOURCE_DIR}/external/portaudio/portaudio_x64.lib")
+    endif()
+  else()
+ 	find_path(PORTAUDIO_INCLUDE_DIR
+	  NAMES
+		portaudio.h
+		PATHS
+			/usr/include
+			/usr/local/include
+			/opt/local/include
+			/sw/include
+	)
+  
+	find_library(PORTAUDIO_LIBRARY
+		NAMES
+		portaudio
+		PATHS
+			/usr/lib
+			/usr/local/lib
+			/opt/local/lib
+			/sw/lib
+	)
+  endif()
+  
+  set(PORTAUDIO_INCLUDE_DIRS
+    ${PORTAUDIO_INCLUDE_DIR}
+  )
+  set(PORTAUDIO_LIBRARIES
+    ${PORTAUDIO_LIBRARY}
+  )
+
+  if (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES)
+    set(PORTAUDIO_FOUND TRUE)
+  endif (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES)
+
+  if (PORTAUDIO_FOUND)
+    if (NOT Portaudio_FIND_QUIETLY)
+      message(STATUS "Found libportaudio: ${PORTAUDIO_LIBRARIES}")
+    endif (NOT Portaudio_FIND_QUIETLY)
+  else (PORTAUDIO_FOUND)
+    if (Portaudio_FIND_REQUIRED)
+      message(FATAL_ERROR "Could not find libportaudio")
+    endif (Portaudio_FIND_REQUIRED)
+  endif (PORTAUDIO_FOUND)
+
+  # show the PORTAUDIO_INCLUDE_DIRS and PORTAUDIO_LIBRARIES variables only in the advanced view
+  mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES)
+
+endif (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)

+ 14 - 0
components/spotify/cspot/bell/example/CMakeLists.txt

@@ -0,0 +1,14 @@
+project(bell_example)
+cmake_minimum_required(VERSION 3.18)
+set(CMAKE_CXX_STANDARD 20)
+set(CMAKE_BUILD_TYPE Debug)
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../ ${CMAKE_CURRENT_BINARY_DIR}/bell)
+
+file(GLOB SOURCES "*.cpp")
+include_directories(".")
+
+add_executable(bell_example ${SOURCES})
+target_link_libraries(bell_example bell ${CMAKE_DL_LIBS} ${THINGS_TO_LINK})
+get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)

+ 70 - 0
components/spotify/cspot/bell/example/main.cpp

@@ -0,0 +1,70 @@
+#include <memory.h>
+#include <atomic>
+#include <cmath>
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <memory>
+#include <vector>
+#include "AudioCodecs.h"
+#include "AudioContainers.h"
+#include "BellHTTPServer.h"
+#include "BellTar.h"
+#include "BellTask.h"
+#include "CentralAudioBuffer.h"
+#include "Compressor.h"
+#include "DecoderGlobals.h"
+#include "EncodedAudioStream.h"
+#include "HTTPClient.h"
+#include "PortAudioSink.h"
+#define DEBUG_LEVEL 4
+#include "X509Bundle.h"
+#include "mbedtls/debug.h"
+
+#include <BellDSP.h>
+#include <BellLogger.h>
+
+std::shared_ptr<bell::CentralAudioBuffer> audioBuffer;
+std::atomic<bool> isPaused = false;
+
+class AudioPlayer : bell::Task {
+ public:
+  std::unique_ptr<PortAudioSink> audioSink;
+  std::unique_ptr<bell::BellDSP> dsp;
+
+  AudioPlayer() : bell::Task("player", 1024, 0, 0) {
+    this->audioSink = std::make_unique<PortAudioSink>();
+    this->audioSink->setParams(44100, 2, 16);
+    this->dsp = std::make_unique<bell::BellDSP>(audioBuffer);
+    startTask();
+  }
+
+  void runTask() override {
+    while (true) {
+      if (audioBuffer->hasAtLeast(64) || isPaused) {
+        auto chunk = audioBuffer->readChunk();
+
+        if (chunk != nullptr && chunk->pcmSize > 0) {
+          this->dsp->process(chunk->pcmData, chunk->pcmSize, 2, 44100,
+                             bell::BitWidth::BW_16);
+
+          this->audioSink->feedPCMFrames(chunk->pcmData, chunk->pcmSize);
+        }
+      }
+    }
+  }
+};
+
+int main() {
+  bell::setDefaultLogger();
+
+  std::fstream file("system.tar", std::ios::in | std::ios::binary);
+  if (!file.is_open()) {
+    std::cout << "file not open" << std::endl;
+    return 1;
+  }
+
+  BellTar::reader reader(file);
+  reader.extract_all_files("./dupa2");
+  return 0;
+}

+ 13 - 0
components/spotify/cspot/bell/example/scripts/dsp_spectogram.py

@@ -0,0 +1,13 @@
+import matplotlib.pyplot as plt
+from scipy import signal
+from scipy.io import wavfile
+
+sample_rate, samples = wavfile.read('out.wav')
+print(sample_rate)
+frequencies, times, spectrogram = signal.spectrogram(samples, sample_rate)
+
+plt.pcolormesh(times, frequencies, spectrogram)
+plt.imshow(spectrogram)
+plt.ylabel('Frequency [Hz]')
+plt.xlabel('Time [sec]')
+plt.show()

+ 6 - 0
components/spotify/cspot/bell/external/alac/.gitignore

@@ -0,0 +1,6 @@
+*.o*
+*.bak
+build/
+codec/*.a
+.vs/
+*.user

+ 241 - 0
components/spotify/cspot/bell/external/alac/ALACMagicCookieDescription.txt

@@ -0,0 +1,241 @@
+__________________________________________________________________________________________________________________________________
+__________________________________________________________________________________________________________________________________
+Apple Lossless Format "Magic Cookie" Description
+__________________________________________________________________________________________________________________________________
+__________________________________________________________________________________________________________________________________
+
+Many encoded formats for audio require additional, codec specific configuration information in order to operate successfully.
+This codec specific information is often called a 'magic cookie'. The Apple Lossless codec's 'magic cookie' contains the 
+ALACSpecificConfig and optional ALACChannelLayoutInfo (both described below).
+
+The 'magic cookie' must accompany the bitstream when stored in any file container (M4A/MP4, CAF) so that it may be provided to the 
+decoder when decoding the bitstream. From the caller's perspective, the 'magic cookie' is opaque and should be stored in the file 
+and presented to the decoder exactly as it is vended from the encoder (and consequently stored in the file). 
+
+The ALAC 'magic cookie' as stored in a file has all fields described in big-endian order (regardless of file format).
+
+The layout of the 'magic cookie' is as follows:
+
+
+---------------- ALAC Specific Info (24 bytes) (mandatory) ---------------------------
+(ALACSpecificConfig)		Decoder Info
+	
+---------------- Channel Layout Info (24 bytes) (optional) ----------------------------
+(ALAC Channel Layout Info)	Channel Layout Info
+
+
+If the channel layout is absent from the cookie, then the following assumptions are made:
+1 channel - mono
+2 channels - stereo in left, right order
+> 2 channels - no specific channel designation or role.
+
+
+__________________________________________________________________________________________________________________________________
+* ALAC Specific Info (24 bytes) (mandatory)
+__________________________________________________________________________________________________________________________________
+
+The Apple Lossless codec stores specific information about the encoded stream in the ALACSpecificConfig. This
+info is vended by the encoder and is used to setup the decoder for a given encoded bitstream. 
+
+When read from and written to a file, the fields of this struct must be in big-endian order. 
+When vended by the encoder (and received by the decoder) the struct values will be in big-endian order.
+
+/*
+    struct	ALACSpecificConfig (defined in ALACAudioTypes.h)
+    abstract   	This struct is used to describe codec provided information about the encoded Apple Lossless bitstream. 
+		It must accompany the encoded stream in the containing audio file and be provided to the decoder.
+
+    field      	frameLength 		uint32_t	indicating the frames per packet when no explicit frames per packet setting is 
+							present in the packet header. The encoder frames per packet can be explicitly set 
+							but for maximum compatibility, the default encoder setting of 4096 should be used.
+
+    field      	compatibleVersion 	uint8_t 	indicating compatible version, 
+							value must be set to 0
+
+    field      	bitDepth 		uint8_t 	describes the bit depth of the source PCM data (maximum value = 32)
+
+    field      	pb 			uint8_t 	currently unused tuning parameter. 
+						 	value should be set to 40
+
+    field      	mb 			uint8_t 	currently unused tuning parameter. 
+						 	value should be set to 10
+
+    field      	kb			uint8_t 	currently unused tuning parameter. 
+						 	value should be set to 14
+
+    field      	numChannels 		uint8_t 	describes the channel count (1 = mono, 2 = stereo, etc...)
+							when channel layout info is not provided in the 'magic cookie', a channel count > 2
+							describes a set of discreet channels with no specific ordering
+
+    field      	maxRun			uint16_t 	currently unused. 
+   						  	value should be set to 255
+
+    field      	maxFrameBytes 		uint32_t 	the maximum size of an Apple Lossless packet within the encoded stream. 
+						  	value of 0 indicates unknown
+
+    field      	avgBitRate 		uint32_t 	the average bit rate in bits per second of the Apple Lossless stream. 
+						  	value of 0 indicates unknown
+
+    field      	sampleRate 		uint32_t 	sample rate of the encoded stream
+ */
+
+typedef struct ALACSpecificConfig
+{
+	uint32_t	frameLength;
+	uint8_t		compatibleVersion;
+	uint8_t		bitDepth;
+	uint8_t		pb;
+	uint8_t		mb;
+	uint8_t		kb;
+	uint8_t		numChannels;
+	uint16_t	maxRun;
+	uint32_t	maxFrameBytes;
+	uint32_t	avgBitRate;
+	uint32_t	sampleRate;
+
+} ALACSpecificConfig;
+		
+
+__________________________________________________________________________________________________________________________________
+Channel Layout Info (24 bytes) (optional)
+__________________________________________________________________________________________________________________________________
+
+The Apple Lossless codec can support a specific set of channel layouts. When channel information is vended 
+by the encoder (in the 'magic cookie'), it is formatted in the the ALACChannelLayoutInfo.
+
+When read from and written to a file, the fields of this struct must be in big-endian order. 
+When vended by the encoder (and received by the decoder) the struct values will be in big-endian order.
+
+/*
+    struct	ALACChannelLayoutInfo (defined in ALACAudioTypes.h)
+    abstract	This struct is used to specify particular channel orderings or configurations.
+		It is an optional portion of the 'magic cookie', being required to describe specific channel layouts (see below)
+		of more than 2 channels. 
+
+    field      	channelLayoutInfoSize 	uint32_t 	indicates the size of the channel layout data
+							value should be set to 24
+
+    field      	channelLayoutInfoID 	uint32_t 	identifier indicating that channel layout info is present 
+							value = 'chan'
+
+    field      	versionFlags 		uint32_t 	version flags
+						 	value should be set to 0
+
+    field	channelLayoutTag	uint32_t	channel layout type
+							from defined list in ALACAudioTypes.h (see below)
+
+    field      	reserved1 		uint32_t 	currently unused field
+						 	value should be set to 0
+
+    field      	reserved2 		uint32_t	currently unused field 
+						 	value should be set to 0
+*/
+
+typedef struct ALACChannelLayoutInfo
+{
+	uint32_t	channelLayoutInfoSize;
+	uint32_t	channelLayoutInfoID;
+	uint32_t	versionFlags;
+	uint32_t	channelLayoutTag;	
+	uint32_t	reserved1;	
+	uint32_t	reserved2;	
+} ALACChannelLayoutInfo;
+
+
+* Channel Layout Tags
+
+These constants will be used to describe the bitstream's channel layout. (defined in ALACAudioTypes.h)
+
+enum
+{
+   kALACChannelLayoutTag_Mono         	= (100<<16) | 1,    	// C
+   kALACChannelLayoutTag_Stereo       	= (101<<16) | 2,	// L R
+   kALACChannelLayoutTag_MPEG_3_0_B   	= (113<<16) | 3,	// C L R
+   kALACChannelLayoutTag_MPEG_4_0_B   	= (116<<16) | 4,	// C L R Cs
+   kALACChannelLayoutTag_MPEG_5_0_D	= (120<<16) | 5,    	// C L R Ls Rs
+   kALACChannelLayoutTag_MPEG_5_1_D   	= (124<<16) | 6,	// C L R Ls Rs LFE
+   kALACChannelLayoutTag_AAC_6_1      	= (142<<16) | 7,	// C L R Ls Rs Cs LFE
+   kALACChannelLayoutTag_MPEG_7_1_B	= (127<<16) | 8    	// C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
+};
+
+
+__________________________________________________________________________________________________________________________________
+__________________________________________________________________________________________________________________________________
+* Storing Apple Lossless Magic Cookie in Audio Files
+__________________________________________________________________________________________________________________________________
+__________________________________________________________________________________________________________________________________
+
+The Apple Lossless Magic Cookie is treated as opaque by file parsing code.  The 'magic cookie' vended by the encoder 
+is placed without modification into the audio file and the read from that file and passed (unmodified) to the decoder.
+
+__________________________________________________________________________________________________________________________________
+* CAF File
+
+In a CAF file (Core Audio File), the 'magic cookie' is stored in CAF's Magic Cookie chunk ('kuki').
+
+__________________________________________________________________________________________________________________________________
+* MP4/M4A File
+
+In an MP4/M4A file, the 'magic cookie' is encapsulated in the AudioSample entry of a Sound Description box ('stsd').  
+An ISO style full box header to describe the ALACSpecificConfig portion is appended to the AudioSampleEntry, followed by the 
+'magic cookie' as it is vended by the encoder. 
+
+(All fields are stored in big-endian order: see ISO/IEC 14496-12 for a full description of the SoundDescription and AudioSampleEntry boxes, etc.)
+
+---------------- SoundDescriptionBox (FullBox) ----------------------------
+
+		SampleEntrySize		 	// = sizeof(SoundDescriptionBox)(16) + sizeof (AudioSampleEntry)(AudioSampleEntry.SampleEntrySize)
+		SampleEntryType			// = 'stsd'
+		VersionFlags 			// = 0
+		EntryCount			// = 1
+
+---------------- Audio Sample Entry (REQUIRED) -----------------------------
+
+		SampleEntrySize 		// sizeof(AudioSampleEntry)(36) + sizeof(full ISO box header)(12) + sizeof(Apple Lossless Magic Cookie)
+		SampleEntryType			// = 'alac', specifies that the AudioSampleEntry describes an Apple Lossless bitstream
+		mReserved[6]			// = 0
+		dref index			// = 1
+		reserved[2]			// = 0
+		channel count			// = number of channels as a uint_16 value
+		sample size			// = source pcm bitdepth (example = 16bit source pcm)
+		predefined			// = 0
+		reserved			// = 0
+		sample rate			// sample rate as a uint_32 value
+
+     Appended to AudioSampleEntry:
+
+		ALAC Specific Info Size		// uint_32 value, = 36 (12 + sizeof(ALACSpecificConfig))
+		ALAC Specific Info ID		// uint_32 value, = 'alac', format ID which matches the Audio Sample Entry SampleEntryType field
+		Version Flags			// uint_32 value, = 0		
+
+		Apple Lossless Magic Cookie	// 'magic cookie' vended from ALAC encoder (24 or 48 Bytes)
+
+__________________________________________________________________________________________________________________________________
+__________________________________________________________________________________________________________________________________
+* Compatibility
+__________________________________________________________________________________________________________________________________
+__________________________________________________________________________________________________________________________________
+
+Previous versions of the Apple Lossless encoder vended a different 'magic cookie'. To ensure compatibility, the Apple Lossless decoder 
+must be prepared to parse a 'magic cookie' in the format described below. Note that the 'magic cookie' defined above is 
+encapsulated in the following method and can be extracted as a contiguous set of bytes.
+
+
+---------------- Format Atom (12 bytes) --------------------------------
+(uint_32)		Format Atom Size		// = 12
+(uint_32)		Channel Layout Info ID		// = 'frma'	
+(uint_32)		Format Type			// = 'alac'	
+	
+---------------- ALAC Specific Info (36 bytes) (required) --------------
+(uint_32)		ALAC Specific Info Size		// = 36 (12 + sizeof(ALACSpecificConfig))
+(uint_32)		ALAC Specific Info ID		// = 'alac', format ID which matches the Audio Sample Entry SampleEntryType field
+(uint_32)		Version Flags			// = 0		
+
+	[ Apple Lossless Magic Cookie (see above) ]
+
+---------------- Terminator Atom (8 bytes) -----------------------------
+(uint_32)		Channel Layout Info Size	// = 8	
+(uint_32)		Channel Layout Info ID		// = 0	
+
+
+

+ 9 - 0
components/spotify/cspot/bell/external/alac/CONTRIBUTING.md

@@ -0,0 +1,9 @@
+By submitting a request, you represent that you have the right to license
+your contribution to the community, and agree that your contributions are
+licensed under the [Apache License Version 2.0](LICENSE).
+
+For existing files modified by your request, you represent that you have
+retained any existing copyright notices and licensing terms. For each new
+file in your request, you represent that you have added to the file a
+copyright notice (including the year and the copyright owner's name) and
+ALAC's licensing terms.

+ 53 - 0
components/spotify/cspot/bell/external/alac/LICENSE

@@ -0,0 +1,53 @@
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+
+You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+
+If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.

+ 9 - 0
components/spotify/cspot/bell/external/alac/PULL_REQUEST_TEMPLATE.md

@@ -0,0 +1,9 @@
+By submitting a request, you represent that you have the right to license
+your contribution to the community, and agree that your contributions are
+licensed under the [Apache License Version 2.0](LICENSE).
+
+For existing files modified by your request, you represent that you have
+retained any existing copyright notices and licensing terms. For each new
+file in your request, you represent that you have added to the file a
+copyright notice (including the year and the copyright owner's name) and
+ALAC's licensing terms.

+ 44 - 0
components/spotify/cspot/bell/external/alac/ReadMe.txt

@@ -0,0 +1,44 @@
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+The Apple Lossless Format
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+Apple Lossless supports the following features. Not all of these are implemented in alacconvert, though they are in the codec code provided.
+
+1. Bit depths 16, 20, 24 and 32 bits.
+2. Any arbitrary integer sample rate from 1 to 384,000 Hz. In theory rates up to 4,294,967,295 (2^32 - 1) Hz could be supported.
+3. From one to eight channels are supported. Channel orders for the supported formats are described as:
+	Num Chan	Order
+	1 		mono
+	2 		stereo (Left, Right)
+	3 		MPEG 3.0 B (Center, Left, Right)
+	4 		MPEG 4.0 B (Center, Left, Right, Center Surround)
+	5 		MPEG 5.0 D (Center, Left, Right, Left Surround, Right Surround)
+	6 		MPEG 5.1 D (Center, Left, Right, Left Surround, Right Surround, Low Frequency Effects)
+	7 		Apple AAC 6.1 (Center, Left, Right, Left Surround, Right Surround, Center Surround, Low Frequency Effects)
+	8 		MPEG 7.1 B (Center, Left Center, Right Center, Left, Right, Left Surround, Right Surround,  Low Frequency Effects)
+4. Packet size defaults to 4096 sample frames of audio per packet. Other packet sizes are certainly possible. However, non-default packet sizes are not guaranteed to work properly on all hardware devices that support Apple Lossless. Packets above 16,384 sample frames are not supported.
+
+
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+This package contains the sources for the Apple Lossless (ALAC) encoder and decoder.
+
+The "codec" directory contains all the sources necessary for a functioning codec. Also includes is a makefile that will build libalac.a on a UNIX/Linux machine.
+
+- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ALACconvert
+
+The convert-utility directory contains sources to build alacconvert which is a simple utility that demonstrates how to use the included ALAC encoder and decoder.
+
+alacconvert supports the following formats:
+
+1. 16- or 24-bit mono or stereo .wav files where the data is little endian integer. Extended WAVE format chunks are not handled.
+2. 16- or 24-bit mono or stereo .caf (Core Audio Format) files as well as certain multi-channel configurations where the data is big or little endian integer. It does no channel order manipulation.
+3. ALAC .caf files.
+
+Three project are provided to build a command line utility called alacconvert that converts cpm data to ALAC or vice versa. A Mac OS X Xcode project, A Windows Visual Studio project, and a generic UNIX/Linux make file.
+
+Note: When building on Windows, if you are using a version of Visual Studio before Visual Studio 2010, <stdint.h> is not installed. You will need to acquire this file on your own. It can be put in the same directory as the project.
+
+
+

+ 202 - 0
components/spotify/cspot/bell/external/alac/codec/ALACAudioTypes.h

@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACAudioTypes.h
+*/
+
+#ifndef ALACAUDIOTYPES_H
+#define ALACAUDIOTYPES_H
+
+#if PRAGMA_ONCE
+#pragma once
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if PRAGMA_STRUCT_ALIGN
+    #pragma options align=mac68k
+#elif PRAGMA_STRUCT_PACKPUSH
+    #pragma pack(push, 2)
+#elif PRAGMA_STRUCT_PACK
+    #pragma pack(2)
+#endif
+
+#include <stdint.h>
+
+#if defined(__ppc__)
+#define TARGET_RT_BIG_ENDIAN 1
+#elif defined(__ppc64__)
+#define TARGET_RT_BIG_ENDIAN 1
+#endif
+
+#define kChannelAtomSize 12
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wmultichar"
+    
+enum 
+{
+    kALAC_UnimplementedError   = -4,
+    kALAC_FileNotFoundError    = -43,
+    kALAC_ParamError           = -50,
+    kALAC_MemFullError         = -108
+};
+
+enum
+{
+    kALACFormatAppleLossless = 'alac',
+    kALACFormatLinearPCM = 'lpcm'
+};
+
+enum
+{
+    kALACMaxChannels	= 8,
+    kALACMaxEscapeHeaderBytes = 8,
+    kALACMaxSearches	= 16,
+    kALACMaxCoefs		= 16,
+    kALACDefaultFramesPerPacket = 4096
+};
+
+typedef uint32_t ALACChannelLayoutTag;
+
+enum
+{
+    kALACFormatFlagIsFloat                     = (1 << 0),     // 0x1
+    kALACFormatFlagIsBigEndian                 = (1 << 1),     // 0x2
+    kALACFormatFlagIsSignedInteger             = (1 << 2),     // 0x4
+    kALACFormatFlagIsPacked                    = (1 << 3),     // 0x8
+    kALACFormatFlagIsAlignedHigh               = (1 << 4),     // 0x10
+};
+
+enum
+{
+#if TARGET_RT_BIG_ENDIAN
+    kALACFormatFlagsNativeEndian       = kALACFormatFlagIsBigEndian
+#else
+    kALACFormatFlagsNativeEndian       = 0
+#endif
+};
+
+// this is required to be an IEEE 64bit float
+typedef double alac_float64_t;
+
+// These are the Channel Layout Tags used in the Channel Layout Info portion of the ALAC magic cookie
+enum
+{
+    kALACChannelLayoutTag_Mono          = (100<<16) | 1,    // C
+    kALACChannelLayoutTag_Stereo        = (101<<16) | 2,	// L R
+    kALACChannelLayoutTag_MPEG_3_0_B    = (113<<16) | 3,	// C L R
+    kALACChannelLayoutTag_MPEG_4_0_B    = (116<<16) | 4,	// C L R Cs
+    kALACChannelLayoutTag_MPEG_5_0_D    = (120<<16) | 5,    // C L R Ls Rs
+    kALACChannelLayoutTag_MPEG_5_1_D    = (124<<16) | 6,	// C L R Ls Rs LFE
+    kALACChannelLayoutTag_AAC_6_1       = (142<<16) | 7,	// C L R Ls Rs Cs LFE
+    kALACChannelLayoutTag_MPEG_7_1_B	= (127<<16) | 8     // C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
+};
+
+// ALAC currently only utilizes these channels layouts. There is a one for one correspondance between a
+// given number of channels and one of these layout tags
+static const ALACChannelLayoutTag	ALACChannelLayoutTags[kALACMaxChannels] =
+{
+    kALACChannelLayoutTag_Mono,         // C
+    kALACChannelLayoutTag_Stereo,		// L R
+    kALACChannelLayoutTag_MPEG_3_0_B,	// C L R
+    kALACChannelLayoutTag_MPEG_4_0_B,	// C L R Cs
+    kALACChannelLayoutTag_MPEG_5_0_D,	// C L R Ls Rs
+    kALACChannelLayoutTag_MPEG_5_1_D,	// C L R Ls Rs LFE
+    kALACChannelLayoutTag_AAC_6_1,		// C L R Ls Rs Cs LFE
+    kALACChannelLayoutTag_MPEG_7_1_B	// C Lc Rc L R Ls Rs LFE    (doc: IS-13818-7 MPEG2-AAC)
+};
+
+// AudioChannelLayout from CoreAudioTypes.h. We never need the AudioChannelDescription so we remove it
+struct ALACAudioChannelLayout
+{
+    ALACChannelLayoutTag          mChannelLayoutTag;
+    uint32_t                      mChannelBitmap;
+    uint32_t                      mNumberChannelDescriptions;
+};
+typedef struct ALACAudioChannelLayout ALACAudioChannelLayout;
+
+struct AudioFormatDescription
+{
+    alac_float64_t mSampleRate;
+    uint32_t  mFormatID;
+    uint32_t  mFormatFlags;
+    uint32_t  mBytesPerPacket;
+    uint32_t  mFramesPerPacket;
+    uint32_t  mBytesPerFrame;
+    uint32_t  mChannelsPerFrame;
+    uint32_t  mBitsPerChannel;
+    uint32_t  mReserved;
+};
+typedef struct AudioFormatDescription  AudioFormatDescription;
+
+/* Lossless Definitions */
+
+enum
+{
+	kALACCodecFormat		= 'alac',
+	kALACVersion			= 0,
+	kALACCompatibleVersion	= kALACVersion,
+	kALACDefaultFrameSize	= 4096
+};
+
+// note: this struct is wrapped in an 'alac' atom in the sample description extension area
+// note: in QT movies, it will be further wrapped in a 'wave' atom surrounded by 'frma' and 'term' atoms
+typedef struct ALACSpecificConfig
+{
+	uint32_t				frameLength;
+	uint8_t					compatibleVersion;
+	uint8_t					bitDepth;							// max 32
+	uint8_t					pb;									// 0 <= pb <= 255
+	uint8_t					mb;
+	uint8_t					kb;
+	uint8_t					numChannels;
+	uint16_t				maxRun;
+	uint32_t				maxFrameBytes;
+	uint32_t				avgBitRate;
+	uint32_t				sampleRate;
+
+} ALACSpecificConfig;
+
+
+// The AudioChannelLayout atom type is not exposed yet so define it here
+enum
+{
+	AudioChannelLayoutAID = 'chan'
+};
+
+#pragma GCC diagnostic pop
+
+#if PRAGMA_STRUCT_ALIGN
+    #pragma options align=reset
+#elif PRAGMA_STRUCT_PACKPUSH
+    #pragma pack(pop)
+#elif PRAGMA_STRUCT_PACK
+    #pragma pack()
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* ALACAUDIOTYPES_H */

+ 260 - 0
components/spotify/cspot/bell/external/alac/codec/ALACBitUtilities.c

@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*=============================================================================
+    File:		ALACBitUtilities.c
+
+	$NoKeywords: $
+=============================================================================*/
+
+#include <stdio.h>
+#include "ALACBitUtilities.h"
+
+// BitBufferInit
+//
+void BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize )
+{
+	bits->cur		= buffer;
+	bits->end		= bits->cur + byteSize;
+	bits->bitIndex	= 0;
+	bits->byteSize	= byteSize;
+}
+
+// BitBufferRead
+//
+uint32_t BitBufferRead( BitBuffer * bits, uint8_t numBits )
+{
+	uint32_t		returnBits;
+	
+	//Assert( numBits <= 16 );
+
+	returnBits = ((uint32_t)bits->cur[0] << 16) | ((uint32_t)bits->cur[1] << 8) | ((uint32_t)bits->cur[2]);
+	returnBits = returnBits << bits->bitIndex;
+	returnBits &= 0x00FFFFFF;
+	
+	bits->bitIndex += numBits;
+	
+	returnBits = returnBits >> (24 - numBits);
+	
+	bits->cur		+= (bits->bitIndex >> 3);
+	bits->bitIndex	&= 7;
+	
+	//Assert( bits->cur <= bits->end );
+	
+	return returnBits;
+}
+
+// BitBufferReadSmall
+//
+// Reads up to 8 bits
+uint8_t BitBufferReadSmall( BitBuffer * bits, uint8_t numBits )
+{
+	uint16_t		returnBits;
+	
+	//Assert( numBits <= 8 );
+	
+	returnBits = (bits->cur[0] << 8) | bits->cur[1];
+	returnBits = returnBits << bits->bitIndex;
+	
+	bits->bitIndex += numBits;
+	
+	returnBits = returnBits >> (16 - numBits);
+	
+	bits->cur		+= (bits->bitIndex >> 3);
+	bits->bitIndex	&= 7;
+	
+	//Assert( bits->cur <= bits->end );
+	
+	return (uint8_t)returnBits;
+}
+
+// BitBufferReadOne
+//
+// Reads one byte
+uint8_t BitBufferReadOne( BitBuffer * bits )
+{
+	uint8_t		returnBits;
+
+	returnBits = (bits->cur[0] >> (7 - bits->bitIndex)) & 1;
+
+	bits->bitIndex++;
+	
+	bits->cur		+= (bits->bitIndex >> 3);
+	bits->bitIndex	&= 7;
+	
+	//Assert( bits->cur <= bits->end );
+	
+	return returnBits;
+}
+
+// BitBufferPeek
+//
+uint32_t BitBufferPeek( BitBuffer * bits, uint8_t numBits )
+{
+	return ((((((uint32_t) bits->cur[0] << 16) | ((uint32_t) bits->cur[1] << 8) |
+			((uint32_t) bits->cur[2])) << bits->bitIndex) & 0x00FFFFFF) >> (24 - numBits));
+}
+
+// BitBufferPeekOne
+//
+uint32_t BitBufferPeekOne( BitBuffer * bits )
+{
+	return ((bits->cur[0] >> (7 - bits->bitIndex)) & 1);
+}
+
+// BitBufferUnpackBERSize
+//
+uint32_t BitBufferUnpackBERSize( BitBuffer * bits )
+{
+	uint32_t		size;
+	uint8_t		tmp;
+	
+	for ( size = 0, tmp = 0x80u; tmp &= 0x80u; size = (size << 7u) | (tmp & 0x7fu) )
+		tmp = (uint8_t) BitBufferReadSmall( bits, 8 );
+	
+	return size;
+}
+
+// BitBufferGetPosition
+//
+uint32_t BitBufferGetPosition( BitBuffer * bits )
+{
+	uint8_t *		begin;
+	
+	begin = bits->end - bits->byteSize;
+	
+	return ((uint32_t)(bits->cur - begin) * 8) + bits->bitIndex;
+}
+
+// BitBufferByteAlign
+//
+void BitBufferByteAlign( BitBuffer * bits, int32_t addZeros )
+{
+	// align bit buffer to next byte boundary, writing zeros if requested
+	if ( bits->bitIndex == 0 )
+		return;
+
+	if ( addZeros )
+		BitBufferWrite( bits, 0, 8 - bits->bitIndex );
+	else	
+		BitBufferAdvance( bits, 8 - bits->bitIndex );	
+}
+
+// BitBufferAdvance
+//
+void BitBufferAdvance( BitBuffer * bits, uint32_t numBits )
+{
+	if ( numBits )
+	{
+		bits->bitIndex += numBits;
+		bits->cur += (bits->bitIndex >> 3);
+		bits->bitIndex &= 7;
+	}
+}
+
+// BitBufferRewind
+//
+void BitBufferRewind( BitBuffer * bits, uint32_t numBits )
+{
+	uint32_t	numBytes;
+	
+	if ( numBits == 0 )
+		return;
+	
+	if ( bits->bitIndex >= numBits )
+	{
+		bits->bitIndex -= numBits;
+		return;
+	}
+	
+	numBits -= bits->bitIndex;
+	bits->bitIndex = 0;
+
+	numBytes	= numBits / 8;
+	numBits		= numBits % 8;
+	
+	bits->cur -= numBytes;
+	
+	if ( numBits > 0 )
+	{
+		bits->bitIndex = 8 - numBits;
+		bits->cur--;
+	}
+	
+	if ( bits->cur < (bits->end - bits->byteSize) )
+	{
+		//DebugCMsg("BitBufferRewind: Rewound too far.");
+
+		bits->cur		= (bits->end - bits->byteSize);
+		bits->bitIndex	= 0;
+	}
+}
+
+// BitBufferWrite
+//
+void BitBufferWrite( BitBuffer * bits, uint32_t bitValues, uint32_t numBits )
+{
+	uint32_t				invBitIndex;
+	
+	RequireAction( bits != nil, return; );
+	RequireActionSilent( numBits > 0, return; );
+
+	invBitIndex = 8 - bits->bitIndex;
+
+	while ( numBits > 0 )
+	{
+		uint32_t		tmp;
+		uint8_t		shift;
+		uint8_t		mask;
+		uint32_t		curNum;
+
+		curNum = MIN( invBitIndex, numBits );
+
+		tmp = bitValues >> (numBits - curNum);
+
+		shift  = (uint8_t)(invBitIndex - curNum);
+		mask   = 0xffu >> (8 - curNum);		// must be done in two steps to avoid compiler sequencing ambiguity
+		mask <<= shift;
+
+		bits->cur[0] = (bits->cur[0] & ~mask) | (((uint8_t) tmp << shift)  & mask);
+		numBits -= curNum;
+
+		// increment to next byte if need be
+		invBitIndex -= curNum;
+		if ( invBitIndex == 0 )
+		{
+			invBitIndex = 8;
+			bits->cur++;
+		}
+	}
+
+	bits->bitIndex = 8 - invBitIndex;
+}
+
+void	BitBufferReset( BitBuffer * bits )
+//void BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize )
+{
+	bits->cur		= bits->end - bits->byteSize;
+    bits->bitIndex	= 0;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif

+ 104 - 0
components/spotify/cspot/bell/external/alac/codec/ALACBitUtilities.h

@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*=============================================================================
+    File:		ALACBitUtilities.h
+	
+	$NoKeywords: $
+=============================================================================*/
+
+#ifndef __ALACBITUTILITIES_H
+#define __ALACBITUTILITIES_H
+
+#include <stdint.h>
+
+#ifndef MIN
+#define MIN(x, y) 			( (x)<(y) ?(x) :(y) )
+#endif //MIN
+#ifndef MAX
+#define MAX(x, y) 			( (x)>(y) ?(x): (y) )
+#endif //MAX
+
+#ifndef nil
+#define nil NULL
+#endif
+
+#define RequireAction(condition, action)			if (!(condition)) { action }
+#define RequireActionSilent(condition, action)			if (!(condition)) { action }
+#define RequireNoErr(condition, action)			if ((condition)) { action }
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+    ALAC_noErr = 0
+};
+    
+
+typedef enum
+{
+    
+    ID_SCE = 0,						/* Single Channel Element   */
+    ID_CPE = 1,						/* Channel Pair Element     */
+    ID_CCE = 2,						/* Coupling Channel Element */
+    ID_LFE = 3,						/* LFE Channel Element      */
+    ID_DSE = 4,						/* not yet supported        */
+    ID_PCE = 5,
+    ID_FIL = 6,
+    ID_END = 7
+} ELEMENT_TYPE;
+
+// types
+typedef struct BitBuffer
+{
+	uint8_t *		cur;
+	uint8_t *		end;
+	uint32_t		bitIndex;
+	uint32_t		byteSize;
+	
+} BitBuffer;
+
+/*
+	BitBuffer routines
+	- these routines take a fixed size buffer and read/write to it
+	- bounds checking must be done by the client
+*/
+void	BitBufferInit( BitBuffer * bits, uint8_t * buffer, uint32_t byteSize );
+uint32_t	BitBufferRead( BitBuffer * bits, uint8_t numBits );   // note: cannot read more than 16 bits at a time
+uint8_t	BitBufferReadSmall( BitBuffer * bits, uint8_t numBits );
+uint8_t	BitBufferReadOne( BitBuffer * bits );
+uint32_t	BitBufferPeek( BitBuffer * bits, uint8_t numBits );   // note: cannot read more than 16 bits at a time
+uint32_t	BitBufferPeekOne( BitBuffer * bits );
+uint32_t	BitBufferUnpackBERSize( BitBuffer * bits );
+uint32_t	BitBufferGetPosition( BitBuffer * bits );
+void	BitBufferByteAlign( BitBuffer * bits, int32_t addZeros );
+void	BitBufferAdvance( BitBuffer * bits, uint32_t numBits );
+void	BitBufferRewind( BitBuffer * bits, uint32_t numBits );
+void	BitBufferWrite( BitBuffer * bits, uint32_t value, uint32_t numBits );
+void	BitBufferReset( BitBuffer * bits);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* __BITUTILITIES_H */

+ 737 - 0
components/spotify/cspot/bell/external/alac/codec/ALACDecoder.cpp

@@ -0,0 +1,737 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACDecoder.cpp
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ALACDecoder.h"
+
+#include "dplib.h"
+#include "aglib.h"
+#include "matrixlib.h"
+
+#include "ALACBitUtilities.h"
+#include "EndianPortable.h"
+
+#if (__GNUC__) > 4 || defined (__APPLE__)
+#pragma GCC diagnostic ignored "-Wunused-const-variable"
+#endif
+#if !defined(__APPLE__) 
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+
+// constants/data
+const uint32_t kMaxBitDepth = 32;			// max allowed bit depth is 32
+
+
+// prototypes
+static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride );
+static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride );
+static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride );
+
+/*
+	Constructor
+*/
+ALACDecoder::ALACDecoder() :
+	mMixBufferU( nil ),
+	mMixBufferV( nil ),
+	mPredictor( nil ),
+	mShiftBuffer( nil )
+{
+	memset( &mConfig, 0, sizeof(mConfig) );
+}
+
+/*
+	Destructor
+*/
+ALACDecoder::~ALACDecoder()
+{
+	// delete the matrix mixing buffers
+	if ( mMixBufferU )
+    {
+		free(mMixBufferU);
+        mMixBufferU = NULL;
+    }
+	if ( mMixBufferV )
+    {
+		free(mMixBufferV);
+        mMixBufferV = NULL;
+    }
+	
+	// delete the dynamic predictor's "corrector" buffer
+	// - note: mShiftBuffer shares memory with this buffer
+	if ( mPredictor )
+    {
+		free(mPredictor);
+        mPredictor = NULL;
+    }
+}
+
+/*
+	Init()
+	- initialize the decoder with the given configuration
+*/
+int32_t ALACDecoder::Init( void * inMagicCookie, uint32_t inMagicCookieSize )
+{
+	int32_t		status = ALAC_noErr;
+    ALACSpecificConfig theConfig;
+    uint8_t * theActualCookie = (uint8_t *)inMagicCookie;
+    uint32_t theCookieBytesRemaining = inMagicCookieSize;
+
+    // For historical reasons the decoder needs to be resilient to magic cookies vended by older encoders.
+    // As specified in the ALACMagicCookieDescription.txt document, there may be additional data encapsulating 
+    // the ALACSpecificConfig. This would consist of format ('frma') and 'alac' atoms which precede the
+    // ALACSpecificConfig. 
+    // See ALACMagicCookieDescription.txt for additional documentation concerning the 'magic cookie'
+    
+    // skip format ('frma') atom if present
+    if (theActualCookie[4] == 'f' && theActualCookie[5] == 'r' && theActualCookie[6] == 'm' && theActualCookie[7] == 'a')
+    {
+        theActualCookie += 12;
+        theCookieBytesRemaining -= 12;
+    }
+    
+    // skip 'alac' atom header if present
+    if (theActualCookie[4] == 'a' && theActualCookie[5] == 'l' && theActualCookie[6] == 'a' && theActualCookie[7] == 'c')
+    {
+        theActualCookie += 12;
+        theCookieBytesRemaining -= 12;
+    }
+
+    // read the ALACSpecificConfig
+    if (theCookieBytesRemaining >= sizeof(ALACSpecificConfig))
+    {
+        theConfig.frameLength = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->frameLength);
+        theConfig.compatibleVersion = ((ALACSpecificConfig *)theActualCookie)->compatibleVersion;
+        theConfig.bitDepth = ((ALACSpecificConfig *)theActualCookie)->bitDepth;
+        theConfig.pb = ((ALACSpecificConfig *)theActualCookie)->pb;
+        theConfig.mb = ((ALACSpecificConfig *)theActualCookie)->mb;
+        theConfig.kb = ((ALACSpecificConfig *)theActualCookie)->kb;
+        theConfig.numChannels = ((ALACSpecificConfig *)theActualCookie)->numChannels;
+        theConfig.maxRun = Swap16BtoN(((ALACSpecificConfig *)theActualCookie)->maxRun);
+        theConfig.maxFrameBytes = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->maxFrameBytes);
+        theConfig.avgBitRate = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->avgBitRate);
+        theConfig.sampleRate = Swap32BtoN(((ALACSpecificConfig *)theActualCookie)->sampleRate);
+
+        mConfig = theConfig;
+        
+        RequireAction( mConfig.compatibleVersion <= kALACVersion, return kALAC_ParamError; );
+
+        // allocate mix buffers
+        mMixBufferU = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
+        mMixBufferV = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
+
+        // allocate dynamic predictor buffer
+        mPredictor = (int32_t *) calloc( mConfig.frameLength * sizeof(int32_t), 1 );
+
+        // "shift off" buffer shares memory with predictor buffer
+        mShiftBuffer = (uint16_t *) mPredictor;
+        
+        RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) && (mPredictor != nil),
+                        status = kALAC_MemFullError; goto Exit; );
+     }
+    else
+    {
+        status = kALAC_ParamError;
+    }
+
+    // skip to Channel Layout Info
+    // theActualCookie += sizeof(ALACSpecificConfig);
+    
+    // Currently, the Channel Layout Info portion of the magic cookie (as defined in the 
+    // ALACMagicCookieDescription.txt document) is unused by the decoder. 
+    
+Exit:
+	return status;
+}
+
+/*
+	Decode()
+	- the decoded samples are interleaved into the output buffer in the order they arrive in
+	  the bitstream
+*/
+int32_t ALACDecoder::Decode( BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples )
+{
+	BitBuffer			shiftBits;
+	uint32_t            bits1, bits2;
+	uint8_t				tag;
+	uint8_t				elementInstanceTag;
+	AGParamRec			agParams;
+	uint32_t				channelIndex;
+	int16_t				coefsU[32];		// max possible size is 32 although NUMCOEPAIRS is the current limit
+	int16_t				coefsV[32];
+	uint8_t				numU, numV;
+	uint8_t				mixBits;
+	int8_t				mixRes;
+	uint16_t			unusedHeader;
+	uint8_t				escapeFlag;
+	uint32_t			chanBits;
+	uint8_t				bytesShifted;
+	uint32_t			shift;
+	uint8_t				modeU, modeV;
+	uint32_t			denShiftU, denShiftV;
+	uint16_t			pbFactorU, pbFactorV;
+	uint16_t			pb;
+	int16_t *			samples;
+	int16_t *			out16;
+	uint8_t *			out20;
+	uint8_t *			out24;
+	int32_t *			out32;
+	uint8_t				headerByte;
+	uint8_t				partialFrame;
+	uint32_t			extraBits;
+	int32_t				val;
+	uint32_t			i, j;
+	int32_t             status;
+	
+	RequireAction( (bits != nil) && (sampleBuffer != nil) && (outNumSamples != nil), return kALAC_ParamError; );
+	RequireAction( numChannels > 0, return kALAC_ParamError; );
+
+	mActiveElements = 0;
+	channelIndex	= 0;
+	
+	samples = (int16_t *) sampleBuffer;
+
+	status = ALAC_noErr;
+	*outNumSamples = numSamples;
+
+	while ( status == ALAC_noErr )
+	{
+		// bail if we ran off the end of the buffer
+    	RequireAction( bits->cur < bits->end, status = kALAC_ParamError; goto Exit; );
+
+		// copy global decode params for this element
+		pb = mConfig.pb;
+
+		// read element tag
+		tag = BitBufferReadSmall( bits, 3 );
+		switch ( tag )
+		{
+			case ID_SCE:
+			case ID_LFE:
+			{
+				// mono/LFE channel
+				elementInstanceTag = BitBufferReadSmall( bits, 4 );
+				mActiveElements |= (1u << elementInstanceTag);
+
+				// read the 12 unused header bits
+				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
+				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );
+
+				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
+				headerByte = (uint8_t) BitBufferRead( bits, 4 );
+				
+				partialFrame = headerByte >> 3;
+				
+				bytesShifted = (headerByte >> 1) & 0x3u;
+				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );
+
+				shift = bytesShifted * 8;
+
+				escapeFlag = headerByte & 0x1;
+
+				chanBits = mConfig.bitDepth - (bytesShifted * 8);
+				
+				// check for partial frame to override requested numSamples
+				if ( partialFrame != 0 )
+				{
+					numSamples  = BitBufferRead( bits, 16 ) << 16;
+					numSamples |= BitBufferRead( bits, 16 );
+				}
+
+				if ( escapeFlag == 0 )
+				{
+					// compressed frame, read rest of parameters
+					mixBits	= (uint8_t) BitBufferRead( bits, 8 );
+					mixRes	= (int8_t) BitBufferRead( bits, 8 );
+					//Assert( (mixBits == 0) && (mixRes == 0) );		// no mixing for mono
+
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					modeU		= headerByte >> 4;
+					denShiftU	= headerByte & 0xfu;
+					
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					pbFactorU	= headerByte >> 5;
+					numU		= headerByte & 0x1fu;
+
+					for ( i = 0; i < numU; i++ )
+						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );
+					
+					// if shift active, skip the the shift buffer but remember where it starts
+					if ( bytesShifted != 0 )
+					{
+						shiftBits = *bits;
+						BitBufferAdvance( bits, (bytesShifted * 8) * numSamples ); 
+					}
+
+					// decompress
+					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
+					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
+					RequireNoErr( status, goto Exit; );
+
+					if ( modeU == 0 )
+					{
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+					else
+					{
+						// the special "numActive == 31" mode can be done in-place
+						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+				}
+				else
+				{
+					//Assert( bytesShifted == 0 );
+
+					// uncompressed frame, copy data into the mix buffer to use common output code
+					shift = 32 - chanBits;
+					if ( chanBits <= 16 )
+					{
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
+							val = (val << shift) >> shift;
+							mMixBufferU[i] = val;
+						}
+					}
+					else
+					{
+						// BitBufferRead() can't read more than 16 bits at a time so break up the reads
+						extraBits = chanBits - 16;
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, 16 );
+							val = (val << 16) >> shift;
+							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t) extraBits );
+						}
+					}
+
+					mixBits = mixRes = 0;
+					bits1 = chanBits * numSamples;
+					bytesShifted = 0;
+				}
+
+				// now read the shifted values into the shift buffer
+				if ( bytesShifted != 0 )
+				{
+					shift = bytesShifted * 8;
+					//Assert( shift <= 16 );
+
+					for ( i = 0; i < numSamples; i++ )
+						mShiftBuffer[i] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
+				}
+
+				// convert 32-bit integers into output buffer
+				switch ( mConfig.bitDepth )
+				{
+					case 16:
+						out16 = &((int16_t *)sampleBuffer)[channelIndex];
+						for ( i = 0, j = 0; i < numSamples; i++, j += numChannels )
+							out16[j] = (int16_t) mMixBufferU[i];
+						break;
+					case 20:
+						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						copyPredictorTo20( mMixBufferU, out20, numChannels, numSamples );
+						break;
+					case 24:
+						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						if ( bytesShifted != 0 )
+							copyPredictorTo24Shift( mMixBufferU, mShiftBuffer, out24, numChannels, numSamples, bytesShifted );
+						else
+							copyPredictorTo24( mMixBufferU, out24, numChannels, numSamples );							
+						break;
+					case 32:
+						out32 = &((int32_t *)sampleBuffer)[channelIndex];
+						if ( bytesShifted != 0 )
+							copyPredictorTo32Shift( mMixBufferU, mShiftBuffer, out32, numChannels, numSamples, bytesShifted );
+						else
+							copyPredictorTo32( mMixBufferU, out32, numChannels, numSamples);
+						break;
+				}
+
+				channelIndex += 1;
+				*outNumSamples = numSamples;
+				break;
+			}
+
+			case ID_CPE:
+			{
+				// if decoding this pair would take us over the max channels limit, bail
+				if ( (channelIndex + 2) > numChannels )
+					goto NoMoreChannels;
+
+				// stereo channel pair
+				elementInstanceTag = BitBufferReadSmall( bits, 4 );
+				mActiveElements |= (1u << elementInstanceTag);
+
+				// read the 12 unused header bits
+				unusedHeader = (uint16_t) BitBufferRead( bits, 12 );
+				RequireAction( unusedHeader == 0, status = kALAC_ParamError; goto Exit; );
+
+				// read the 1-bit "partial frame" flag, 2-bit "shift-off" flag & 1-bit "escape" flag
+				headerByte = (uint8_t) BitBufferRead( bits, 4 );
+				
+				partialFrame = headerByte >> 3;
+				
+				bytesShifted = (headerByte >> 1) & 0x3u;
+				RequireAction( bytesShifted != 3, status = kALAC_ParamError; goto Exit; );
+
+				shift = bytesShifted * 8;
+
+				escapeFlag = headerByte & 0x1;
+
+				chanBits = mConfig.bitDepth - (bytesShifted * 8) + 1;
+				
+				// check for partial frame length to override requested numSamples
+				if ( partialFrame != 0 )
+				{
+					numSamples  = BitBufferRead( bits, 16 ) << 16;
+					numSamples |= BitBufferRead( bits, 16 );
+				}
+
+				if ( escapeFlag == 0 )
+				{
+					// compressed frame, read rest of parameters
+					mixBits		= (uint8_t) BitBufferRead( bits, 8 );
+					mixRes		= (int8_t) BitBufferRead( bits, 8 );
+
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					modeU		= headerByte >> 4;
+					denShiftU	= headerByte & 0xfu;
+					
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					pbFactorU	= headerByte >> 5;
+					numU		= headerByte & 0x1fu;
+					for ( i = 0; i < numU; i++ )
+						coefsU[i] = (int16_t) BitBufferRead( bits, 16 );
+
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					modeV		= headerByte >> 4;
+					denShiftV	= headerByte & 0xfu;
+					
+					headerByte	= (uint8_t) BitBufferRead( bits, 8 );
+					pbFactorV	= headerByte >> 5;
+					numV		= headerByte & 0x1fu;
+					for ( i = 0; i < numV; i++ )
+						coefsV[i] = (int16_t) BitBufferRead( bits, 16 );
+
+					// if shift active, skip the interleaved shifted values but remember where they start
+					if ( bytesShifted != 0 )
+					{
+						shiftBits = *bits;
+						BitBufferAdvance( bits, (bytesShifted * 8) * 2 * numSamples );
+					}
+
+					// decompress and run predictor for "left" channel
+					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorU) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
+					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits1 );
+					RequireNoErr( status, goto Exit; );
+
+					if ( modeU == 0 )
+					{
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+					else
+					{
+						// the special "numActive == 31" mode can be done in-place
+						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
+						unpc_block( mPredictor, mMixBufferU, numSamples, &coefsU[0], numU, chanBits, denShiftU );
+					}
+
+					// decompress and run predictor for "right" channel
+					set_ag_params( &agParams, mConfig.mb, (pb * pbFactorV) / 4, mConfig.kb, numSamples, numSamples, mConfig.maxRun );
+					status = dyn_decomp( &agParams, bits, mPredictor, numSamples, chanBits, &bits2 );
+					RequireNoErr( status, goto Exit; );
+
+					if ( modeV == 0 )
+					{
+						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
+					}
+					else
+					{
+						// the special "numActive == 31" mode can be done in-place
+						unpc_block( mPredictor, mPredictor, numSamples, nil, 31, chanBits, 0 );
+						unpc_block( mPredictor, mMixBufferV, numSamples, &coefsV[0], numV, chanBits, denShiftV );
+					}
+				}
+				else
+				{
+					//Assert( bytesShifted == 0 );
+
+					// uncompressed frame, copy data into the mix buffers to use common output code
+					chanBits = mConfig.bitDepth;
+					shift = 32 - chanBits;
+					if ( chanBits <= 16 )
+					{
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
+							val = (val << shift) >> shift;
+							mMixBufferU[i] = val;
+
+							val = (int32_t) BitBufferRead( bits, (uint8_t) chanBits );
+							val = (val << shift) >> shift;
+							mMixBufferV[i] = val;
+						}
+					}
+					else
+					{
+						// BitBufferRead() can't read more than 16 bits at a time so break up the reads
+						extraBits = chanBits - 16;
+						for ( i = 0; i < numSamples; i++ )
+						{
+							val = (int32_t) BitBufferRead( bits, 16 );
+							val = (val << 16) >> shift;
+							mMixBufferU[i] = val | BitBufferRead( bits, (uint8_t)extraBits );
+
+							val = (int32_t) BitBufferRead( bits, 16 );
+							val = (val << 16) >> shift;
+							mMixBufferV[i] = val | BitBufferRead( bits, (uint8_t)extraBits );
+						}
+					}
+
+					bits1 = chanBits * numSamples;
+					bits2 = chanBits * numSamples;
+					mixBits = mixRes = 0;
+					bytesShifted = 0;
+				}
+
+				// now read the shifted values into the shift buffer
+				if ( bytesShifted != 0 )
+				{
+					shift = bytesShifted * 8;
+					//Assert( shift <= 16 );
+
+					for ( i = 0; i < (numSamples * 2); i += 2 )
+					{
+						mShiftBuffer[i + 0] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
+						mShiftBuffer[i + 1] = (uint16_t) BitBufferRead( &shiftBits, (uint8_t) shift );
+					}
+				}
+
+				// un-mix the data and convert to output format
+				// - note that mixRes = 0 means just interleave so we use that path for uncompressed frames
+				switch ( mConfig.bitDepth )
+				{
+					case 16:
+						out16 = &((int16_t *)sampleBuffer)[channelIndex];
+						unmix16( mMixBufferU, mMixBufferV, out16, numChannels, numSamples, mixBits, mixRes );
+						break;
+					case 20:
+						out20 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						unmix20( mMixBufferU, mMixBufferV, out20, numChannels, numSamples, mixBits, mixRes );
+						break;
+					case 24:
+						out24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+						unmix24( mMixBufferU, mMixBufferV, out24, numChannels, numSamples,
+									mixBits, mixRes, mShiftBuffer, bytesShifted );
+						break;
+					case 32:
+						out32 = &((int32_t *)sampleBuffer)[channelIndex];
+						unmix32( mMixBufferU, mMixBufferV, out32, numChannels, numSamples,
+									mixBits, mixRes, mShiftBuffer, bytesShifted );
+						break;
+				}
+
+				channelIndex += 2;
+				*outNumSamples = numSamples;
+				break;
+			}
+
+			case ID_CCE:
+			case ID_PCE:
+			{
+				// unsupported element, bail
+				//AssertNoErr( tag );
+				status = kALAC_ParamError;
+				break;
+			}
+
+			case ID_DSE:
+			{
+				// data stream element -- parse but ignore
+				status = this->DataStreamElement( bits );
+				break;
+			}
+			
+			case ID_FIL:
+			{
+				// fill element -- parse but ignore
+				status = this->FillElement( bits );
+				break;
+			}
+
+			case ID_END:
+			{
+				// frame end, all done so byte align the frame and check for overruns
+				BitBufferByteAlign( bits, false );
+				//Assert( bits->cur == bits->end );
+				goto Exit;
+			}
+		}
+
+#if ! DEBUG
+		// if we've decoded all of our channels, bail (but not in debug b/c we want to know if we're seeing bad bits)
+		// - this also protects us if the config does not match the bitstream or crap data bits follow the audio bits
+		if ( channelIndex >= numChannels )
+			break;
+#endif
+	}
+
+NoMoreChannels:
+
+	// if we get here and haven't decoded all of the requested channels, fill the remaining channels with zeros
+	for ( ; channelIndex < numChannels; channelIndex++ )
+	{
+		switch ( mConfig.bitDepth )
+		{
+			case 16:
+			{
+				int16_t *	fill16 = &((int16_t *)sampleBuffer)[channelIndex];
+				Zero16( fill16, numSamples, numChannels );
+				break;
+			}
+			case 24:
+			{
+				uint8_t *	fill24 = (uint8_t *)sampleBuffer + (channelIndex * 3);
+				Zero24( fill24, numSamples, numChannels );
+				break;
+			}
+			case 32:
+			{
+				int32_t *	fill32 = &((int32_t *)sampleBuffer)[channelIndex];
+				Zero32( fill32, numSamples, numChannels );
+				break;
+			}
+		}
+	}
+
+Exit:
+	return status;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	FillElement()
+	- they're just filler so we don't need 'em
+*/
+int32_t ALACDecoder::FillElement( BitBuffer * bits )
+{
+	int16_t		count;
+	
+	// 4-bit count or (4-bit + 8-bit count) if 4-bit count == 15
+	// - plus this weird -1 thing I still don't fully understand
+	count = BitBufferReadSmall( bits, 4 );
+	if ( count == 15 )
+		count += (int16_t) BitBufferReadSmall( bits, 8 ) - 1;
+
+	BitBufferAdvance( bits, count * 8 );
+
+	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );
+
+	return ALAC_noErr;	
+}
+
+/*
+	DataStreamElement()
+	- we don't care about data stream elements so just skip them
+*/
+int32_t ALACDecoder::DataStreamElement( BitBuffer * bits )
+{
+	uint8_t		element_instance_tag;
+	int32_t		data_byte_align_flag;
+	uint16_t		count;
+	
+	// the tag associates this data stream element with a given audio element
+	element_instance_tag = BitBufferReadSmall( bits, 4 );
+	
+	data_byte_align_flag = BitBufferReadOne( bits );
+
+	// 8-bit count or (8-bit + 8-bit count) if 8-bit count == 255
+	count = BitBufferReadSmall( bits, 8 );
+	if ( count == 255 )
+		count += BitBufferReadSmall( bits, 8 );
+
+	// the align flag means the bitstream should be byte-aligned before reading the following data bytes
+	if ( data_byte_align_flag )
+		BitBufferByteAlign( bits, false );
+
+	// skip the data bytes
+	BitBufferAdvance( bits, count * 8 );
+
+	RequireAction( bits->cur <= bits->end, return kALAC_ParamError; );
+
+	return ALAC_noErr;
+}
+
+/*
+	ZeroN()
+	- helper routines to clear out output channel buffers when decoding fewer channels than requested
+*/
+static void Zero16( int16_t * buffer, uint32_t numItems, uint32_t stride )
+{
+	if ( stride == 1 )
+	{
+		memset( buffer, 0, numItems * sizeof(int16_t) );
+	}
+	else
+	{
+		for ( uint32_t index = 0; index < (numItems * stride); index += stride )
+			buffer[index] = 0;
+	}
+}
+
+static void Zero24( uint8_t * buffer, uint32_t numItems, uint32_t stride )
+{
+	if ( stride == 1 )
+	{
+		memset( buffer, 0, numItems * 3 );
+	}
+	else
+	{
+		for ( uint32_t index = 0; index < (numItems * stride * 3); index += (stride * 3) )
+		{
+			buffer[index + 0] = 0;
+			buffer[index + 1] = 0;
+			buffer[index + 2] = 0;
+		}
+	}
+}
+
+static void Zero32( int32_t * buffer, uint32_t numItems, uint32_t stride )
+{
+	if ( stride == 1 )
+	{
+		memset( buffer, 0, numItems * sizeof(int32_t) );
+	}
+	else
+	{
+		for ( uint32_t index = 0; index < (numItems * stride); index += stride )
+			buffer[index] = 0;
+	}
+}

+ 65 - 0
components/spotify/cspot/bell/external/alac/codec/ALACDecoder.h

@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACDecoder.h
+*/
+
+#ifndef _ALACDECODER_H
+#define _ALACDECODER_H
+
+#if PRAGMA_ONCE
+#pragma once
+#endif
+
+#include <stdint.h>
+
+#include "ALACAudioTypes.h"
+
+struct BitBuffer;
+
+class ALACDecoder
+{
+	public:
+		ALACDecoder();
+		~ALACDecoder();
+
+		int32_t	Init( void * inMagicCookie, uint32_t inMagicCookieSize );
+		int32_t	Decode( struct BitBuffer * bits, uint8_t * sampleBuffer, uint32_t numSamples, uint32_t numChannels, uint32_t * outNumSamples );
+
+	public:
+		// decoding parameters (public for use in the analyzer)
+		ALACSpecificConfig		mConfig;
+
+	protected:
+		int32_t	FillElement( struct BitBuffer * bits );
+		int32_t	DataStreamElement( struct BitBuffer * bits );
+
+		uint16_t					mActiveElements;
+
+		// decoding buffers
+		int32_t *				mMixBufferU;
+		int32_t *				mMixBufferV;
+		int32_t *				mPredictor;
+		uint16_t *				mShiftBuffer;	// note: this points to mPredictor's memory but different
+												//		 variable for clarity and type difference
+};
+
+#endif	/* _ALACDECODER_H */

+ 1432 - 0
components/spotify/cspot/bell/external/alac/codec/ALACEncoder.cpp

@@ -0,0 +1,1432 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACEncoder.cpp
+*/
+
+// build stuff
+#define VERBOSE_DEBUG		0
+
+// headers
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ALACEncoder.h"
+
+#include "aglib.h"
+#include "dplib.h"
+#include "matrixlib.h"
+
+#include "ALACBitUtilities.h"
+#include "ALACAudioTypes.h"
+#include "EndianPortable.h"
+
+#if (__GNUC__) > 4 || defined (__APPLE__)
+#pragma GCC diagnostic ignored "-Wunused-const-variable"
+#endif
+#if !defined(__APPLE__) 
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif
+
+// Note: in C you can't typecast to a 2-dimensional array pointer but that's what we need when
+// picking which coefs to use so we declare this typedef b/c we *can* typecast to this type
+typedef int16_t (*SearchCoefs)[kALACMaxCoefs];
+
+// defines/constants
+const uint32_t kALACEncoderMagic	= 'dpge';
+const uint32_t kMaxSampleSize		= 32;			// max allowed bit width is 32
+const uint32_t kDefaultMixBits	= 2;
+const uint32_t kDefaultMixRes		= 0;
+const uint32_t kMaxRes			= 4;
+const uint32_t kDefaultNumUV		= 8;
+const uint32_t kMinUV				= 4;
+const uint32_t kMaxUV				= 8;
+
+// static functions
+#if VERBOSE_DEBUG
+static void AddFiller( BitBuffer * bits, int32_t numBytes );
+#endif
+
+
+/*
+	Map Format: 3-bit field per channel which is the same as the "element tag" that should be placed
+				at the beginning of the frame for that channel.  Indicates whether SCE, CPE, or LFE.
+				Each particular field is accessed via the current channel index.  Note that the channel
+				index increments by two for channel pairs.
+				
+	For example:
+	
+			C L R 3-channel input		= (ID_CPE << 3) | (ID_SCE)
+				index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
+				index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)
+
+			C L R Ls Rs LFE 5.1-channel input = (ID_LFE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
+				index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3)
+				index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3)
+				index 3 value = (map & (0x7ul << (3 * 3))) >> (3 * 3)
+				index 5 value = (map & (0x7ul << (5 * 3))) >> (5 * 3)
+				index 7 value = (map & (0x7ul << (7 * 3))) >> (7 * 3)
+*/
+static const uint32_t	sChannelMaps[kALACMaxChannels] =
+{
+	ID_SCE,
+	ID_CPE,
+	(ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 18) | (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE),
+	(ID_SCE << 21) | (ID_CPE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE)
+};
+
+static const uint32_t sSupportediPodSampleRates[] =
+{
+	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
+};
+
+/*
+	Constructor
+*/
+ALACEncoder::ALACEncoder() :
+	mBitDepth( 0 ),
+    mFastMode( 0 ),
+	mMixBufferU( nil ),
+	mMixBufferV( nil ),
+	mPredictorU( nil ),
+	mPredictorV( nil ),
+	mShiftBufferUV( nil ),
+	mWorkBuffer( nil ),
+
+
+	mTotalBytesGenerated( 0 ),
+	mAvgBitRate( 0 ),
+	mMaxFrameBytes( 0 )
+{
+	// overrides
+	mFrameSize = kALACDefaultFrameSize;
+}
+
+/*
+	Destructor
+*/
+ALACEncoder::~ALACEncoder()
+{
+	// delete the matrix mixing buffers
+	if ( mMixBufferU )
+    {
+		free(mMixBufferU);
+        mMixBufferU = NULL;
+    }
+	if ( mMixBufferV )
+    {
+		free(mMixBufferV);
+        mMixBufferV = NULL;
+    }
+	
+	// delete the dynamic predictor's "corrector" buffers
+	if ( mPredictorU )
+    {
+		free(mPredictorU);
+        mPredictorU = NULL;
+    }
+	if ( mPredictorV )
+    {
+		free(mPredictorV);
+        mPredictorV = NULL;
+    }
+
+	// delete the unused byte shift buffer
+	if ( mShiftBufferUV )
+    {
+		free(mShiftBufferUV);
+        mShiftBufferUV = NULL;
+    }
+
+	// delete the work buffer
+	if ( mWorkBuffer )
+    {
+		free(mWorkBuffer);
+        mWorkBuffer = NULL;
+    }	
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	HEADER SPECIFICATION  
+
+        For every segment we adopt the following header:
+        
+			1 byte reserved			(always 0)
+			1 byte flags			(see below)
+			[4 byte frame length]	(optional, see below)
+			     ---Next, the per-segment ALAC parameters---
+			1 byte mixBits			(middle-side parameter)
+			1 byte mixRes			(middle-side parameter, interpreted as signed char)
+
+			1 byte shiftU			(4 bits modeU, 4 bits denShiftU)
+			1 byte filterU			(3 bits pbFactorU, 5 bits numU)
+			(numU) shorts			(signed DP coefficients for V channel)
+			     ---Next, 2nd-channel ALAC parameters in case of stereo mode---
+			1 byte shiftV			(4 bits modeV, 4 bits denShiftV)
+			1 byte filterV			(3 bits pbFactorV, 5 bits numV)
+			(numV) shorts			(signed DP coefficients for V channel)
+			     ---After this come the shift-off bytes for (>= 24)-bit data (n-byte shift) if indicated---
+			     ---Then comes the AG-compressor bitstream---
+
+
+        FLAGS
+        -----
+
+		The presence of certain flag bits changes the header format such that the parameters might
+		not even be sent.  The currently defined flags format is:
+
+			0000psse
+			
+			where		0 	= reserved, must be 0
+						p	= 1-bit field "partial frame" flag indicating 32-bit frame length follows this byte
+						ss	= 2-bit field indicating "number of shift-off bytes ignored by compression"
+						e	= 1-bit field indicating "escape"
+
+		The "partial frame" flag means that the following segment is not equal to the frame length specified
+		in the out-of-band decoder configuration.  This allows the decoder to deal with end-of-file partial
+		segments without incurring the 32-bit overhead for each segment.
+
+		The "shift-off" field indicates the number of bytes at the bottom of the word that were passed through
+		uncompressed.  The reason for this is that the entropy inherent in the LS bytes of >= 24-bit words
+		quite often means that the frame would have to be "escaped" b/c the compressed size would be >= the
+		uncompressed size.  However, by shifting the input values down and running the remaining bits through
+		the normal compression algorithm, a net win can be achieved.  If this field is non-zero, it means that
+		the shifted-off bytes follow after the parameter section of the header and before the compressed
+		bitstream.  Note that doing this also allows us to use matrixing on 32-bit inputs after one or more
+		bytes are shifted off the bottom which helps the eventual compression ratio.  For stereo channels,
+		the shifted off bytes are interleaved.
+
+        The "escape" flag means that this segment was not compressed b/c the compressed size would be
+        >= uncompressed size.  In that case, the audio data was passed through uncompressed after the header.
+        The other header parameter bytes will not be sent.
+        
+
+		PARAMETERS
+		----------
+
+		If the segment is not a partial or escape segment, the total header size (in bytes) is given exactly by:
+
+			4 + (2 + 2 * numU)                   (mono mode)
+			4 + (2 + 2 * numV) + (2 + 2 * numV)  (stereo mode)
+
+        where the ALAC filter-lengths numU, numV are bounded by a
+        constant (in the current source, numU, numV <= NUMCOEPAIRS), and
+        this forces an absolute upper bound on header size.
+
+        Each segment-decode process loads up these bytes from the front of the
+        local stream, in the above order, then follows with the entropy-encoded
+        bits for the given segment.
+
+        To generalize middle-side, there are various mixing modes including middle-side, each lossless,
+        as embodied in the mix() and unmix() functions.  These functions exploit a generalized middle-side
+        transformation:
+
+        u := [(rL + (m-r)R)/m];
+        v := L - R;
+
+        where [ ] denotes integer floor.  The (lossless) inverse is
+
+        L = u + v - [rV/m];
+        R = L - v;
+
+        In the segment header, m and r are encoded in mixBits and mixRes.
+        Classical "middle-side" is obtained with m = 2, r = 1, but now
+        we have more generalized mixes.
+
+        NOTES
+        -----
+        The relevance of the ALAC coefficients is explained in detail
+        in patent documents.
+*/
+
+/*
+	EncodeStereo()
+	- encode a channel pair
+*/
+int32_t ALACEncoder::EncodeStereo( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
+{
+	BitBuffer		workBits;
+	BitBuffer		startBits = *bitstream;			// squirrel away copy of current state in case we need to go back and do an escape packet
+	AGParamRec		agParams;
+	uint32_t          bits1, bits2;
+	uint32_t			dilate;
+	int32_t			mixBits, mixRes, maxRes;
+	uint32_t			minBits, minBits1, minBits2;
+	uint32_t			numU, numV;
+	uint32_t			mode;
+	uint32_t			pbFactor;
+	uint32_t			chanBits;
+	uint32_t			denShift;
+	uint8_t			bytesShifted;
+	SearchCoefs		coefsU;
+	SearchCoefs		coefsV;
+	uint32_t			index;
+	uint8_t			partialFrame;
+	uint32_t			escapeBits;
+	bool			doEscape;
+	int32_t		status = ALAC_noErr;
+
+	// make sure we handle this bit-depth before we get going
+	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );
+
+	// reload coefs pointers for this channel pair
+	// - note that, while you might think they should be re-initialized per block, retaining state across blocks
+	//	 actually results in better overall compression
+	// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
+	//	 different coefs for the different passes of "mixRes" results in even better compression
+	coefsU = (SearchCoefs) mCoefsU[channelIndex];
+	coefsV = (SearchCoefs) mCoefsV[channelIndex];
+
+	// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
+	// so enable 16-bit "shift off" and encode in 17-bit mode
+	// - in addition, 24-bit mode really improves with one byte shifted off
+	if ( mBitDepth == 32 )
+		bytesShifted = 2;
+	else if ( mBitDepth >= 24 )
+		bytesShifted = 1;
+	else
+		bytesShifted = 0;
+
+	chanBits = mBitDepth - (bytesShifted * 8) + 1;
+	
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// brute-force encode optimization loop
+	// - run over variations of the encoding params to find the best choice
+	mixBits		= kDefaultMixBits;
+	maxRes		= kMaxRes;
+	numU = numV = kDefaultNumUV;
+	denShift	= DENSHIFT_DEFAULT;
+	mode		= 0;
+	pbFactor	= 4;
+	dilate		= 8;
+
+	minBits	= minBits1 = minBits2 = 1ul << 31;
+	
+    int32_t		bestRes = mLastMixRes[channelIndex];
+
+    for ( mixRes = 0; mixRes <= maxRes; mixRes++ )
+    {
+        // mix the stereo inputs
+        switch ( mBitDepth )
+        {
+            case 16:
+                mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes );
+                break;
+            case 20:
+                mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes );
+                break;
+            case 24:
+                // includes extraction of shifted-off bytes
+                mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate,
+                        mixBits, mixRes, mShiftBufferUV, bytesShifted );
+                break;
+            case 32:
+                // includes extraction of shifted-off bytes
+                mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate,
+                        mixBits, mixRes, mShiftBufferUV, bytesShifted );
+                break;
+        }
+
+        BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );
+        
+        // run the dynamic predictors
+        pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+        pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+
+        // run the lossless compressor on each channel
+        set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+        status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
+        RequireNoErr( status, goto Exit; );
+
+        set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+        status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );
+        RequireNoErr( status, goto Exit; );
+
+        // look for best match
+        if ( (bits1 + bits2) < minBits1 )
+        {
+            minBits1 = bits1 + bits2;
+            bestRes = mixRes;
+        }
+    }
+    
+    mLastMixRes[channelIndex] = (int16_t)bestRes;
+
+	// mix the stereo inputs with the current best mixRes
+	mixRes = mLastMixRes[channelIndex];
+	switch ( mBitDepth )
+	{
+		case 16:
+			mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 20:
+			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 24:
+			// also extracts the shifted off bytes into the shift buffers
+			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+		case 32:
+			// also extracts the shifted off bytes into the shift buffers
+			mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+	}
+
+	// now it's time for the predictor coefficient search loop
+	numU = numV = kMinUV;
+	minBits1 = minBits2 = 1ul << 31;
+
+	for ( uint32_t numUV = kMinUV; numUV <= kMaxUV; numUV += 4 )
+	{
+		BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );		
+
+		dilate = 32;
+
+		// run the predictor over the same data multiple times to help it converge
+		for ( uint32_t converge = 0; converge < 8; converge++ )
+		{
+		    pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
+		    pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT );
+		}
+
+		dilate = 8;
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
+
+		if ( (bits1 * dilate + 16 * numUV) < minBits1 )
+		{
+			minBits1 = bits1 * dilate + 16 * numUV;
+			numU = numUV;
+		}
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 );
+
+		if ( (bits2 * dilate + 16 * numUV) < minBits2 )
+		{
+			minBits2 = bits2 * dilate + 16 * numUV;
+			numV = numUV;
+		}
+	}
+
+	// test for escape hatch if best calculated compressed size turns out to be more than the input size
+	minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
+	if ( bytesShifted != 0 )
+		minBits += (numSamples * (bytesShifted * 8) * 2);
+
+	escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */
+
+	doEscape = (minBits >= escapeBits) ? true : false;
+
+	if ( doEscape == false )
+	{
+		// write bitstream header and coefs
+		BitBufferWrite( bitstream, 0, 12 );
+		BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
+		if ( partialFrame )
+			BitBufferWrite( bitstream, numSamples, 32 );
+		BitBufferWrite( bitstream, mixBits, 8 );
+		BitBufferWrite( bitstream, mixRes, 8 );
+		
+		//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
+		//Assert( (pbFactor < 8) && (numU < 32) );
+		//Assert( (pbFactor < 8) && (numV < 32) );
+
+		BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+		BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
+		for ( index = 0; index < numU; index++ )
+			BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 );
+
+		BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+		BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
+		for ( index = 0; index < numV; index++ )
+			BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 );
+
+		// if shift active, write the interleaved shift buffers
+		if ( bytesShifted != 0 )
+		{
+			uint32_t		bitShift = bytesShifted * 8;
+
+			//Assert( bitShift <= 16 );
+
+			for ( index = 0; index < (numSamples * 2); index += 2 )
+			{
+				uint32_t			shiftedVal;
+				
+				shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1];
+				BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
+			}
+		}
+
+		// run the dynamic predictor and lossless compression for the "left" channel
+		// - note: to avoid allocating more buffers, we're mixing and matching between the available buffers instead
+		//		   of only using "U" buffers for the U-channel and "V" buffers for the V-channel
+		if ( mode == 0 )
+		{
+			pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+		}
+		else
+		{
+			pc_block( mMixBufferU, mPredictorV, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+			pc_block( mPredictorV, mPredictorU, numSamples, nil, 31, chanBits, 0 );
+		}
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
+		RequireNoErr( status, goto Exit; );
+
+		// run the dynamic predictor and lossless compression for the "right" channel
+		if ( mode == 0 )
+		{
+			pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+		}
+		else
+		{
+			pc_block( mMixBufferV, mPredictorU, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+			pc_block( mPredictorU, mPredictorV, numSamples, nil, 31, chanBits, 0 );
+		}
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 );
+		RequireNoErr( status, goto Exit; );
+
+		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
+			chuck it and do an escape packet
+		*/
+		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
+		if ( minBits >= escapeBits )
+		{
+			*bitstream = startBits;		// reset bitstream state
+			doEscape = true;
+			printf( "compressed frame too big: %u vs. %u \n", minBits, escapeBits );
+		}
+	}
+
+	if ( doEscape == true )
+	{
+		/* escape */
+		status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples );
+
+#if VERBOSE_DEBUG		
+		DebugMsg( "escape!: %lu vs %lu", minBits, escapeBits );
+#endif
+	}
+	
+Exit:
+	return status;
+}
+
+/*
+	EncodeStereoFast()
+	- encode a channel pair without the search loop for maximum possible speed
+*/
+int32_t ALACEncoder::EncodeStereoFast( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
+{
+	BitBuffer		startBits = *bitstream;			// squirrel away current bit position in case we decide to use escape hatch
+	AGParamRec		agParams;
+	uint32_t	bits1, bits2;
+	int32_t			mixBits, mixRes;
+	uint32_t			minBits, minBits1, minBits2;
+	uint32_t			numU, numV;
+	uint32_t			mode;
+	uint32_t			pbFactor;
+	uint32_t			chanBits;
+	uint32_t			denShift;
+	uint8_t			bytesShifted;
+	SearchCoefs		coefsU;
+	SearchCoefs		coefsV;
+	uint32_t			index;
+	uint8_t			partialFrame;
+	uint32_t			escapeBits;
+	bool			doEscape;	
+	int32_t		status;
+
+	// make sure we handle this bit-depth before we get going
+	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );
+
+	// reload coefs pointers for this channel pair
+	// - note that, while you might think they should be re-initialized per block, retaining state across blocks
+	//	 actually results in better overall compression
+	// - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using
+	//	 different coefs for the different passes of "mixRes" results in even better compression
+	coefsU = (SearchCoefs) mCoefsU[channelIndex];
+	coefsV = (SearchCoefs) mCoefsV[channelIndex];
+
+	// matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many
+	// so enable 16-bit "shift off" and encode in 17-bit mode
+	// - in addition, 24-bit mode really improves with one byte shifted off
+	if ( mBitDepth == 32 )
+		bytesShifted = 2;
+	else if ( mBitDepth >= 24 )
+		bytesShifted = 1;
+	else
+		bytesShifted = 0;
+
+	chanBits = mBitDepth - (bytesShifted * 8) + 1;
+	
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// set up default encoding parameters for "fast" mode
+	mixBits		= kDefaultMixBits;
+	mixRes		= kDefaultMixRes;
+	numU = numV = kDefaultNumUV;
+	denShift	= DENSHIFT_DEFAULT;
+	mode		= 0;
+	pbFactor	= 4;
+
+	minBits	= minBits1 = minBits2 = 1ul << 31;
+	
+	// mix the stereo inputs with default mixBits/mixRes
+	switch ( mBitDepth )
+	{
+		case 16:
+			mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 20:
+			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes );
+			break;
+		case 24:
+			// also extracts the shifted off bytes into the shift buffers
+			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+		case 32:
+			// also extracts the shifted off bytes into the shift buffers
+			mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples,
+					mixBits, mixRes, mShiftBufferUV, bytesShifted );
+			break;
+	}
+
+	/* speculatively write the bitstream assuming the compressed version will be smaller */
+
+	// write bitstream header and coefs
+	BitBufferWrite( bitstream, 0, 12 );
+	BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
+	if ( partialFrame )
+		BitBufferWrite( bitstream, numSamples, 32 );
+	BitBufferWrite( bitstream, mixBits, 8 );
+	BitBufferWrite( bitstream, mixRes, 8 );
+	
+	//Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) );
+	//Assert( (pbFactor < 8) && (numU < 32) );
+	//Assert( (pbFactor < 8) && (numV < 32) );
+
+	BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+	BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
+	for ( index = 0; index < numU; index++ )
+		BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 );
+
+	BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 );
+	BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 );
+	for ( index = 0; index < numV; index++ )
+		BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 );
+
+	// if shift active, write the interleaved shift buffers
+	if ( bytesShifted != 0 )
+	{
+		uint32_t		bitShift = bytesShifted * 8;
+
+		//Assert( bitShift <= 16 );
+
+		for ( index = 0; index < (numSamples * 2); index += 2 )
+		{
+			uint32_t			shiftedVal;
+			
+			shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1];
+			BitBufferWrite( bitstream, shiftedVal, bitShift * 2 );
+		}
+	}
+
+	// run the dynamic predictor and lossless compression for the "left" channel
+	// - note: we always use mode 0 in the "fast" path so we don't need the code for mode != 0
+	pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT );
+
+	set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+	status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
+	RequireNoErr( status, goto Exit; );
+
+	// run the dynamic predictor and lossless compression for the "right" channel
+	pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT );
+
+	set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT );
+	status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 );
+	RequireNoErr( status, goto Exit; );
+
+	// do bit requirement calculations
+	minBits1 = bits1 + (numU * sizeof(int16_t) * 8);
+	minBits2 = bits2 + (numV * sizeof(int16_t) * 8);
+
+	// test for escape hatch if best calculated compressed size turns out to be more than the input size
+	minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
+	if ( bytesShifted != 0 )
+		minBits += (numSamples * (bytesShifted * 8) * 2);
+
+	escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */
+
+	doEscape = (minBits >= escapeBits) ? true : false;
+
+	if ( doEscape == false )
+	{
+		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
+			chuck it and do an escape packet
+		*/
+		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
+		if ( minBits >= escapeBits )
+		{
+			doEscape = true;
+			printf( "compressed frame too big: %u vs. %u\n", minBits, escapeBits );
+		}
+
+	}
+
+	if ( doEscape == true )
+	{
+		/* escape */
+
+		// reset bitstream position since we speculatively wrote the compressed version
+		*bitstream = startBits;
+
+		// write escape frame
+		status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples );
+
+#if VERBOSE_DEBUG		
+		DebugMsg( "escape!: %u vs %u", minBits, (numSamples * mBitDepth * 2) );
+#endif
+	}
+	
+Exit:
+	return status;
+}
+
+/*
+	EncodeStereoEscape()
+	- encode stereo escape frame
+*/
+int32_t ALACEncoder::EncodeStereoEscape( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t numSamples )
+{
+	int16_t *		input16;
+	int32_t *		input32;
+	uint8_t			partialFrame;
+	uint32_t			index;
+
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// write bitstream header
+	BitBufferWrite( bitstream, 0, 12 );
+	BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 );	// LSB = 1 means "frame not compressed"
+	if ( partialFrame )
+		BitBufferWrite( bitstream, numSamples, 32 );
+
+	// just copy the input data to the output buffer
+	switch ( mBitDepth )
+	{
+		case 16:
+			input16 = (int16_t *) inputBuffer;
+			
+			for ( index = 0; index < (numSamples * stride); index += stride )
+			{
+				BitBufferWrite( bitstream, input16[index + 0], 16 );
+				BitBufferWrite( bitstream, input16[index + 1], 16 );
+			}
+			break;
+		case 20:
+			// mix20() with mixres param = 0 means de-interleave so use it to simplify things
+			mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0 );
+			for ( index = 0; index < numSamples; index++ )
+			{
+				BitBufferWrite( bitstream, mMixBufferU[index], 20 );
+				BitBufferWrite( bitstream, mMixBufferV[index], 20 );
+			}				
+			break;
+		case 24:
+			// mix24() with mixres param = 0 means de-interleave so use it to simplify things
+			mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0, mShiftBufferUV, 0 );
+			for ( index = 0; index < numSamples; index++ )
+			{
+				BitBufferWrite( bitstream, mMixBufferU[index], 24 );
+				BitBufferWrite( bitstream, mMixBufferV[index], 24 );
+			}				
+			break;
+		case 32:
+			input32 = (int32_t *) inputBuffer;
+
+			for ( index = 0; index < (numSamples * stride); index += stride )
+			{
+				BitBufferWrite( bitstream, input32[index + 0], 32 );
+				BitBufferWrite( bitstream, input32[index + 1], 32 );
+			}				
+			break;
+	}
+	
+	return ALAC_noErr;
+}
+
+/*
+	EncodeMono()
+	- encode a mono input buffer
+*/
+int32_t ALACEncoder::EncodeMono( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples )
+{
+	BitBuffer		startBits = *bitstream;			// squirrel away copy of current state in case we need to go back and do an escape packet
+	AGParamRec		agParams;
+	uint32_t	bits1;
+	uint32_t			numU;
+	SearchCoefs		coefsU;
+	uint32_t			dilate;
+	uint32_t			minBits, bestU;
+	uint32_t			minU, maxU;
+	uint32_t			index, index2;
+	uint8_t			bytesShifted;
+	uint32_t			shift;
+	uint32_t			mask;
+	uint32_t			chanBits;
+	uint8_t			pbFactor;
+	uint8_t			partialFrame;
+	int16_t *		input16;
+	int32_t *		input32;
+	uint32_t			escapeBits;
+	bool			doEscape;
+	int32_t		status;
+
+	// make sure we handle this bit-depth before we get going
+	RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; );
+
+	status = ALAC_noErr;
+	
+	// reload coefs array from previous frame
+	coefsU = (SearchCoefs) mCoefsU[channelIndex];
+
+	// pick bit depth for actual encoding
+	// - we lop off the lower byte(s) for 24-/32-bit encodings
+	if ( mBitDepth == 32 )
+		bytesShifted = 2;
+	else if ( mBitDepth >= 24 )
+		bytesShifted = 1;
+	else
+		bytesShifted = 0;
+
+	shift = bytesShifted * 8;
+	mask = (1ul << shift) - 1;
+	chanBits = mBitDepth - (bytesShifted * 8);
+
+	// flag whether or not this is a partial frame
+	partialFrame = (numSamples == mFrameSize) ? 0 : 1;
+
+	// convert N-bit data to 32-bit for predictor
+	switch ( mBitDepth )
+	{
+		case 16:
+		{
+			// convert 16-bit data to 32-bit for predictor
+			input16 = (int16_t *) inputBuffer;
+			for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride )
+				mMixBufferU[index] = (int32_t) input16[index2];
+			break;
+		}
+		case 20:
+			// convert 20-bit data to 32-bit for predictor
+			copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+			break;
+		case 24:
+			// convert 24-bit data to 32-bit for the predictor and extract the shifted off byte(s)
+			copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+			for ( index = 0; index < numSamples; index++ )
+			{
+				mShiftBufferUV[index] = (uint16_t)(mMixBufferU[index] & mask);
+				mMixBufferU[index] >>= shift;
+			}
+			break;
+		case 32:
+		{
+			// just copy the 32-bit input data for the predictor and extract the shifted off byte(s)
+			input32 = (int32_t *) inputBuffer;
+
+			for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride )
+			{
+				int32_t			val = input32[index2];
+				
+				mShiftBufferUV[index] = (uint16_t)(val & mask);
+				mMixBufferU[index] = val >> shift;
+			}
+			break;
+		}
+	}
+
+	// brute-force encode optimization loop (implied "encode depth" of 0 if comparing to cmd line tool)
+	// - run over variations of the encoding params to find the best choice
+	minU		= 4;
+	maxU		= 8;
+	minBits		= 1ul << 31;
+	pbFactor	= 4;
+	
+	minBits	= 1ul << 31;
+	bestU	= minU;
+
+	for ( numU = minU; numU <= maxU; numU += 4 )
+	{
+		BitBuffer		workBits;
+		uint32_t			numBits;
+
+		BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes );
+	
+		dilate = 32;
+		for ( uint32_t converge = 0; converge < 7; converge++ )	
+			pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
+
+		dilate = 8;
+		pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
+
+		set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT );
+		status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 );
+		RequireNoErr( status, goto Exit; );
+
+		numBits = (dilate * bits1) + (16 * numU);
+		if ( numBits < minBits )
+		{
+			bestU	= numU;
+			minBits = numBits;
+		}
+	}             
+
+	// test for escape hatch if best calculated compressed size turns out to be more than the input size
+	// - first, add bits for the header bytes mixRes/maxRes/shiftU/filterU
+	minBits += (4 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0);
+	if ( bytesShifted != 0 )
+		minBits += (numSamples * (bytesShifted * 8));
+
+	escapeBits = (numSamples * mBitDepth) + ((partialFrame == true) ? 32 : 0) + (2 * 8);	/* 2 common header bytes */
+
+	doEscape = (minBits >= escapeBits) ? true : false;
+
+	if ( doEscape == false )
+	{
+		// write bitstream header
+		BitBufferWrite( bitstream, 0, 12 );
+		BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 );
+		if ( partialFrame )
+			BitBufferWrite( bitstream, numSamples, 32 );
+		BitBufferWrite( bitstream, 0, 16 );								// mixBits = mixRes = 0
+		
+		// write the params and predictor coefs
+		numU = bestU;
+		BitBufferWrite( bitstream, (0 << 4) | DENSHIFT_DEFAULT, 8 );	// modeU = 0
+		BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 );
+		for ( index = 0; index < numU; index++ )
+			BitBufferWrite( bitstream, coefsU[numU-1][index], 16 );
+
+		// if shift active, write the interleaved shift buffers
+		if ( bytesShifted != 0 )
+		{
+			for ( index = 0; index < numSamples; index++ )
+				BitBufferWrite( bitstream, mShiftBufferUV[index], shift );
+		}
+
+		// run the dynamic predictor with the best result
+		pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT );
+
+		// do lossless compression
+		set_standard_ag_params( &agParams, numSamples, numSamples );
+		status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 );
+		//AssertNoErr( status );
+
+
+		/*	if we happened to create a compressed packet that was actually bigger than an escape packet would be,
+			chuck it and do an escape packet
+		*/
+		minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits );
+		if ( minBits >= escapeBits )
+		{
+			*bitstream = startBits;		// reset bitstream state
+			doEscape = true;
+			printf( "compressed frame too big: %u vs. %u\n", minBits, escapeBits );
+		}
+	}
+
+	if ( doEscape == true )
+	{
+		// write bitstream header and coefs
+		BitBufferWrite( bitstream, 0, 12 );
+		BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 );	// LSB = 1 means "frame not compressed"
+		if ( partialFrame )
+			BitBufferWrite( bitstream, numSamples, 32 );
+
+		// just copy the input data to the output buffer
+		switch ( mBitDepth )
+		{
+			case 16:
+				input16 = (int16_t *) inputBuffer;
+				for ( index = 0; index < (numSamples * stride); index += stride )
+					BitBufferWrite( bitstream, input16[index], 16 );
+				break;
+			case 20:
+				// convert 20-bit data to 32-bit for simplicity
+				copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+				for ( index = 0; index < numSamples; index++ )
+					BitBufferWrite( bitstream, mMixBufferU[index], 20 );
+				break;
+			case 24:
+				// convert 24-bit data to 32-bit for simplicity
+				copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples );
+				for ( index = 0; index < numSamples; index++ )
+					BitBufferWrite( bitstream, mMixBufferU[index], 24 );
+				break;
+			case 32:
+				input32 = (int32_t *) inputBuffer;
+				for ( index = 0; index < (numSamples * stride); index += stride )
+					BitBufferWrite( bitstream, input32[index], 32 );
+				break;
+		}
+#if VERBOSE_DEBUG		
+		DebugMsg( "escape!: %lu vs %lu", minBits, (numSamples * mBitDepth) );
+#endif
+	}
+
+Exit:
+	return status;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	Encode()
+	- encode the next block of samples
+*/
+int32_t ALACEncoder::Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat,
+                             unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes)
+{
+	uint32_t				numFrames;
+	uint32_t				outputSize;
+	BitBuffer			bitstream;
+	int32_t			status;
+
+	numFrames = *ioNumBytes/theInputFormat.mBytesPerPacket;
+
+	// create a bit buffer structure pointing to our output buffer
+	BitBufferInit( &bitstream, theWriteBuffer, mMaxOutputBytes );
+
+	if ( theInputFormat.mChannelsPerFrame == 2 )
+	{
+		// add 3-bit frame start tag ID_CPE = channel pair & 4-bit element instance tag = 0
+		BitBufferWrite( &bitstream, ID_CPE, 3 );
+		BitBufferWrite( &bitstream, 0, 4 );
+
+		// encode stereo input buffer
+		if ( mFastMode == false )
+			status = this->EncodeStereo( &bitstream, theReadBuffer, 2, 0, numFrames );
+		else
+			status = this->EncodeStereoFast( &bitstream, theReadBuffer, 2, 0, numFrames );
+		RequireNoErr( status, goto Exit; );
+	}
+	else if ( theInputFormat.mChannelsPerFrame == 1 )
+	{
+		// add 3-bit frame start tag ID_SCE = mono channel & 4-bit element instance tag = 0
+		BitBufferWrite( &bitstream, ID_SCE, 3 );
+		BitBufferWrite( &bitstream, 0, 4 );
+
+		// encode mono input buffer
+		status = this->EncodeMono( &bitstream, theReadBuffer, 1, 0, numFrames );
+		RequireNoErr( status, goto Exit; );
+	}
+	else
+	{
+		char *					inputBuffer;
+		uint32_t				tag;
+		uint32_t				channelIndex;
+		uint32_t				inputIncrement;
+		uint8_t				stereoElementTag;
+		uint8_t				monoElementTag;
+		uint8_t				lfeElementTag;
+		
+		inputBuffer		= (char *) theReadBuffer;
+		inputIncrement	= ((mBitDepth + 7) / 8);
+		
+		stereoElementTag	= 0;
+		monoElementTag		= 0;
+		lfeElementTag		= 0;
+
+		for ( channelIndex = 0; channelIndex < theInputFormat.mChannelsPerFrame; )
+		{
+			tag = (sChannelMaps[theInputFormat.mChannelsPerFrame - 1] & (0x7ul << (channelIndex * 3))) >> (channelIndex * 3);
+	
+			BitBufferWrite( &bitstream, tag, 3 );
+			switch ( tag )
+			{
+				case ID_SCE:
+					// mono
+					BitBufferWrite( &bitstream, monoElementTag, 4 );
+
+					status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );
+					
+					inputBuffer += inputIncrement;
+					channelIndex++;
+					monoElementTag++;
+					break;
+
+				case ID_CPE:
+					// stereo
+					BitBufferWrite( &bitstream, stereoElementTag, 4 );
+
+					status = this->EncodeStereo( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );
+
+					inputBuffer += (inputIncrement * 2);
+					channelIndex += 2;
+					stereoElementTag++;
+					break;
+
+				case ID_LFE:
+					// LFE channel (subwoofer)
+					BitBufferWrite( &bitstream, lfeElementTag, 4 );
+
+					status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames );
+
+					inputBuffer += inputIncrement;
+					channelIndex++;
+					lfeElementTag++;
+					break;
+
+				default:
+					printf( "That ain't right! (%u)\n", tag );
+					status = kALAC_ParamError;
+					goto Exit;
+			}
+
+			RequireNoErr( status, goto Exit; );
+		}
+	}
+
+#if VERBOSE_DEBUG
+{
+	// if there is room left in the output buffer, add some random fill data to test decoder
+	int32_t			bitsLeft;
+	int32_t			bytesLeft;
+	
+	bitsLeft = BitBufferGetPosition( &bitstream ) - 3;	// - 3 for ID_END tag
+	bytesLeft = bitstream.byteSize - ((bitsLeft + 7) / 8);
+	
+	if ( (bytesLeft > 20) && ((bytesLeft & 0x4u) != 0) )
+		AddFiller( &bitstream, bytesLeft );
+}
+#endif
+
+	// add 3-bit frame end tag: ID_END
+	BitBufferWrite( &bitstream, ID_END, 3 );
+
+	// byte-align the output data
+	BitBufferByteAlign( &bitstream, true );
+
+	outputSize = BitBufferGetPosition( &bitstream ) / 8;
+	//Assert( outputSize <= mMaxOutputBytes );
+
+
+	// all good, let iTunes know what happened and remember the total number of input sample frames
+	*ioNumBytes = outputSize;
+	//mEncodedFrames		   	   += encodeMsg->numInputSamples;
+
+	// gather encoding stats
+	mTotalBytesGenerated += outputSize;
+	mMaxFrameBytes = MAX( mMaxFrameBytes, outputSize );
+
+	status = ALAC_noErr;
+
+Exit:
+	return status;
+}
+
+/*
+	Finish()
+	- drain out any leftover samples
+*/
+
+int32_t ALACEncoder::Finish()
+{
+/*	// finalize bit rate statistics
+	if ( mSampleSize.numEntries != 0 )
+		mAvgBitRate = (uint32_t)( (((float)mTotalBytesGenerated * 8.0f) / (float)mSampleSize.numEntries) * ((float)mSampleRate / (float)mFrameSize) );
+	else
+		mAvgBitRate = 0;
+*/
+	return ALAC_noErr;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	GetConfig()
+*/
+void ALACEncoder::GetConfig( ALACSpecificConfig & config )
+{
+	config.frameLength			= Swap32NtoB(mFrameSize);
+	config.compatibleVersion	= (uint8_t) kALACCompatibleVersion;
+	config.bitDepth				= (uint8_t) mBitDepth;
+	config.pb					= (uint8_t) PB0;
+	config.kb					= (uint8_t) KB0;
+	config.mb					= (uint8_t) MB0;
+	config.numChannels			= (uint8_t) mNumChannels;
+	config.maxRun				= Swap16NtoB((uint16_t) MAX_RUN_DEFAULT);
+	config.maxFrameBytes		= Swap32NtoB(mMaxFrameBytes);
+	config.avgBitRate			= Swap32NtoB(mAvgBitRate);
+	config.sampleRate			= Swap32NtoB(mOutputSampleRate);
+}
+
+uint32_t ALACEncoder::GetMagicCookieSize(uint32_t inNumChannels)
+{
+    if (inNumChannels > 2)
+    {
+        return sizeof(ALACSpecificConfig) + kChannelAtomSize + sizeof(ALACAudioChannelLayout);
+    }
+    else
+    {
+        return sizeof(ALACSpecificConfig);
+    }
+}
+
+void ALACEncoder::GetMagicCookie(void * outCookie, uint32_t * ioSize)
+{
+    ALACSpecificConfig theConfig = {0};
+    ALACAudioChannelLayout theChannelLayout = {0};
+    uint8_t theChannelAtom[kChannelAtomSize] = {0, 0, 0, 0, 'c', 'h', 'a', 'n', 0, 0, 0, 0};
+    uint32_t theCookieSize = sizeof(ALACSpecificConfig);
+    uint8_t * theCookiePointer = (uint8_t *)outCookie;
+    
+    GetConfig(theConfig);
+    if (theConfig.numChannels > 2)
+    {
+        theChannelLayout.mChannelLayoutTag = ALACChannelLayoutTags[theConfig.numChannels - 1];
+        theCookieSize += (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
+    }
+     if (*ioSize >= theCookieSize)
+    {
+        memcpy(theCookiePointer, &theConfig, sizeof(ALACSpecificConfig));
+        theChannelAtom[3] = (sizeof(ALACAudioChannelLayout) + kChannelAtomSize);
+        if (theConfig.numChannels > 2)
+        {
+            theCookiePointer += sizeof(ALACSpecificConfig);
+            memcpy(theCookiePointer, theChannelAtom, kChannelAtomSize);
+            theCookiePointer += kChannelAtomSize;
+            memcpy(theCookiePointer, &theChannelLayout, sizeof(ALACAudioChannelLayout));
+        }
+        *ioSize = theCookieSize;
+    }
+    else
+    {
+        *ioSize = 0; // no incomplete cookies
+    }
+}
+
+/*
+	InitializeEncoder()
+	- initialize the encoder component with the current config
+*/
+int32_t ALACEncoder::InitializeEncoder(AudioFormatDescription theOutputFormat)
+{
+	int32_t			status;
+    
+    mOutputSampleRate = theOutputFormat.mSampleRate;
+    mNumChannels = theOutputFormat.mChannelsPerFrame;
+    switch(theOutputFormat.mFormatFlags)
+    {
+        case 1:
+            mBitDepth = 16;
+            break;
+        case 2:
+            mBitDepth = 20;
+            break;
+        case 3:
+            mBitDepth = 24;
+            break;
+        case 4:
+            mBitDepth = 32;
+            break;
+        default:
+            break;
+    }
+
+	// set up default encoding parameters and state
+	// - note: mFrameSize is set in the constructor or via SetFrameSize() which must be called before this routine
+	for ( uint32_t index = 0; index < kALACMaxChannels; index++ )
+		mLastMixRes[index] = kDefaultMixRes;
+
+	// the maximum output frame size can be no bigger than (samplesPerBlock * numChannels * ((10 + sampleSize)/8) + 1)
+	// but note that this can be bigger than the input size!
+	// - since we don't yet know what our input format will be, use our max allowed sample size in the calculation
+	mMaxOutputBytes = mFrameSize * mNumChannels * ((10 + kMaxSampleSize) / 8)  + 1;
+
+	// allocate mix buffers
+	mMixBufferU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+	mMixBufferV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+
+	// allocate dynamic predictor buffers
+	mPredictorU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+	mPredictorV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 );
+	
+	// allocate combined shift buffer
+	mShiftBufferUV = (uint16_t *) calloc( mFrameSize * 2 * sizeof(uint16_t),1 );
+	
+	// allocate work buffer for search loop
+	mWorkBuffer = (uint8_t *) calloc( mMaxOutputBytes, 1 );
+
+	RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) &&
+					(mPredictorU != nil) && (mPredictorV != nil) &&
+					(mShiftBufferUV != nil) && (mWorkBuffer != nil ),
+					status = kALAC_MemFullError; goto Exit; );
+
+	status = ALAC_noErr;
+
+
+	// initialize coefs arrays once b/c retaining state across blocks actually improves the encode ratio
+	for ( int32_t channel = 0; channel < (int32_t)mNumChannels; channel++ )
+	{
+		for ( int32_t search = 0; search < kALACMaxSearches; search++ )
+		{
+			init_coefs( mCoefsU[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
+			init_coefs( mCoefsV[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs );
+		}
+	}
+
+Exit:
+	return status;
+}
+
+/*
+	GetSourceFormat()
+	- given the input format, return one of our supported formats
+*/
+void ALACEncoder::GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output )
+{
+	// default is 16-bit native endian
+	// - note: for float input we assume that's coming from one of our decoders (mp3, aac) so it only makes sense
+	//		   to encode to 16-bit since the source was lossy in the first place
+	// - note: if not a supported bit depth, find the closest supported bit depth to the input one
+	if ( (source->mFormatID != kALACFormatLinearPCM) || ((source->mFormatFlags & kALACFormatFlagIsFloat) != 0) ||
+		( source->mBitsPerChannel <= 16 ) )
+		mBitDepth = 16;
+	else if ( source->mBitsPerChannel <= 20 )
+		mBitDepth = 20;
+	else if ( source->mBitsPerChannel <= 24 )
+		mBitDepth = 24;
+	else
+		mBitDepth = 32;
+		
+	// we support 16/20/24/32-bit integer data at any sample rate and our target number of channels
+	// and sample rate were specified when we were configured
+	/*
+    MakeUncompressedAudioFormat( mNumChannels, (float) mOutputSampleRate, mBitDepth, kAudioFormatFlagsNativeIntegerPacked, output );
+     */
+}
+
+
+
+#if VERBOSE_DEBUG
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+/*
+	AddFiller()
+	- add fill and data stream elements to the bitstream to test the decoder
+*/
+static void AddFiller( BitBuffer * bits, int32_t numBytes )
+{
+	uint8_t		tag;
+	uint32_t		index;
+
+	// out of lameness, subtract 6 bytes to deal with header + alignment as required for fill/data elements
+	numBytes -= 6;
+	if ( numBytes <= 0 )
+		return;
+	
+	// randomly pick Fill or Data Stream Element based on numBytes requested
+	tag = (numBytes & 0x8) ? ID_FIL : ID_DSE;
+
+	BitBufferWrite( bits, tag, 3 );
+	if ( tag == ID_FIL )
+	{
+		// can't write more than 269 bytes in a fill element
+		numBytes = (numBytes > 269) ? 269 : numBytes;
+
+		// fill element = 4-bit size unless >= 15 then 4-bit size + 8-bit extension size
+		if ( numBytes >= 15 )
+		{
+			uint16_t			extensionSize;
+
+			BitBufferWrite( bits, 15, 4 );
+
+			// 8-bit extension count field is "extra + 1" which is weird but I didn't define the syntax
+			// - otherwise, there's no way to represent 15
+			// - for example, to really mean 15 bytes you must encode extensionSize = 1
+			// - why it's not like data stream elements I have no idea
+			extensionSize = (numBytes - 15) + 1;
+			Assert( extensionSize <= 255 );
+			BitBufferWrite( bits, extensionSize, 8 );
+		}
+		else
+			BitBufferWrite( bits, numBytes, 4 );
+
+		BitBufferWrite( bits, 0x10, 8 );		// extension_type = FILL_DATA = b0001 or'ed with fill_nibble = b0000
+		for ( index = 0; index < (numBytes - 1); index++ )
+			BitBufferWrite( bits, 0xa5, 8 );	// fill_byte = b10100101 = 0xa5
+	}
+	else
+	{
+		// can't write more than 510 bytes in a data stream element
+		numBytes = (numBytes > 510) ? 510 : numBytes;
+
+		BitBufferWrite( bits, 0, 4 );			// element instance tag
+		BitBufferWrite( bits, 1, 1 );			// byte-align flag = true
+
+		// data stream element = 8-bit size unless >= 255 then 8-bit size + 8-bit size
+		if ( numBytes >= 255 )
+		{
+			BitBufferWrite( bits, 255, 8 );
+			BitBufferWrite( bits, numBytes - 255, 8 );
+		}
+		else
+			BitBufferWrite( bits, numBytes, 8 );
+		
+		BitBufferByteAlign( bits, true );		// byte-align with zeros
+
+		for ( index = 0; index < numBytes; index++ )
+			BitBufferWrite( bits, 0x5a, 8 );
+	}
+}
+
+#endif	/* VERBOSE_DEBUG */

+ 92 - 0
components/spotify/cspot/bell/external/alac/codec/ALACEncoder.h

@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ALACEncoder.h
+*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include "ALACAudioTypes.h"
+
+
+struct BitBuffer;
+
+class ALACEncoder
+{
+	public:
+		ALACEncoder();
+		virtual ~ALACEncoder();
+
+		virtual int32_t	Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat,
+                                   unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes);
+		virtual int32_t	Finish( );
+
+		void				SetFastMode( bool fast ) { mFastMode = fast; };
+
+		// this must be called *before* InitializeEncoder()
+		void				SetFrameSize( uint32_t frameSize ) { mFrameSize = frameSize; };
+
+		void				GetConfig( ALACSpecificConfig & config );
+        uint32_t            GetMagicCookieSize(uint32_t inNumChannels);
+        void				GetMagicCookie( void * config, uint32_t * ioSize ); 
+
+        virtual int32_t	InitializeEncoder(AudioFormatDescription theOutputFormat);
+
+    protected:
+		virtual void		GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output );
+		
+		int32_t			EncodeStereo( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
+		int32_t			EncodeStereoFast( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
+		int32_t			EncodeStereoEscape( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t numSamples );
+		int32_t			EncodeMono( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples );
+
+
+		// ALAC encoder parameters
+		int16_t					mBitDepth;
+		bool					mFastMode;
+
+		// encoding state
+		int16_t					mLastMixRes[kALACMaxChannels];
+
+		// encoding buffers
+		int32_t *				mMixBufferU;
+		int32_t *				mMixBufferV;
+		int32_t *				mPredictorU;
+		int32_t *				mPredictorV;
+		uint16_t *				mShiftBufferUV;
+		
+		uint8_t *					mWorkBuffer;
+
+		// per-channel coefficients buffers
+		int16_t					mCoefsU[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs];
+		int16_t					mCoefsV[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs];
+
+		// encoding statistics
+		uint32_t					mTotalBytesGenerated;
+		uint32_t					mAvgBitRate;
+		uint32_t					mMaxFrameBytes;
+        uint32_t                  mFrameSize;
+        uint32_t                  mMaxOutputBytes;
+        uint32_t                  mNumChannels;
+        uint32_t                  mOutputSampleRate;		
+};

+ 335 - 0
components/spotify/cspot/bell/external/alac/codec/APPLE_LICENSE.txt

@@ -0,0 +1,335 @@
+APPLE PUBLIC SOURCE LICENSE
+Version 2.0 -  August 6, 2003
+
+Please read this License carefully before downloading this software.  By
+downloading or using this software, you are agreeing to be bound by the terms
+of this License.  If you do not or cannot agree to the terms of this License,
+please do not download or use the software.
+
+Apple Note:  In January 2007, Apple changed its corporate name from "Apple
+Computer, Inc." to "Apple Inc."  This change has been reflected below and
+copyright years updated, but no other changes have been made to the APSL 2.0.
+
+1.	General; Definitions.  This License applies to any program or other
+work which Apple Inc. ("Apple") makes publicly available and which contains a
+notice placed by Apple identifying such program or work as "Original Code" and
+stating that it is subject to the terms of this Apple Public Source License
+version 2.0 ("License").  As used in this License:
+
+1.1	 "Applicable Patent Rights" mean:  (a) in the case where Apple is the
+grantor of rights, (i) claims of patents that are now or hereafter acquired,
+owned by or assigned to Apple and (ii) that cover subject matter contained in
+the Original Code, but only to the extent necessary to use, reproduce and/or
+distribute the Original Code without infringement; and (b) in the case where
+You are the grantor of rights, (i) claims of patents that are now or hereafter
+acquired, owned by or assigned to You and (ii) that cover subject matter in
+Your Modifications, taken alone or in combination with Original Code.
+
+1.2	"Contributor" means any person or entity that creates or contributes to
+the creation of Modifications.
+
+1.3	 "Covered Code" means the Original Code, Modifications, the combination
+of Original Code and any Modifications, and/or any respective portions thereof.
+
+1.4	"Externally Deploy" means: (a) to sublicense, distribute or otherwise
+make Covered Code available, directly or indirectly, to anyone other than You;
+and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way
+to provide a service, including but not limited to delivery of content, through
+electronic communication with a client other than You.
+
+1.5	"Larger Work" means a work which combines Covered Code or portions
+thereof with code not governed by the terms of this License.
+
+1.6	"Modifications" mean any addition to, deletion from, and/or change to,
+the substance and/or structure of the Original Code, any previous
+Modifications, the combination of Original Code and any previous Modifications,
+and/or any respective portions thereof.  When code is released as a series of
+files, a Modification is:  (a) any addition to or deletion from the contents of
+a file containing Covered Code; and/or (b) any new file or other representation
+of computer program statements that contains any part of Covered Code. 
+
+1.7	"Original Code" means (a) the Source Code of a program or other work as
+originally made available by Apple under this License, including the Source
+Code of any updates or upgrades to such programs or works made available by
+Apple under this License, and that has been expressly identified by Apple as
+such in the header file(s) of such work; and (b) the object code compiled from
+such Source Code and originally made available by Apple under this License
+
+1.8	"Source Code" means the human readable form of a program or other work
+that is suitable for making modifications to it, including all modules it
+contains, plus any associated interface definition files, scripts used to
+control compilation and installation of an executable (object code).
+
+1.9	"You" or "Your" means an individual or a legal entity exercising rights
+under this License.  For legal entities, "You" or "Your" includes any entity
+which controls, is controlled by, or is under common control with, You, where
+"control" means (a) the power, direct or indirect, to cause the direction or
+management of such entity, whether by contract or otherwise, or (b) ownership
+of fifty percent (50%) or more of the outstanding shares or beneficial
+ownership of such entity.
+
+2.	Permitted Uses; Conditions & Restrictions.   Subject to the terms and
+conditions of this License, Apple hereby grants You, effective on the date You
+accept this License and download the Original Code, a world-wide, royalty-free,
+non-exclusive license, to the extent of Apple's Applicable Patent Rights and
+copyrights covering the Original Code, to do the following:
+
+2.1	Unmodified Code.  You may use, reproduce, display, perform, internally
+distribute within Your organization, and Externally Deploy verbatim, unmodified
+copies of the Original Code, for commercial or non-commercial purposes,
+provided that in each instance:
+
+(a)	You must retain and reproduce in all copies of Original Code the
+copyright and other proprietary notices and disclaimers of Apple as they appear
+in the Original Code, and keep intact all notices in the Original Code that
+refer to this License; and
+
+(b) 	You must include a copy of this License with every copy of Source Code
+of Covered Code and documentation You distribute or Externally Deploy, and You
+may not offer or impose any terms on such Source Code that alter or restrict
+this License or the recipients' rights hereunder, except as permitted under
+Section 6.
+
+2.2	Modified Code.  You may modify Covered Code and use, reproduce,
+display, perform, internally distribute within Your organization, and
+Externally Deploy Your Modifications and Covered Code, for commercial or
+non-commercial purposes, provided that in each instance You also meet all of
+these conditions:
+
+(a)	You must satisfy all the conditions of Section 2.1 with respect to the
+Source Code of the Covered Code; 
+
+(b)	You must duplicate, to the extent it does not already exist, the notice
+in Exhibit A in each file of the Source Code of all Your Modifications, and
+cause the modified files to carry prominent notices stating that You changed
+the files and the date of any change; and
+
+(c)	If You Externally Deploy Your Modifications, You must make Source Code
+of all Your Externally Deployed Modifications either available to those to whom
+You have Externally Deployed Your Modifications, or publicly available.  Source
+Code of Your Externally Deployed Modifications must be released under the terms
+set forth in this License, including the license grants set forth in Section 3
+below, for as long as you Externally Deploy the Covered Code or twelve (12)
+months from the date of initial External Deployment, whichever is longer. You
+should preferably distribute the Source Code of Your Externally Deployed
+Modifications electronically (e.g. download from a web site).
+
+2.3	Distribution of Executable Versions.  In addition, if You Externally
+Deploy Covered Code (Original Code and/or Modifications) in object code,
+executable form only, You must include a prominent notice, in the code itself
+as well as in related documentation, stating that Source Code of the Covered
+Code is available under the terms of this License with information on how and
+where to obtain such Source Code.  
+
+2.4	Third Party Rights.  You expressly acknowledge and agree that although
+Apple and each Contributor grants the licenses to their respective portions of
+the Covered Code set forth herein, no assurances are provided by Apple or any
+Contributor that the Covered Code does not infringe the patent or other
+intellectual property rights of any other entity. Apple and each Contributor
+disclaim any liability to You for claims brought by any other entity based on
+infringement of intellectual property rights or otherwise. As a condition to
+exercising the rights and licenses granted hereunder, You hereby assume sole
+responsibility to secure any other intellectual property rights needed, if any.
+For example, if a third party patent license is required to allow You to
+distribute the Covered Code, it is Your responsibility to acquire that license
+before distributing the Covered Code.
+
+3.	Your Grants.  In consideration of, and as a condition to, the licenses
+granted to You under this License, You hereby grant to any person or entity
+receiving or distributing Covered Code under this License a non-exclusive,
+royalty-free, perpetual, irrevocable license, under Your Applicable Patent
+Rights and other intellectual property rights (other than patent) owned or
+controlled by You, to use, reproduce, display, perform, modify, sublicense,
+distribute and Externally Deploy Your Modifications of the same scope and
+extent as Apple's licenses under Sections 2.1 and 2.2 above.  
+
+4.	Larger Works.  You may create a Larger Work by combining Covered Code
+with other code not governed by the terms of this License and distribute the
+Larger Work as a single product.  In each such instance, You must make sure the
+requirements of this License are fulfilled for the Covered Code or any portion
+thereof. 
+
+5.	Limitations on Patent License.   Except as expressly stated in Section
+2, no other patent rights, express or implied, are granted by Apple herein.
+Modifications and/or Larger Works may require additional patent licenses from
+Apple which Apple may grant in its sole discretion.  
+
+6.	Additional Terms.  You may choose to offer, and to charge a fee for,
+warranty, support, indemnity or liability obligations and/or other rights
+consistent with the scope of the license granted herein ("Additional Terms") to
+one or more recipients of Covered Code. However, You may do so only on Your own
+behalf and as Your sole responsibility, and not on behalf of Apple or any
+Contributor. You must obtain the recipient's agreement that any such Additional
+Terms are offered by You alone, and You hereby agree to indemnify, defend and
+hold Apple and every Contributor harmless for any liability incurred by or
+claims asserted against Apple or such Contributor by reason of any such
+Additional Terms. 
+
+7.	Versions of the License.  Apple may publish revised and/or new versions
+of this License from time to time.  Each version will be given a distinguishing
+version number.  Once Original Code has been published under a particular
+version of this License, You may continue to use it under the terms of that
+version. You may also choose to use such Original Code under the terms of any
+subsequent version of this License published by Apple.  No one other than Apple
+has the right to modify the terms applicable to Covered Code created under this
+License.  
+
+8.	NO WARRANTY OR SUPPORT.  The Covered Code may contain in whole or in
+part pre-release, untested, or not fully tested works.  The Covered Code may
+contain errors that could cause failures or loss of data, and may be incomplete
+or contain inaccuracies.  You expressly acknowledge and agree that use of the
+Covered Code, or any portion thereof, is at Your sole and entire risk.  THE
+COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF
+ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE"
+FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM
+ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF
+SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF
+QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.  APPLE AND EACH
+CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE
+COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR
+REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR
+ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED.  NO ORAL OR
+WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED
+REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY.  You acknowledge
+that the Covered Code is not intended for use in the operation of nuclear
+facilities, aircraft navigation, communication systems, or air traffic control
+machines in which case the failure of the Covered Code could lead to death,
+personal injury, or severe physical or environmental damage.
+
+9.	LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO
+EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL,
+INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR
+YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER
+UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS
+LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF
+THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL
+PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF
+LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT
+APPLY TO YOU. In no event shall Apple's total liability to You for all damages
+(other than as may be required by applicable law) under this License exceed the
+amount of fifty dollars ($50.00).
+
+10.	Trademarks.  This License does not grant any rights to use the
+trademarks or trade names  "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime
+Streaming Server" or any other trademarks, service marks, logos or trade names
+belonging to Apple (collectively "Apple Marks") or to any trademark, service
+mark, logo or trade name belonging to any Contributor.  You agree not to use
+any Apple Marks in or as part of the name of products derived from the Original
+Code or to endorse or promote products derived from the Original Code other
+than as expressly permitted by and in strict compliance at all times with
+Apple's third party trademark usage guidelines which are posted at
+http://www.apple.com/legal/guidelinesfor3rdparties.html.  
+
+11.	Ownership. Subject to the licenses granted under this License, each
+Contributor retains all rights, title and interest in and to any Modifications
+made by such Contributor.  Apple retains all rights, title and interest in and
+to the Original Code and any Modifications made by or on behalf of Apple
+("Apple Modifications"), and such Apple Modifications will not be automatically
+subject to this License.  Apple may, at its sole discretion, choose to license
+such Apple Modifications under this License, or on different terms from those
+contained in this License or may choose not to license them at all.  
+
+12.	Termination.  
+
+12.1	Termination.  This License and the rights granted hereunder will
+terminate:
+
+(a)	automatically without notice from Apple if You fail to comply with any
+term(s) of this License and fail to cure such breach within 30 days of becoming
+aware of such breach;
+(b)	immediately in the event of the circumstances described in Section
+13.5(b); or
+(c)	automatically without notice from Apple if You, at any time during the
+term of this License, commence an action for patent infringement against Apple;
+provided that Apple did not first commence an action for patent infringement
+against You in that instance.
+
+12.2	Effect of Termination.  Upon termination, You agree to immediately stop
+any further use, reproduction, modification, sublicensing and distribution of
+the Covered Code.  All sublicenses to the Covered Code which have been properly
+granted prior to termination shall survive any termination of this License.
+Provisions which, by their nature, should remain in effect beyond the
+termination of this License shall survive, including but not limited to
+Sections 3, 5, 8, 9, 10, 11, 12.2 and 13.  No party will be liable to any other
+for compensation, indemnity or damages of any sort solely as a result of
+terminating this License in accordance with its terms, and termination of this
+License will be without prejudice to any other right or remedy of any party.
+
+13. 	Miscellaneous.
+
+13.1	Government End Users.   The Covered Code is a "commercial item" as
+defined in FAR 2.101.  Government software and technical data rights in the
+Covered Code include only those rights customarily provided to the public as
+defined in this License. This customary commercial license in technical data
+and software is provided in accordance with FAR 12.211 (Technical Data) and
+12.212 (Computer Software) and, for Department of Defense purchases, DFAR
+252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in
+Commercial Computer Software or Computer Software Documentation).  Accordingly,
+all U.S. Government End Users acquire Covered Code with only those rights set
+forth herein.
+
+13.2	Relationship of Parties.  This License will not be construed as
+creating an agency, partnership, joint venture or any other form of legal
+association between or among You, Apple or any Contributor, and You will not
+represent to the contrary, whether expressly, by implication, appearance or
+otherwise.
+
+13.3	Independent Development.   Nothing in this License will impair Apple's
+right to acquire, license, develop, have others develop for it, market and/or
+distribute technology or products that perform the same or similar functions
+as, or otherwise compete with, Modifications, Larger Works, technology or
+products that You may develop, produce, market or distribute.
+
+13.4	Waiver; Construction.  Failure by Apple or any Contributor to enforce
+any provision of this License will not be deemed a waiver of future enforcement
+of that or any other provision.  Any law or regulation which provides that the
+language of a contract shall be construed against the drafter will not apply to
+this License.
+
+13.5	Severability.  (a) If for any reason a court of competent jurisdiction
+finds any provision of this License, or portion thereof, to be unenforceable,
+that provision of the License will be enforced to the maximum extent
+permissible so as to effect the economic benefits and intent of the parties,
+and the remainder of this License will continue in full force and effect.  (b)
+Notwithstanding the foregoing, if applicable law prohibits or restricts You
+from fully and/or specifically complying with Sections 2 and/or 3 or prevents
+the enforceability of either of those Sections, this License will immediately
+terminate and You must immediately discontinue any use of the Covered Code and
+destroy all copies of it that are in your possession or control.
+
+13.6	Dispute Resolution.  Any litigation or other dispute resolution between
+You and Apple relating to this License shall take place in the Northern
+District of California, and You and Apple hereby consent to the personal
+jurisdiction of, and venue in, the state and federal courts within that
+District with respect to this License. The application of the United Nations
+Convention on Contracts for the International Sale of Goods is expressly
+excluded.
+
+13.7	Entire Agreement; Governing Law.  This License constitutes the entire
+agreement between the parties with respect to the subject matter hereof.  This
+License shall be governed by the laws of the United States and the State of
+California, except that body of California law concerning conflicts of law. 
+
+Where You are located in the province of Quebec, Canada, the following clause
+applies:  The parties hereby confirm that they have requested that this License
+and all related documents be drafted in English. Les parties ont exigé que le
+présent contrat et tous les documents connexes soient rédigés en anglais. 
+
+EXHIBIT A. 
+
+"Portions Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.
+
+This file contains Original Code and/or Modifications of Original Code as
+defined in and that are subject to the Apple Public Source License Version 2.0
+(the 'License').  You may not use this file except in compliance with the
+License.  Please obtain a copy of the License at
+http://www.opensource.apple.com/apsl/ and read it before using this file.
+
+The Original Code and all software distributed under the License are
+distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
+OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
+LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.  Please see the License for the
+specific language governing rights and limitations under the License." 
+

+ 177 - 0
components/spotify/cspot/bell/external/alac/codec/EndianPortable.c

@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+//
+//  EndianPortable.c
+//
+//  Copyright 2011 Apple Inc. All rights reserved.
+//
+
+#include <stdio.h>
+#include "EndianPortable.h"
+
+#define BSWAP16(x) (((x << 8) | ((x >> 8) & 0x00ff)))
+#define BSWAP32(x) (((x << 24) | ((x << 8) & 0x00ff0000) | ((x >> 8) & 0x0000ff00) | ((x >> 24) & 0x000000ff)))
+#define BSWAP64(x) ((((int64_t)x << 56) | (((int64_t)x << 40) & 0x00ff000000000000LL) | \
+                    (((int64_t)x << 24) & 0x0000ff0000000000LL) | (((int64_t)x << 8) & 0x000000ff00000000LL) | \
+                    (((int64_t)x >> 8) & 0x00000000ff000000LL) | (((int64_t)x >> 24) & 0x0000000000ff0000LL) | \
+                    (((int64_t)x >> 40) & 0x000000000000ff00LL) | (((int64_t)x >> 56) & 0x00000000000000ffLL)))
+
+#if defined(__i386__)
+#define TARGET_RT_LITTLE_ENDIAN 1
+#elif defined(__x86_64__)
+#define TARGET_RT_LITTLE_ENDIAN 1
+#elif defined (TARGET_OS_WIN32)
+#define TARGET_RT_LITTLE_ENDIAN 1
+#elif defined (__arm__) || defined(__aarch64__)
+#define TARGET_RT_LITTLE_ENDIAN 1
+#endif
+
+uint16_t Swap16NtoB(uint16_t inUInt16)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP16(inUInt16);
+#else
+    return inUInt16;
+#endif
+}
+
+uint16_t Swap16BtoN(uint16_t inUInt16)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP16(inUInt16);
+#else
+    return inUInt16;
+#endif
+}
+
+uint32_t Swap32NtoB(uint32_t inUInt32)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP32(inUInt32);
+#else
+    return inUInt32;
+#endif
+}
+
+uint32_t Swap32BtoN(uint32_t inUInt32)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP32(inUInt32);
+#else
+    return inUInt32;
+#endif
+}
+
+uint64_t Swap64BtoN(uint64_t inUInt64)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP64(inUInt64);
+#else
+    return inUInt64;
+#endif
+}
+
+uint64_t Swap64NtoB(uint64_t inUInt64)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+    return BSWAP64(inUInt64);
+#else
+    return inUInt64;
+#endif
+}
+
+float SwapFloat32BtoN(float in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		float f;
+		int32_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP32(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+float SwapFloat32NtoB(float in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		float f;
+		int32_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP32(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+double SwapFloat64BtoN(double in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		double f;
+		int64_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP64(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+double SwapFloat64NtoB(double in)
+{
+#if TARGET_RT_LITTLE_ENDIAN
+	union {
+		double f;
+		int64_t i;
+	} x;
+	x.f = in;	
+	x.i = BSWAP64(x.i);
+	return x.f;
+#else
+	return in;
+#endif
+}
+
+void Swap16(uint16_t * inUInt16)
+{
+	*inUInt16 = BSWAP16(*inUInt16);
+}
+
+void Swap24(uint8_t * inUInt24)
+{
+	uint8_t tempVal = inUInt24[0];
+	inUInt24[0] = inUInt24[2];
+	inUInt24[2] = tempVal;
+}
+
+void Swap32(uint32_t * inUInt32)
+{
+	*inUInt32 = BSWAP32(*inUInt32);
+}
+

+ 59 - 0
components/spotify/cspot/bell/external/alac/codec/EndianPortable.h

@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+//
+//  EndianPortable.h
+//
+//  Copyright 2011 Apple Inc. All rights reserved.
+//
+
+#ifndef _EndianPortable_h
+#define _EndianPortable_h
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+uint16_t Swap16NtoB(uint16_t inUInt16);
+uint16_t Swap16BtoN(uint16_t inUInt16);
+
+uint32_t Swap32NtoB(uint32_t inUInt32);
+uint32_t Swap32BtoN(uint32_t inUInt32);
+
+uint64_t Swap64BtoN(uint64_t inUInt64);
+uint64_t Swap64NtoB(uint64_t inUInt64);
+
+float SwapFloat32BtoN(float in);
+float SwapFloat32NtoB(float in);
+
+double SwapFloat64BtoN(double in);
+double SwapFloat64NtoB(double in);
+
+void Swap16(uint16_t * inUInt16);
+void Swap24(uint8_t * inUInt24);
+void Swap32(uint32_t * inUInt32);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 362 - 0
components/spotify/cspot/bell/external/alac/codec/ag_dec.c

@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ag_dec.c
+	
+	Contains:   Adaptive Golomb decode routines.
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+#include "aglib.h"
+#include "ALACBitUtilities.h"
+#include "ALACAudioTypes.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if __GNUC__ && TARGET_OS_MAC
+	#if __POWERPC__
+		#include <ppc_intrinsics.h>
+	#else
+		#include <libkern/OSByteOrder.h>
+	#endif
+#endif
+
+#define CODE_TO_LONG_MAXBITS	32
+#define N_MAX_MEAN_CLAMP		0xffff
+#define N_MEAN_CLAMP_VAL		0xffff
+#define REPORT_VAL  40
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+/*	And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
+	to help the compiler out.   In many cases this required manual inlining or a macro.  Sorry
+	if it is ugly but the performance gains are well worth it.
+	- WSK 5/19/04
+*/
+
+void set_standard_ag_params(AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth)
+{
+	/* Use
+		fullwidth = sectorwidth = numOfSamples, for analog 1-dimensional type-short data,
+		but use
+		fullwidth = full image width, sectorwidth = sector (patch) width
+		for such as image (2-dim.) data.
+	*/
+	set_ag_params( params, MB0, PB0, KB0, fullwidth, sectorwidth, MAX_RUN_DEFAULT );
+}
+
+void set_ag_params(AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun)
+{
+	params->mb = params->mb0 = m;
+	params->pb = p;
+	params->kb = k;
+	params->wb = (1u<<params->kb)-1;
+	params->qb = QB-params->pb; 
+	params->fw = f;
+	params->sw = s;
+	params->maxrun = maxrun;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+
+// note: implementing this with some kind of "count leading zeros" assembly is a big performance win
+static inline int32_t lead( int32_t m )
+{
+	long j;
+	unsigned long c = (1ul << 31);
+
+	for(j=0; j < 32; j++)
+	{
+		if((c & m) != 0)
+			break;
+		c >>= 1;
+	}
+	return (j);
+}
+
+#define arithmin(a, b) ((a) < (b) ? (a) : (b))
+
+static inline int32_t ALWAYS_INLINE lg3a( int32_t x)
+{
+    int32_t result;
+
+    x += 3;
+    result = lead(x);
+
+    return 31 - result;
+}
+
+static inline uint32_t ALWAYS_INLINE read32bit( uint8_t * buffer )
+{
+	// embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
+	uint32_t		value;
+	
+	value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
+			 ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
+	return value;
+
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+#define get_next_fromlong(inlong, suff)		((inlong) >> (32 - (suff)))
+
+
+static inline uint32_t ALWAYS_INLINE
+getstreambits( uint8_t *in, int32_t bitoffset, int32_t numbits )
+{
+	uint32_t	load1, load2;
+	uint32_t	byteoffset = bitoffset / 8;
+	uint32_t	result;
+	
+	//Assert( numbits <= 32 );
+
+	load1 = read32bit( in + byteoffset );
+
+	if ( (numbits + (bitoffset & 0x7)) > 32)
+	{
+		int32_t load2shift;
+
+		result = load1 << (bitoffset & 0x7);
+		load2 = (uint32_t) in[byteoffset+4];
+		load2shift = (8-(numbits + (bitoffset & 0x7)-32));
+		load2 >>= load2shift;
+		result >>= (32-numbits);
+		result |= load2;		
+	}
+	else
+	{
+		result = load1 >> (32-numbits-(bitoffset & 7));
+	}
+
+	// a shift of >= "the number of bits in the type of the value being shifted" results in undefined
+	// behavior so don't try to shift by 32
+	if ( numbits != (sizeof(result) * 8) )
+		result &= ~(0xfffffffful << numbits);
+	
+	return result;
+}
+
+
+static inline int32_t dyn_get(unsigned char *in, uint32_t *bitPos, uint32_t m, uint32_t k)
+{
+    uint32_t	tempbits = *bitPos;
+    uint32_t		result;
+    uint32_t		pre = 0, v;
+    uint32_t		streamlong;
+
+	streamlong = read32bit( in + (tempbits >> 3) );
+    streamlong <<= (tempbits & 7);
+
+    /* find the number of bits in the prefix */ 
+    {
+        uint32_t	notI = ~streamlong;
+    	pre = lead( notI);
+    }
+
+    if(pre >= MAX_PREFIX_16)
+    {
+        pre = MAX_PREFIX_16;
+        tempbits += pre;
+        streamlong <<= pre;
+        result = get_next_fromlong(streamlong,MAX_DATATYPE_BITS_16);
+        tempbits += MAX_DATATYPE_BITS_16;
+
+    }
+    else
+    {
+        // all of the bits must fit within the long we have loaded
+        //Assert(pre+1+k <= 32);
+
+        tempbits += pre;
+        tempbits += 1;
+        streamlong <<= pre+1;
+        v = get_next_fromlong(streamlong, k);
+        tempbits += k;
+    
+        result = pre*m + v-1;
+
+        if(v<2) {
+            result -= (v-1);
+            tempbits -= 1;
+        }
+    }
+
+    *bitPos = tempbits;
+    return result;
+}
+
+
+static inline int32_t dyn_get_32bit( uint8_t * in, uint32_t * bitPos, int32_t m, int32_t k, int32_t maxbits )
+{
+	uint32_t	tempbits = *bitPos;
+	uint32_t		v;
+	uint32_t		streamlong;
+	uint32_t		result;
+	
+	streamlong = read32bit( in + (tempbits >> 3) );
+	streamlong <<= (tempbits & 7);
+
+	/* find the number of bits in the prefix */ 
+	{
+		uint32_t notI = ~streamlong;
+		result = lead( notI);
+	}
+	
+	if(result >= MAX_PREFIX_32)
+	{
+		result = getstreambits(in, tempbits+MAX_PREFIX_32, maxbits);
+		tempbits += MAX_PREFIX_32 + maxbits;
+	}
+	else
+	{		
+		/* all of the bits must fit within the long we have loaded*/
+		//Assert(k<=14);
+		//Assert(result<MAX_PREFIX_32);
+		//Assert(result+1+k <= 32);
+		
+		tempbits += result;
+		tempbits += 1;
+		
+		if (k != 1)
+		{
+			streamlong <<= result+1;
+			v = get_next_fromlong(streamlong, k);
+			tempbits += k;
+			tempbits -= 1;
+			result = result*m;
+			
+			if(v>=2)
+			{
+				result += (v-1);
+				tempbits += 1;
+			}
+		}
+	}
+
+	*bitPos = tempbits;
+
+	return result;
+}
+
+int32_t dyn_decomp( AGParamRecPtr params, BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits )
+{
+    uint8_t 		*in;
+    int32_t			*outPtr = pc;
+    uint32_t 	bitPos, startPos, maxPos;
+    uint32_t		j, m, k, n, c, mz;
+    int32_t			del, zmode;
+    uint32_t 	mb;
+    uint32_t	pb_local = params->pb;
+    uint32_t	kb_local = params->kb;
+    uint32_t	wb_local = params->wb;
+    int32_t				status;
+
+	RequireAction( (bitstream != nil) && (pc != nil) && (outNumBits != nil), return kALAC_ParamError; );
+	*outNumBits = 0;
+
+	in = bitstream->cur;
+	startPos = bitstream->bitIndex;
+	maxPos = bitstream->byteSize * 8;
+	bitPos = startPos;
+
+    mb = params->mb0;
+    zmode = 0;
+
+    c = 0;
+	status = ALAC_noErr;
+
+    while (c < numSamples)
+    {
+		// bail if we've run off the end of the buffer
+    	RequireAction( bitPos < maxPos, status = kALAC_ParamError; goto Exit; );
+
+        m = (mb)>>QBSHIFT;
+        k = lg3a(m);
+
+        k = arithmin(k, kb_local);
+        m = (1<<k)-1;
+        
+		n = dyn_get_32bit( in, &bitPos, m, k, maxSize );
+
+        // least significant bit is sign bit
+        {
+        	uint32_t	ndecode = n + zmode;
+            int32_t		multiplier = (- (ndecode&1));
+
+            multiplier |= 1;
+            del = ((ndecode+1) >> 1) * (multiplier);
+        }
+
+        *outPtr++ = del;
+
+        c++;
+
+        mb = pb_local*(n+zmode) + mb - ((pb_local*mb)>>QBSHIFT);
+
+		// update mean tracking
+		if (n > N_MAX_MEAN_CLAMP)
+			mb = N_MEAN_CLAMP_VAL;
+
+        zmode = 0;
+
+        if (((mb << MMULSHIFT) < QB) && (c < numSamples))
+        {
+            zmode = 1;
+            k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT);
+            mz = ((1<<k)-1) & wb_local;
+
+            n = dyn_get(in, &bitPos, mz, k);
+
+            RequireAction(c+n <= numSamples, status = kALAC_ParamError; goto Exit; );
+
+            for(j=0; j < n; j++)
+            {
+                *outPtr++ = 0;
+                ++c;                    
+            }
+
+            if(n >= 65535)
+            	zmode = 0;
+
+            mb = 0;
+        }
+    }
+
+Exit:
+	*outNumBits = (bitPos - startPos);
+	BitBufferAdvance( bitstream, *outNumBits );
+	RequireAction( bitstream->cur <= bitstream->end, status = kALAC_ParamError; );
+
+    return status;
+}

+ 370 - 0
components/spotify/cspot/bell/external/alac/codec/ag_enc.c

@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		ag_enc.c
+	
+	Contains:   Adaptive Golomb encode routines.
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+#include "aglib.h"
+#include "ALACBitUtilities.h"
+#include "EndianPortable.h"
+#include "ALACAudioTypes.h"
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if __GNUC__ && TARGET_OS_MAC
+	#if __POWERPC__
+		#include <ppc_intrinsics.h>
+	#else
+		#include <libkern/OSByteOrder.h>
+	#endif
+#endif
+
+#define CODE_TO_LONG_MAXBITS	32
+#define N_MAX_MEAN_CLAMP		0xffff
+#define N_MEAN_CLAMP_VAL		0xffff
+#define REPORT_VAL  40
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+
+/*	And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this
+	to help the compiler out.   In many cases this required manual inlining or a macro.  Sorry
+	if it is ugly but the performance gains are well worth it.
+	- WSK 5/19/04
+*/
+
+// note: implementing this with some kind of "count leading zeros" assembly is a big performance win
+static inline int32_t lead( int32_t m )
+{
+	long j;
+	unsigned long c = (1ul << 31);
+
+	for(j=0; j < 32; j++)
+	{
+		if((c & m) != 0)
+			break;
+		c >>= 1;
+	}
+	return (j);
+}
+
+#define arithmin(a, b) ((a) < (b) ? (a) : (b))
+
+static inline int32_t ALWAYS_INLINE lg3a( int32_t x)
+{
+    int32_t result;
+
+    x += 3;
+    result = lead(x);
+
+    return 31 - result;
+}
+
+static inline int32_t ALWAYS_INLINE abs_func( int32_t a )
+{
+	// note: the CW PPC intrinsic __abs() turns into these instructions so no need to try and use it
+	int32_t isneg  = a >> 31;
+	int32_t xorval = a ^ isneg;
+	int32_t result = xorval-isneg;
+	
+	return result;	
+}
+
+static inline uint32_t ALWAYS_INLINE read32bit( uint8_t * buffer )
+{
+	// embedded CPUs typically can't read unaligned 32-bit words so just read the bytes
+	uint32_t		value;
+	
+	value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) |
+			 ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3];
+	return value;
+}
+
+#if PRAGMA_MARK
+#pragma mark -
+#endif
+
+static inline int32_t dyn_code(int32_t m, int32_t k, int32_t n, uint32_t *outNumBits)
+{
+	uint32_t 	div, mod, de;
+	uint32_t	numBits;
+	uint32_t	value;
+
+	//Assert( n >= 0 );
+
+	div = n/m;
+
+	if(div >= MAX_PREFIX_16)
+	{
+		numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
+		value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;
+	}
+	else
+	{
+		mod = n%m;
+		de = (mod == 0);
+		numBits = div + k + 1 - de;
+		value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;
+
+		// if coding this way is bigger than doing escape, then do escape
+		if (numBits > MAX_PREFIX_16 + MAX_DATATYPE_BITS_16)
+		{
+		    numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16;
+		    value = (((1<<MAX_PREFIX_16)-1)<<MAX_DATATYPE_BITS_16) + n;            
+		}
+	}
+	
+	*outNumBits = numBits;
+
+	return (int32_t) value;
+}
+
+
+static inline int32_t dyn_code_32bit(int32_t maxbits, uint32_t m, uint32_t k, uint32_t n, uint32_t *outNumBits, uint32_t *outValue, uint32_t *overflow, uint32_t *overflowbits)
+{
+	uint32_t 	div, mod, de;
+	uint32_t	numBits;
+	uint32_t	value;
+	int32_t			didOverflow = 0;
+
+	div = n/m;
+
+	if (div < MAX_PREFIX_32)
+	{
+		mod = n - (m * div);
+
+		de = (mod == 0);
+		numBits = div + k + 1 - de;
+		value = (((1<<div)-1)<<(numBits-div)) + mod + 1 - de;		
+		if (numBits > 25)
+			goto codeasescape;
+	}
+	else
+	{
+codeasescape:
+		numBits = MAX_PREFIX_32;
+		value = (((1<<MAX_PREFIX_32)-1));
+		*overflow = n;
+		*overflowbits = maxbits;
+		didOverflow = 1;
+	}
+	
+	*outNumBits = numBits;
+	*outValue = value;
+
+	return didOverflow;
+}
+
+
+static inline void ALWAYS_INLINE dyn_jam_noDeref(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
+{
+	uint32_t	*i = (uint32_t *)(out + (bitPos >> 3));
+	uint32_t	mask;
+	uint32_t	curr;
+	uint32_t	shift;
+
+	//Assert( numBits <= 32 );
+
+	curr = *i;
+	curr = Swap32NtoB( curr );
+
+	shift = 32 - (bitPos & 7) - numBits;
+
+	mask = ~0u >> (32 - numBits);		// mask must be created in two steps to avoid compiler sequencing ambiguity
+	mask <<= shift;
+
+	value  = (value << shift) & mask;
+	value |= curr & ~mask;
+	
+	*i = Swap32BtoN( value );
+}
+
+
+static inline void ALWAYS_INLINE dyn_jam_noDeref_large(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value)
+{
+	uint32_t *	i = (uint32_t *)(out + (bitPos>>3));
+	uint32_t	w;
+	uint32_t	curr;
+	uint32_t	mask;
+	int32_t			shiftvalue = (32 - (bitPos&7) - numBits);
+	
+	//Assert(numBits <= 32);
+
+	curr = *i;
+	curr = Swap32NtoB( curr );
+
+	if (shiftvalue < 0)
+	{
+		uint8_t 	tailbyte;
+		uint8_t 	*tailptr;
+
+		w = value >> -shiftvalue;
+		mask = ~0u >> -shiftvalue;
+		w |= (curr & ~mask);
+
+		tailptr = ((uint8_t *)i) + 4;
+		tailbyte = (value << ((8+shiftvalue))) & 0xff;
+		*tailptr = (uint8_t)tailbyte;
+	}
+	else
+	{
+		mask = ~0u >> (32 - numBits);
+		mask <<= shiftvalue;			// mask must be created in two steps to avoid compiler sequencing ambiguity
+
+		w  = (value << shiftvalue) & mask;
+		w |= curr & ~mask;
+	}
+	
+	*i = Swap32BtoN( w );
+}
+
+
+int32_t dyn_comp( AGParamRecPtr params, int32_t * pc, BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits )
+{
+    unsigned char *		out;
+    uint32_t		bitPos, startPos;
+    uint32_t			m, k, n, c, mz, nz;
+    uint32_t		numBits;
+    uint32_t			value;
+    int32_t				del, zmode;
+	uint32_t		overflow, overflowbits;
+    int32_t					status;
+
+    // shadow the variables in params so there's not the dereferencing overhead
+    uint32_t		mb, pb, kb, wb;
+    int32_t					rowPos = 0;
+    int32_t					rowSize = params->sw;
+    int32_t					rowJump = (params->fw) - rowSize;
+    int32_t *			inPtr = pc;
+
+	*outNumBits = 0;
+	RequireAction( (bitSize >= 1) && (bitSize <= 32), return kALAC_ParamError; );
+
+	out = bitstream->cur;
+	startPos = bitstream->bitIndex;
+    bitPos = startPos;
+
+    mb = params->mb = params->mb0;
+    pb = params->pb;
+    kb = params->kb;
+    wb = params->wb;
+    zmode = 0;
+
+    c=0;
+	status = ALAC_noErr;
+
+    while (c < numSamples)
+    {
+        m  = mb >> QBSHIFT;
+        k = lg3a(m);
+        if ( k > kb)
+        {
+        	k = kb;
+        }
+        m = (1<<k)-1;
+
+        del = *inPtr++;
+        rowPos++;
+
+        n = (abs_func(del) << 1) - ((del >> 31) & 1) - zmode;
+		//Assert( 32-lead(n) <= bitSize );
+
+		if ( dyn_code_32bit(bitSize, m, k, n, &numBits, &value, &overflow, &overflowbits) )
+		{
+			dyn_jam_noDeref(out, bitPos, numBits, value);
+			bitPos += numBits;			
+			dyn_jam_noDeref_large(out, bitPos, overflowbits, overflow);			
+			bitPos += overflowbits;
+		}
+		else
+		{
+			dyn_jam_noDeref(out, bitPos, numBits, value);
+			bitPos += numBits;
+		}
+      
+        c++;
+        if ( rowPos >= rowSize)
+        {
+        	rowPos = 0;
+        	inPtr += rowJump;
+        }
+
+        mb = pb * (n + zmode) + mb - ((pb *mb)>>QBSHIFT);
+
+		// update mean tracking if it's overflowed
+		if (n > N_MAX_MEAN_CLAMP)
+			mb = N_MEAN_CLAMP_VAL;
+
+        zmode = 0;
+
+        RequireAction(c <= numSamples, status = kALAC_ParamError; goto Exit; );
+
+        if (((mb << MMULSHIFT) < QB) && (c < numSamples))
+        {
+            zmode = 1;
+            nz = 0;
+
+            while(c<numSamples && *inPtr == 0)
+            {
+            	/* Take care of wrap-around globals. */
+                ++inPtr;
+                ++nz;
+                ++c;
+                if ( ++rowPos >= rowSize)
+                {
+                	rowPos = 0;
+                	inPtr += rowJump;
+                }
+
+                if(nz >= 65535)
+                {
+                	zmode = 0;
+                	break;
+                }
+            }
+
+            k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT);
+            mz = ((1<<k)-1) & wb;
+
+            value = dyn_code(mz, k, nz, &numBits);
+            dyn_jam_noDeref(out, bitPos, numBits, value);
+            bitPos += numBits;
+
+            mb = 0;
+        }
+    }
+
+    *outNumBits = (bitPos - startPos);
+	BitBufferAdvance( bitstream, *outNumBits );
+
+Exit:
+	return status;
+}

+ 81 - 0
components/spotify/cspot/bell/external/alac/codec/aglib.h

@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		aglib.h
+	
+	Copyright:	(C) 2001-2011 Apple, Inc.
+*/
+
+#ifndef AGLIB_H
+#define AGLIB_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define QBSHIFT 9
+#define QB (1<<QBSHIFT)
+#define PB0 40
+#define MB0 10
+#define KB0 14
+#define MAX_RUN_DEFAULT 255
+
+#define MMULSHIFT 2
+#define MDENSHIFT (QBSHIFT - MMULSHIFT - 1)
+#define MOFF ((1<<(MDENSHIFT-2)))
+
+#define BITOFF 24
+
+/* Max. prefix of 1's. */
+#define MAX_PREFIX_16			9
+#define MAX_PREFIX_TOLONG_16	15
+#define MAX_PREFIX_32			9
+
+/* Max. bits in 16-bit data type */
+#define MAX_DATATYPE_BITS_16	16
+
+typedef struct AGParamRec
+{
+    uint32_t mb, mb0, pb, kb, wb, qb;
+    uint32_t fw, sw;
+
+    uint32_t maxrun;
+
+    // fw = 1, sw = 1;
+
+} AGParamRec, *AGParamRecPtr;
+
+struct BitBuffer;
+
+void	set_standard_ag_params(AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth);
+void	set_ag_params(AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun);
+
+int32_t		dyn_comp(AGParamRecPtr params, int32_t * pc, struct BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits);
+int32_t		dyn_decomp(AGParamRecPtr params, struct BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //#ifndef AGLIB_H

+ 85 - 0
components/spotify/cspot/bell/external/alac/codec/alac.vcxproj

@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemGroup Label="ProjectConfigurations">
+    <ProjectConfiguration Include="Release|Win32">
+      <Configuration>Release</Configuration>
+      <Platform>Win32</Platform>
+    </ProjectConfiguration>
+    <ProjectConfiguration Include="Release|x64">
+      <Configuration>Release</Configuration>
+      <Platform>x64</Platform>
+    </ProjectConfiguration>
+  </ItemGroup>
+  <ItemGroup>
+    <ClCompile Include="ag_dec.c" />
+    <ClCompile Include="ag_enc.c" />
+    <ClCompile Include="ALACBitUtilities.c" />
+    <ClCompile Include="ALACDecoder.cpp" />
+    <ClCompile Include="ALACEncoder.cpp" />
+    <ClCompile Include="dp_dec.c" />
+    <ClCompile Include="dp_enc.c" />
+    <ClCompile Include="EndianPortable.c" />
+    <ClCompile Include="matrix_dec.c" />
+    <ClCompile Include="matrix_enc.c" />
+  </ItemGroup>
+  <PropertyGroup Label="Globals">
+    <VCProjectVersion>16.0</VCProjectVersion>
+    <Keyword>Win32Proj</Keyword>
+    <ProjectGuid>{73ae36f4-6af9-46b0-a682-4321d57ef8e7}</ProjectGuid>
+    <RootNamespace>alac</RootNamespace>
+    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <PropertyGroup>
+    <IntDir>build\$(Configuration)\$(Platform)</IntDir>	
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <OutDir>..\targets\win32\x86</OutDir>	
+  </PropertyGroup>
+  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+    <ConfigurationType>StaticLibrary</ConfigurationType>
+    <UseDebugLibraries>false</UseDebugLibraries>
+    <PlatformToolset>v143</PlatformToolset>
+    <WholeProgramOptimization>true</WholeProgramOptimization>
+    <CharacterSet>Unicode</CharacterSet>
+    <OutDir>..\targets\win32\$(Platform)</OutDir>	
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ImportGroup Label="ExtensionSettings">
+  </ImportGroup>
+  <ImportGroup Label="Shared">
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+  </ImportGroup>
+  <PropertyGroup Label="UserMacros" />
+  <ItemDefinitionGroup>
+    <ClCompile>
+      <WarningLevel>Level3</WarningLevel>
+      <FunctionLevelLinking>true</FunctionLevelLinking>
+      <IntrinsicFunctions>true</IntrinsicFunctions>
+      <SDLCheck>false</SDLCheck>
+      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <ConformanceMode>true</ConformanceMode>
+      <PrecompiledHeader>NotUsing</PrecompiledHeader>
+    </ClCompile>
+    <Link>
+      <SubSystem>
+      </SubSystem>
+      <EnableCOMDATFolding>true</EnableCOMDATFolding>
+      <OptimizeReferences>true</OptimizeReferences>
+      <GenerateDebugInformation>true</GenerateDebugInformation>
+    </Link>
+  </ItemDefinitionGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+  <ImportGroup Label="ExtensionTargets">
+  </ImportGroup>
+</Project>

+ 42 - 0
components/spotify/cspot/bell/external/alac/codec/build.sh

@@ -0,0 +1,42 @@
+#!/bin/bash
+
+list="x86_64-linux-gnu-gcc i686-linux-gnu-gcc arm-linux-gnueabi-gcc aarch64-linux-gnu-gcc sparc64-linux-gnu-gcc mips-linux-gnu-gcc powerpc-linux-gnu-gcc"
+declare -A alias=( [i686-linux-gnu-gcc]=x86-linux-gnu-gcc )
+declare -a compilers
+
+IFS= read -ra candidates <<< "$list"
+
+# first select platforms/compilers
+for cc in ${candidates[@]}
+do
+	# check compiler first
+	if ! command -v $cc &> /dev/null; then
+		continue
+	fi
+	
+	if [[ $# == 0 ]]; then
+		compilers+=($cc)
+		continue
+	fi
+
+	for arg in $@
+	do
+		if [[ ${alias[$cc]:-$cc} =~ $arg ]]; then 
+			compilers+=($cc)
+		fi
+	done
+done
+
+for cc in ${compilers[@]}
+do
+	IFS=- read -r platform host dummy <<< ${alias[$cc]:-$cc}
+	
+	make clean && make CC=$cc
+	mkdir -p ../targets/$host/$platform
+	cp libalac.a $_
+done
+
+mkdir -p ../targets/include
+cp ALACAudioTypes.h $_
+cp ALACEncoder.h $_
+cp ALACDecoder.h $_

+ 381 - 0
components/spotify/cspot/bell/external/alac/codec/dp_dec.c

@@ -0,0 +1,381 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		dp_dec.c
+
+	Contains:	Dynamic Predictor decode routines
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+
+#include "dplib.h"
+#include <string.h>
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+#if TARGET_CPU_PPC && (__MWERKS__ >= 0x3200)
+// align loops to a 16 byte boundary to make the G5 happy
+#pragma function_align 16
+#define LOOP_ALIGN			asm { align 16 }
+#else
+#define LOOP_ALIGN
+#endif
+
+static inline int32_t ALWAYS_INLINE sign_of_int( int32_t i )
+{
+    int32_t negishift;
+	
+    negishift = ((uint32_t)-i) >> 31;
+    return negishift | (i >> 31);
+}
+
+void unpc_block( int32_t * pc1, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift )
+{
+	register int16_t	a0, a1, a2, a3;
+	register int32_t	b0, b1, b2, b3;
+	int32_t					j, k, lim;
+	int32_t				sum1, sg, sgn, top, dd;
+	int32_t *			pout;
+	int32_t				del, del0;
+	uint32_t			chanshift = 32 - chanbits;
+	int32_t				denhalf = 1<<(denshift-1);
+
+	out[0] = pc1[0];
+	if ( numactive == 0 )
+	{
+		// just copy if numactive == 0 (but don't bother if in/out pointers the same)
+		if ( (num > 1)  && (pc1 != out) )
+			memcpy( &out[1], &pc1[1], (num - 1) * sizeof(int32_t) );
+		return;
+	}
+	if ( numactive == 31 )
+	{
+		// short-circuit if numactive == 31
+		int32_t		prev;
+		
+		/*	this code is written such that the in/out buffers can be the same
+			to conserve buffer space on embedded devices like the iPod
+			
+			(original code)
+			for ( j = 1; j < num; j++ )
+				del = pc1[j] + out[j-1];
+				out[j] = (del << chanshift) >> chanshift;
+		*/
+		prev = out[0];
+		for ( j = 1; j < num; j++ )
+		{
+			del = pc1[j] + prev;
+			prev = (del << chanshift) >> chanshift;
+			out[j] = prev;
+		}
+		return;
+	}
+
+	for ( j = 1; j <= numactive; j++ )
+	{
+		del = pc1[j] + out[j-1];
+		out[j] = (del << chanshift) >> chanshift;
+	}
+
+	lim = numactive + 1;
+
+	if ( numactive == 4 )
+	{
+		// optimization for numactive == 4
+		register int16_t	a0, a1, a2, a3;
+		register int32_t	b0, b1, b2, b3;
+
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = out[j - lim];
+			pout = out + j - 1;
+
+			b0 = top - pout[0];
+			b1 = top - pout[-1];
+			b2 = top - pout[-2];
+			b3 = top - pout[-3];
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift;
+
+			del = pc1[j];
+			del0 = del;
+			sg = sign_of_int(del);
+			del += top + sum1;
+
+			out[j] = (del << chanshift) >> chanshift;
+
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+	}
+	else if ( numactive == 8 )
+	{
+		register int16_t	a4, a5, a6, a7;
+		register int32_t	b4, b5, b6, b7;
+
+		// optimization for numactive == 8
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+		a4 = coefs[4];
+		a5 = coefs[5];
+		a6 = coefs[6];
+		a7 = coefs[7];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = out[j - lim];
+			pout = out + j - 1;
+
+			b0 = top - (*pout--);
+			b1 = top - (*pout--);
+			b2 = top - (*pout--);
+			b3 = top - (*pout--);
+			b4 = top - (*pout--);
+			b5 = top - (*pout--);
+			b6 = top - (*pout--);
+			b7 = top - (*pout);
+			pout += 8;
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3
+					- a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift;
+
+			del = pc1[j];
+			del0 = del;
+			sg = sign_of_int(del);
+			del += top + sum1;
+
+			out[j] = (del << chanshift) >> chanshift;
+
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				sgn = sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				sgn = -sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+		coefs[4] = a4;
+		coefs[5] = a5;
+		coefs[6] = a6;
+		coefs[7] = a7;
+	}
+	else
+	{
+		// general case
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			sum1 = 0;
+			pout = out + j - 1;
+			top = out[j-lim];
+
+			for ( k = 0; k < numactive; k++ )
+				sum1 += coefs[k] * (pout[-k] - top);
+
+			del = pc1[j];
+			del0 = del;
+			sg = sign_of_int( del );
+			del += top + ((sum1 + denhalf) >> denshift);
+			out[j] = (del << chanshift) >> chanshift;
+
+			if ( sg > 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pout[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] -= sgn;
+					del0 -= (numactive - k) * ((sgn * dd) >> denshift);
+					if ( del0 <= 0 )
+						break;
+				}
+			}
+			else if ( sg < 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pout[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] += sgn;
+					del0 -= (numactive - k) * ((-sgn * dd) >> denshift);
+					if ( del0 >= 0 )
+						break;
+				}
+			}
+		}
+	}
+}

+ 386 - 0
components/spotify/cspot/bell/external/alac/codec/dp_enc.c

@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		dp_enc.c
+
+	Contains:	Dynamic Predictor encode routines
+
+	Copyright:	(c) 2001-2011 Apple, Inc.
+*/
+
+#include "dplib.h"
+#include <string.h>
+
+#if __GNUC__
+#define ALWAYS_INLINE		__attribute__((always_inline))
+#else
+#define ALWAYS_INLINE
+#endif
+
+#if TARGET_CPU_PPC && (__MWERKS__ >= 0x3200)
+// align loops to a 16 byte boundary to make the G5 happy
+#pragma function_align 16
+#define LOOP_ALIGN			asm { align 16 }
+#else
+#define LOOP_ALIGN
+#endif
+
+void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs )
+{
+	int32_t		k;
+	int32_t		den = 1 << denshift;
+
+	coefs[0] = (AINIT * den) >> 4;
+	coefs[1] = (BINIT * den) >> 4;
+	coefs[2] = (CINIT * den) >> 4;
+	for ( k = 3; k < numPairs; k++ )
+		coefs[k]  = 0;
+}
+
+void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs )
+{
+	int32_t k;
+
+	for ( k = 0; k < numPairs; k++ )
+		dstCoefs[k] = srcCoefs[k];
+}
+
+static inline int32_t ALWAYS_INLINE sign_of_int( int32_t i )
+{
+    int32_t negishift;
+	
+    negishift = ((uint32_t)-i) >> 31;
+    return negishift | (i >> 31);
+}
+
+void pc_block( int32_t * in, int32_t * pc1, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift )
+{
+	register int16_t	a0, a1, a2, a3;
+	register int32_t	b0, b1, b2, b3;
+	int32_t					j, k, lim;
+	int32_t *			pin;
+	int32_t				sum1, dd;
+	int32_t				sg, sgn;
+	int32_t				top;
+	int32_t				del, del0;
+	uint32_t			chanshift = 32 - chanbits;
+	int32_t				denhalf = 1 << (denshift - 1);
+
+	pc1[0] = in[0];
+	if ( numactive == 0 )
+	{
+		// just copy if numactive == 0 (but don't bother if in/out pointers the same)
+		if ( (num > 1) && (in != pc1) )
+			memcpy( &pc1[1], &in[1], (num - 1) * sizeof(int32_t) );
+		return;
+	}
+	if ( numactive == 31 )
+	{
+		// short-circuit if numactive == 31
+		for( j = 1; j < num; j++ )
+		{
+			del = in[j] - in[j-1];
+			pc1[j] = (del << chanshift) >> chanshift;
+		}
+		return;
+	}
+	
+	for ( j = 1; j <= numactive; j++ )
+	{
+		del = in[j] - in[j-1];
+		pc1[j] = (del << chanshift) >> chanshift;
+	}
+
+	lim = numactive + 1;
+
+	if ( numactive == 4 )
+	{
+		// optimization for numactive == 4
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = in[j - lim];
+			pin = in + j - 1;
+
+			b0 = top - pin[0];
+			b1 = top - pin[-1];
+			b2 = top - pin[-2];
+			b3 = top - pin[-3];
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift;
+
+			del = in[j] - top - sum1;
+			del = (del << chanshift) >> chanshift;
+			pc1[j] = del;	     
+			del0 = del;
+
+			sg = sign_of_int(del);
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= (4 - 3) * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= (4 - 2) * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= (4 - 1) * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+	}
+	else if ( numactive == 8 )
+	{
+		// optimization for numactive == 8
+		register int16_t	a4, a5, a6, a7;
+		register int32_t	b4, b5, b6, b7;
+
+		a0 = coefs[0];
+		a1 = coefs[1];
+		a2 = coefs[2];
+		a3 = coefs[3];
+		a4 = coefs[4];
+		a5 = coefs[5];
+		a6 = coefs[6];
+		a7 = coefs[7];
+
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = in[j - lim];
+			pin = in + j - 1;
+
+			b0 = top - (*pin--);
+			b1 = top - (*pin--);
+			b2 = top - (*pin--);
+			b3 = top - (*pin--);
+			b4 = top - (*pin--);
+			b5 = top - (*pin--);
+			b6 = top - (*pin--);
+			b7 = top - (*pin);
+			pin += 8;
+
+			sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3
+					- a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift;
+
+			del = in[j] - top - sum1;
+			del = (del << chanshift) >> chanshift;
+			pc1[j] = del;	     
+			del0 = del;
+
+			sg = sign_of_int(del);
+			if ( sg > 0 )
+			{
+				sgn = sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				sgn = sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+				
+				sgn = sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 <= 0 )
+					continue;
+
+				a0 -= sign_of_int( b0 );
+			}
+			else if ( sg < 0 )
+			{
+				// note: to avoid unnecessary negations, we flip the value of "sgn"
+				sgn = -sign_of_int( b7 );
+				a7 -= sgn;
+				del0 -= 1 * ((sgn * b7) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b6 );
+				a6 -= sgn;
+				del0 -= 2 * ((sgn * b6) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b5 );
+				a5 -= sgn;
+				del0 -= 3 * ((sgn * b5) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				sgn = -sign_of_int( b4 );
+				a4 -= sgn;
+				del0 -= 4 * ((sgn * b4) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b3 );
+				a3 -= sgn;
+				del0 -= 5 * ((sgn * b3) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b2 );
+				a2 -= sgn;
+				del0 -= 6 * ((sgn * b2) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+				
+				sgn = -sign_of_int( b1 );
+				a1 -= sgn;
+				del0 -= 7 * ((sgn * b1) >> denshift);
+				if ( del0 >= 0 )
+					continue;
+
+				a0 += sign_of_int( b0 );
+			}
+		}
+
+		coefs[0] = a0;
+		coefs[1] = a1;
+		coefs[2] = a2;
+		coefs[3] = a3;
+		coefs[4] = a4;
+		coefs[5] = a5;
+		coefs[6] = a6;
+		coefs[7] = a7;
+	}
+	else
+	{
+//pc_block_general:
+		// general case
+		for ( j = lim; j < num; j++ )
+		{
+			LOOP_ALIGN
+
+			top = in[j - lim];
+			pin = in + j - 1;
+
+			sum1 = 0;
+			for ( k = 0; k < numactive; k++ )
+				sum1 -= coefs[k] * (top - pin[-k]);
+		
+			del = in[j] - top - ((sum1 + denhalf) >> denshift);
+			del = (del << chanshift) >> chanshift;
+			pc1[j] = del;
+			del0 = del;
+
+			sg = sign_of_int( del );
+			if ( sg > 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pin[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] -= sgn;
+					del0 -= (numactive - k) * ((sgn * dd) >> denshift);
+					if ( del0 <= 0 )
+						break;
+				}
+			}
+			else if ( sg < 0 )
+			{
+				for ( k = (numactive - 1); k >= 0; k-- )
+				{
+					dd = top - pin[-k];
+					sgn = sign_of_int( dd );
+					coefs[k] += sgn;
+					del0 -= (numactive - k) * ((-sgn * dd) >> denshift);
+					if ( del0 >= 0 )
+						break;
+				}
+			}
+		}
+	}
+}

+ 61 - 0
components/spotify/cspot/bell/external/alac/codec/dplib.h

@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		dplib.h
+	
+	Contains:	Dynamic Predictor routines
+
+	Copyright:	Copyright (C) 2001-2011 Apple, Inc.
+*/
+
+#ifndef __DPLIB_H__
+#define __DPLIB_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// defines
+
+#define DENSHIFT_MAX  15
+#define DENSHIFT_DEFAULT 9
+#define AINIT 38
+#define BINIT (-29)
+#define CINIT (-2)
+#define NUMCOEPAIRS 16
+
+// prototypes
+
+void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs );
+void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs );
+
+// NOTE: these routines read at least "numactive" samples so the i/o buffers must be at least that big
+
+void pc_block( int32_t * in, int32_t * pc, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift );
+void unpc_block( int32_t * pc, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* __DPLIB_H__ */

+ 390 - 0
components/spotify/cspot/bell/external/alac/codec/matrix_dec.c

@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		matrix_dec.c
+	
+	Contains:	ALAC mixing/matrixing decode routines.
+
+	Copyright:	(c) 2004-2011 Apple, Inc.
+*/
+
+#include "matrixlib.h"
+#include "ALACAudioTypes.h"
+
+// up to 24-bit "offset" macros for the individual bytes of a 20/24-bit word
+#if TARGET_RT_BIG_ENDIAN
+	#define LBYTE	2
+	#define MBYTE	1
+	#define HBYTE	0
+#else
+	#define LBYTE	0
+	#define MBYTE	1
+	#define HBYTE	2
+#endif
+
+/*
+    There is no plain middle-side option; instead there are various mixing
+    modes including middle-side, each lossless, as embodied in the mix()
+    and unmix() functions.  These functions exploit a generalized middle-side
+    transformation:
+    
+    u := [(rL + (m-r)R)/m];
+    v := L - R;
+    
+    where [ ] denotes integer floor.  The (lossless) inverse is
+    
+    L = u + v - [rV/m];
+    R = L - v;
+*/
+
+// 16-bit routines
+
+void unmix16( int32_t * u, int32_t * v, int16_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	int16_t *	op = out;
+	int32_t 		j;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		l, r;
+
+			l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+			r = l - v[j];
+
+			op[0] = (int16_t) l;
+			op[1] = (int16_t) r;
+			op += stride;
+		} 
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			op[0] = (int16_t) u[j];
+			op[1] = (int16_t) v[j];
+			op += stride;
+		}
+	}
+}
+
+// 20-bit routines
+// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers
+
+void unmix20( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	uint8_t *	op = out;
+	int32_t 		j;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		l, r;
+
+			l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+			r = l - v[j];
+
+			l <<= 4;
+			r <<= 4;
+
+			op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+			op += 3;
+
+			op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+			op += (stride - 1) * 3;
+		}
+	}
+	else 
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		val;
+
+			val = u[j] << 4;
+			op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+			op += 3;
+
+			val = v[j] << 4;
+			op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+			op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+			op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+
+			op += (stride - 1) * 3;
+		}
+	}
+}
+
+// 24-bit routines
+// - the 24 bits of data are right-justified in the input/output predictor buffers
+
+void unmix24( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{
+	uint8_t *	op = out;
+	int32_t			shift = bytesShifted * 8;
+	int32_t		l, r;
+	int32_t 		j, k;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+				r = l - v[j];
+
+				l = (l << shift) | (uint32_t) shiftUV[k + 0];
+				r = (r << shift) | (uint32_t) shiftUV[k + 1];
+
+				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+				op += 3;
+
+				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				l = u[j] + v[j] - ((mixres * v[j]) >> mixbits);
+				r = l - v[j];
+
+				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+				op += 3;
+
+				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+	}
+	else 
+	{
+		/* Conventional separated stereo. */
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = u[j];
+				r = v[j];
+
+				l = (l << shift) | (uint32_t) shiftUV[k + 0];
+				r = (r << shift) | (uint32_t) shiftUV[k + 1];
+
+				op[HBYTE] = (uint8_t)((l >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((l >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((l >>  0) & 0xffu);
+				op += 3;
+
+				op[HBYTE] = (uint8_t)((r >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((r >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((r >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				int32_t		val;
+
+				val = u[j];
+				op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+				op += 3;
+
+				val = v[j];
+				op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+				op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+				op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+
+				op += (stride - 1) * 3;
+			}
+		}
+	}
+}
+
+// 32-bit routines
+// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit
+// - otherwise, the calculations might overflow into the 33rd bit and be lost
+// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers
+
+void unmix32( int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{
+	int32_t *	op = out;
+	int32_t			shift = bytesShifted * 8;
+	int32_t		l, r;
+	int32_t 		j, k;
+
+	if ( mixres != 0 )
+	{
+		//Assert( bytesShifted != 0 );
+
+		/* matrixed stereo with shift */
+		for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+		{
+			int32_t		lt, rt;
+
+			lt = u[j];
+			rt = v[j];
+			
+			l = lt + rt - ((mixres * rt) >> mixbits);
+			r = l - rt;
+
+			op[0] = (l << shift) | (uint32_t) shiftUV[k + 0];
+			op[1] = (r << shift) | (uint32_t) shiftUV[k + 1];
+			op += stride;
+		} 
+	}
+	else
+	{
+		if ( bytesShifted == 0 )
+		{
+			/* interleaving w/o shift */
+			for ( j = 0; j < numSamples; j++ )
+			{
+				op[0] = u[j];
+				op[1] = v[j];
+				op += stride;
+			}
+		}
+		else
+		{
+			/* interleaving with shift */
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				op[0] = (u[j] << shift) | (uint32_t) shiftUV[k + 0];
+				op[1] = (v[j] << shift) | (uint32_t) shiftUV[k + 1];
+				op += stride;
+			}
+		}
+	}
+}
+
+// 20/24-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)
+
+void copyPredictorTo24( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples )
+{
+	uint8_t *	op = out;
+	int32_t			j;
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t		val = in[j];
+
+		op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+		op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+		op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+		op += (stride * 3);
+	}
+}
+
+void copyPredictorTo24Shift( int32_t * in, uint16_t * shift, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted )
+{
+	uint8_t *	op = out;
+	int32_t			shiftVal = bytesShifted * 8;
+	int32_t			j;
+
+	//Assert( bytesShifted != 0 );
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t		val = in[j];
+
+		val = (val << shiftVal) | (uint32_t) shift[j];
+
+		op[HBYTE] = (uint8_t)((val >> 16) & 0xffu);
+		op[MBYTE] = (uint8_t)((val >>  8) & 0xffu);
+		op[LBYTE] = (uint8_t)((val >>  0) & 0xffu);
+		op += (stride * 3);
+	}
+}
+
+void copyPredictorTo20( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples )
+{
+	uint8_t *	op = out;
+	int32_t			j;
+
+	// 32-bit predictor values are right-aligned but 20-bit output values should be left-aligned
+	// in the 24-bit output buffer
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t		val = in[j];
+
+		op[HBYTE] = (uint8_t)((val >> 12) & 0xffu);
+		op[MBYTE] = (uint8_t)((val >>  4) & 0xffu);
+		op[LBYTE] = (uint8_t)((val <<  4) & 0xffu);
+		op += (stride * 3);
+	}
+}
+
+void copyPredictorTo32( int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples )
+{
+	int32_t			i, j;
+
+	// this is only a subroutine to abstract the "iPod can only output 16-bit data" problem
+	for ( i = 0, j = 0; i < numSamples; i++, j += stride )
+		out[j] = in[i];
+}
+
+void copyPredictorTo32Shift( int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted )
+{
+	int32_t *		op = out;
+	uint32_t		shiftVal = bytesShifted * 8;
+	int32_t				j;
+
+	//Assert( bytesShifted != 0 );
+
+	// this is only a subroutine to abstract the "iPod can only output 16-bit data" problem
+	for ( j = 0; j < numSamples; j++ )
+	{
+		op[0] = (in[j] << shiftVal) | (uint32_t) shift[j];
+		op += stride;
+	}
+}

+ 342 - 0
components/spotify/cspot/bell/external/alac/codec/matrix_enc.c

@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		matrix_enc.c
+	
+	Contains:	ALAC mixing/matrixing encode routines.
+
+	Copyright:	(c) 2004-2011 Apple, Inc.
+*/
+
+#include "matrixlib.h"
+#include "ALACAudioTypes.h"
+
+// up to 24-bit "offset" macros for the individual bytes of a 20/24-bit word
+#if TARGET_RT_BIG_ENDIAN
+	#define LBYTE	2
+	#define MBYTE	1
+	#define HBYTE	0
+#else
+	#define LBYTE	0
+	#define MBYTE	1
+	#define HBYTE	2
+#endif
+
+/*
+    There is no plain middle-side option; instead there are various mixing
+    modes including middle-side, each lossless, as embodied in the mix()
+    and unmix() functions.  These functions exploit a generalized middle-side
+    transformation:
+    
+    u := [(rL + (m-r)R)/m];
+    v := L - R;
+    
+    where [ ] denotes integer floor.  The (lossless) inverse is
+    
+    L = u + v - [rV/m];
+    R = L - v;
+*/
+
+// 16-bit routines
+
+void mix16( int16_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	int16_t	*	ip = in;
+	int32_t			j;
+
+	if ( mixres != 0 )
+	{
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2;
+
+		/* matrixed stereo */
+		m2 = mod - mixres;
+		for ( j = 0; j < numSamples; j++ )
+		{
+			int32_t		l, r;
+
+			l = (int32_t) ip[0];
+			r = (int32_t) ip[1];
+			ip += stride;
+			u[j] = (mixres * l + m2 * r) >> mixbits;
+			v[j] = l - r;
+		}
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			u[j] = (int32_t) ip[0];
+			v[j] = (int32_t) ip[1];
+			ip += stride;
+		}
+	}
+}
+
+// 20-bit routines
+// - the 20 bits of data are left-justified in 3 bytes of storage but right-aligned for input/output predictor buffers
+
+void mix20( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres )
+{
+	int32_t		l, r;
+	uint8_t *	ip = in;
+	int32_t			j;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2 = mod - mixres;
+
+		for ( j = 0; j < numSamples; j++ )
+		{
+			l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			l = (l << 8) >> 12;
+			ip += 3;
+
+			r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			r = (r << 8) >> 12;
+			ip += (stride - 1) * 3;
+
+			u[j] = (mixres * l + m2 * r) >> mixbits;
+			v[j] = l - r;
+		} 
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		for ( j = 0; j < numSamples; j++ )
+		{
+			l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			u[j] = (l << 8) >> 12;
+			ip += 3;
+
+			r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+			v[j] = (r << 8) >> 12;
+			ip += (stride - 1) * 3;
+		}
+	}
+}
+
+// 24-bit routines
+// - the 24 bits of data are right-justified in the input/output predictor buffers
+
+void mix24( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+			int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{	
+	int32_t		l, r;
+	uint8_t *	ip = in;
+	int32_t			shift = bytesShifted * 8;
+	uint32_t	mask  = (1ul << shift) - 1;
+	int32_t			j, k;
+
+	if ( mixres != 0 )
+	{
+		/* matrixed stereo */
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2 = mod - mixres;
+
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				l = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				r = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+
+				shiftUV[k + 0] = (uint16_t)(l & mask);
+				shiftUV[k + 1] = (uint16_t)(r & mask);
+				
+				l >>= shift;
+				r >>= shift;
+
+				u[j] = (mixres * l + m2 * r) >> mixbits;
+				v[j] = l - r;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				l = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				r = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+
+				u[j] = (mixres * l + m2 * r) >> mixbits;
+				v[j] = l - r;
+			}
+		}
+	}
+	else
+	{
+		/* Conventional separated stereo. */
+		if ( bytesShifted != 0 )
+		{
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				l = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				r = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+
+				shiftUV[k + 0] = (uint16_t)(l & mask);
+				shiftUV[k + 1] = (uint16_t)(r & mask);
+				
+				l >>= shift;
+				r >>= shift;
+
+				u[j] = l;
+				v[j] = r;
+			}
+		}
+		else
+		{
+			for ( j = 0; j < numSamples; j++ )
+			{
+				l = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				u[j] = (l << 8) >> 8;
+				ip += 3;
+
+				r = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+				v[j] = (r << 8) >> 8;
+				ip += (stride - 1) * 3;
+			}
+		}
+	}
+}
+
+// 32-bit routines
+// - note that these really expect the internal data width to be < 32 but the arrays are 32-bit
+// - otherwise, the calculations might overflow into the 33rd bit and be lost
+// - therefore, these routines deal with the specified "unused lower" bytes in the "shift" buffers
+
+void mix32( int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+			int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted )
+{
+	int32_t	*	ip = in;
+	int32_t			shift = bytesShifted * 8;
+	uint32_t	mask  = (1ul << shift) - 1;
+	int32_t		l, r;
+	int32_t			j, k;
+
+	if ( mixres != 0 )
+	{
+		int32_t		mod = 1 << mixbits;
+		int32_t		m2;
+
+		//Assert( bytesShifted != 0 );
+
+		/* matrixed stereo with shift */
+		m2 = mod - mixres;
+		for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+		{
+			l = ip[0];
+			r = ip[1];
+			ip += stride;
+
+			shiftUV[k + 0] = (uint16_t)(l & mask);
+			shiftUV[k + 1] = (uint16_t)(r & mask);
+			
+			l >>= shift;
+			r >>= shift;
+
+			u[j] = (mixres * l + m2 * r) >> mixbits;
+			v[j] = l - r;
+		}
+	}
+	else
+	{
+		if ( bytesShifted == 0 )
+		{
+			/* de-interleaving w/o shift */
+			for ( j = 0; j < numSamples; j++ )
+			{
+				u[j] = ip[0];
+				v[j] = ip[1];
+				ip += stride;
+			}
+		}
+		else
+		{
+			/* de-interleaving with shift */
+			for ( j = 0, k = 0; j < numSamples; j++, k += 2 )
+			{
+				l = ip[0];
+				r = ip[1];
+				ip += stride;
+
+				shiftUV[k + 0] = (uint16_t)(l & mask);
+				shiftUV[k + 1] = (uint16_t)(r & mask);
+				
+				l >>= shift;
+				r >>= shift;
+
+				u[j] = l;
+				v[j] = r;
+			}
+		}
+	}
+}
+
+// 20/24-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)
+
+void copy20ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples )
+{
+	uint8_t *	ip = in;
+	int32_t			j;
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t			val;
+
+		// 20-bit values are left-aligned in the 24-bit input buffer but right-aligned in the 32-bit output buffer
+		val = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+		out[j] = (val << 8) >> 12;
+		ip += stride * 3;
+	}
+}
+
+void copy24ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples )
+{
+	uint8_t *	ip = in;
+	int32_t			j;
+
+	for ( j = 0; j < numSamples; j++ )
+	{
+		int32_t			val;
+
+		val = (int32_t)( ((uint32_t)ip[HBYTE] << 16) | ((uint32_t)ip[MBYTE] << 8) | (uint32_t)ip[LBYTE] );
+		out[j] = (val << 8) >> 8;
+		ip += stride * 3;
+	}
+}

+ 80 - 0
components/spotify/cspot/bell/external/alac/codec/matrixlib.h

@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2011 Apple Inc. All rights reserved.
+ *
+ * @APPLE_APACHE_LICENSE_HEADER_START@
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * 
+ * @APPLE_APACHE_LICENSE_HEADER_END@
+ */
+
+/*
+	File:		matrixlib.h
+	
+	Contains:	ALAC mixing/matrixing routines to/from 32-bit predictor buffers.
+
+	Copyright:	Copyright (C) 2004 to 2011 Apple, Inc.
+*/
+
+#ifndef __MATRIXLIB_H
+#define __MATRIXLIB_H
+
+#pragma once
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// 16-bit routines
+void	mix16( int16_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres );
+void	unmix16( int32_t * u, int32_t * v, int16_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres );
+
+// 20-bit routines
+void	mix20( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples, int32_t mixbits, int32_t mixres );
+void	unmix20( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t mixbits, int32_t mixres );
+
+// 24-bit routines
+// - 24-bit data sometimes compresses better by shifting off the bottom byte so these routines deal with
+//	 the specified "unused lower bytes" in the combined "shift" buffer
+void	mix24( uint8_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+void	unmix24( int32_t * u, int32_t * v, uint8_t * out, uint32_t stride, int32_t numSamples,
+				 int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+
+// 32-bit routines
+// - note that these really expect the internal data width to be < 32-bit but the arrays are 32-bit
+// - otherwise, the calculations might overflow into the 33rd bit and be lost
+// - therefore, these routines deal with the specified "unused lower" bytes in the combined "shift" buffer
+void	mix32( int32_t * in, uint32_t stride, int32_t * u, int32_t * v, int32_t numSamples,
+				int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+void	unmix32( int32_t * u, int32_t * v, int32_t * out, uint32_t stride, int32_t numSamples,
+				 int32_t mixbits, int32_t mixres, uint16_t * shiftUV, int32_t bytesShifted );
+
+// 20/24/32-bit <-> 32-bit helper routines (not really matrixing but convenient to put here)
+void	copy20ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples );
+void	copy24ToPredictor( uint8_t * in, uint32_t stride, int32_t * out, int32_t numSamples );
+
+void	copyPredictorTo24( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples );
+void	copyPredictorTo24Shift( int32_t * in, uint16_t * shift, uint8_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted );
+void	copyPredictorTo20( int32_t * in, uint8_t * out, uint32_t stride, int32_t numSamples );
+
+void	copyPredictorTo32( int32_t * in, int32_t * out, uint32_t stride, int32_t numSamples );
+void	copyPredictorTo32Shift( int32_t * in, uint16_t * shift, int32_t * out, uint32_t stride, int32_t numSamples, int32_t bytesShifted );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* __MATRIXLIB_H */

Some files were not shown because too many files changed in this diff