From a1737e7842b093f2f702bd1b810e9513a97459a9 Mon Sep 17 00:00:00 2001 From: jaenek Date: Wed, 29 Jul 2020 02:18:01 +0200 Subject: [PATCH 001/150] Follow redirects (#276) --- src/AudioFileSourceHTTPStream.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/AudioFileSourceHTTPStream.cpp b/src/AudioFileSourceHTTPStream.cpp index 4060ff25..3c6ada81 100644 --- a/src/AudioFileSourceHTTPStream.cpp +++ b/src/AudioFileSourceHTTPStream.cpp @@ -1,7 +1,7 @@ /* AudioFileSourceHTTPStream Streaming HTTP source - + Copyright (C) 2017 Earle F. Philhower, III This program is free software: you can redistribute it and/or modify @@ -38,6 +38,7 @@ bool AudioFileSourceHTTPStream::open(const char *url) { pos = 0; http.begin(client, url); + http.setFollowRedirects(true); http.setReuse(true); int code = http.GET(); if (code != HTTP_CODE_OK) { From 7bb251102ef718b4007536f41ad8f5ee4ed00b35 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 29 Jul 2020 07:48:27 -0700 Subject: [PATCH 002/150] Only follow HTTP redirects on ESP8266 ESP32 doesn't have the redirect following capability, don't try and turn it on. --- src/AudioFileSourceHTTPStream.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AudioFileSourceHTTPStream.cpp b/src/AudioFileSourceHTTPStream.cpp index 3c6ada81..ed659ee5 100644 --- a/src/AudioFileSourceHTTPStream.cpp +++ b/src/AudioFileSourceHTTPStream.cpp @@ -38,8 +38,10 @@ bool AudioFileSourceHTTPStream::open(const char *url) { pos = 0; http.begin(client, url); - http.setFollowRedirects(true); http.setReuse(true); +#ifndef ESP32 + http.setFollowRedirects(true); +#endif int code = http.GET(); if (code != HTTP_CODE_OK) { http.end(); From d37010e5d776d7a2cf560ffbc629246ba9596648 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 3 Aug 2020 12:55:57 -0700 Subject: [PATCH 003/150] Add Mini-Wecker project --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e88db0e7..75105c38 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ If you have a neat use for this library, [I'd love to hear about it](mailto:earl My personal use of the ESP8266Audio library is only to drive a 3D-printed, network-time-setting alarm clock for my kids which can play an MP3 instead of a bell to wake them up, called [Psychoclock](https://github.com/earlephilhower/psychoclock). +Harald Sattler has built a neat German [word clock with MP3 alarm](http://www.harald-sattler.de/html/mini-wecker.htm). Detailed discussion on the process and models are included. + Erich Heinemann has developed a Stomper (instrument for playing samples in real-time during a live stage performance) that you can find more info about [here](https://github.com/ErichHeinemann/hman-stomper). Dagnall53 has integrated this into a really neat MQTT based model train controller to add sounds to his set. More info is available [here](https://github.com/dagnall53/ESPMQTTRocnetSound), including STL files for 3D printed components! From c5f0930b036b45990bd2778f2da582c7d7a26812 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 7 Aug 2020 21:28:13 -0700 Subject: [PATCH 004/150] Add MIDI host test w/valgrind Valgrind detects an error in TSF.h, not yet fixed. This could be causing issues on the ESP32. --- tests/host/Makefile | 9 +++++++-- tests/host/midi.cpp | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) create mode 100644 tests/host/midi.cpp diff --git a/tests/host/Makefile b/tests/host/Makefile index 6a6eb821..345a8799 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -1,4 +1,3 @@ -all: mp3 aac wav libmad=../../src/libmad/decoder.c ../../src/libmad/frame.c ../../src/libmad/bit.c ../../src/libmad/stream.c ../../src/libmad/fixed.c \ ../../src/libmad/timer.c ../../src/libmad/layer3.c ../../src/libmad/synth.c ../../src/libmad/huffman.c ../../src/libmad/version.c @@ -33,7 +32,7 @@ CPPOPTS=-g -Wunused-parameter -Wall -std=c++11 -m32 -include Arduino.h .phony: all -all: mp3 aac wav +all: mp3 aac wav midi mp3: FORCE rm -f *.o @@ -55,6 +54,12 @@ wav: FORCE rm -f *.o echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./wav +midi: FORCE + rm -f *.o + g++ $(CPPOPTS) -o midi midi.cpp Serial.cpp ../../src/AudioFileSourceSTDIO.cpp ../../src/AudioOutputSTDIO.cpp ../../src/AudioGeneratorMIDI.cpp ../../src/AudioLogger.cpp -I ../../src/ -I. + rm -f *.o + echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./midi + clean: rm -f mp3 aac wav *.o diff --git a/tests/host/midi.cpp b/tests/host/midi.cpp new file mode 100644 index 00000000..f688f6c0 --- /dev/null +++ b/tests/host/midi.cpp @@ -0,0 +1,32 @@ +#include +#include "AudioFileSourceSTDIO.h" +#include "AudioOutputSTDIO.h" +#include "AudioGeneratorMIDI.h" + +#define SF2 "../../examples/PlayMIDIFromLittleFS/data/1mgm.sf2" +#define MIDI "../../examples/PlayMIDIFromLittleFS/data/furelise.mid" + + +int main(int argc, char **argv) +{ + (void) argc; + (void) argv; + AudioFileSourceSTDIO *midifile = new AudioFileSourceSTDIO(MIDI); + AudioFileSourceSTDIO *sf2file = new AudioFileSourceSTDIO(SF2); + AudioOutputSTDIO *out = new AudioOutputSTDIO(); + out->SetFilename("midi.wav"); + AudioGeneratorMIDI *midi = new AudioGeneratorMIDI(); + + midi->SetSoundfont(sf2file); + midi->SetSampleRate(22050); + + midi->begin(midifile, out); + while (midi->loop()) { /*noop*/ } + midi->stop(); + out->stop(); + + delete out; + delete midi; + delete midifile; + delete sf2file; +} From fe21f08e99682eda8ecfbed4b1de8482d66588ff Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 7 Aug 2020 21:32:32 -0700 Subject: [PATCH 005/150] Clear running state var in MIDI constructor --- src/AudioGeneratorMIDI.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioGeneratorMIDI.h b/src/AudioGeneratorMIDI.h index 0642c7c9..8a1ac3f9 100644 --- a/src/AudioGeneratorMIDI.h +++ b/src/AudioGeneratorMIDI.h @@ -29,7 +29,7 @@ class AudioGeneratorMIDI : public AudioGenerator { public: - AudioGeneratorMIDI() { freq=44100; }; + AudioGeneratorMIDI() { freq=44100; running = false; }; virtual ~AudioGeneratorMIDI() override {}; bool SetSoundfont(AudioFileSource *newsf2) { if (isRunning()) return false; From 9c654e55cb477edbbdd6415fc3a061121558af64 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 7 Aug 2020 21:40:55 -0700 Subject: [PATCH 006/150] Fix MIDI test app from double-fclose()ing FILE --- tests/host/midi.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/host/midi.cpp b/tests/host/midi.cpp index f688f6c0..c96d69d7 100644 --- a/tests/host/midi.cpp +++ b/tests/host/midi.cpp @@ -23,7 +23,6 @@ int main(int argc, char **argv) midi->begin(midifile, out); while (midi->loop()) { /*noop*/ } midi->stop(); - out->stop(); delete out; delete midi; From 33494596a47a2228dd42ebe21d09082b5f9a72f9 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 7 Aug 2020 21:49:39 -0700 Subject: [PATCH 007/150] Fix OOB read on fast sample generation in MIDI Valgrind identified cases where the chunk read position came out to be -1, which was causing a read of memory before the actual cache buffers. This could result in add'l noise on playback. --- src/libtinysoundfont/tsf.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index be47f663..c3368ffc 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -1268,6 +1268,7 @@ short tsf_read_short_cached(tsf *f, int pos) f->timestamp[repl] = f->epoch++; f->offset[repl] = readOff; misses++; +// fprintf(stderr, "buffer[%d][%d-%d = %d]\n", repl, pos, readOff, pos - readOff); return f->buffer[repl][pos - readOff]; } @@ -1420,9 +1421,9 @@ static void tsf_voice_render(tsf* f, struct tsf_voice* v, float* outputBuffer, i } -void DumpF32P32(char *name, long long x) { - printf("%s = %08x.%08x\n", name, (int32_t)((x>>32)&0xffffffff), (int32_t)(x&0xffffffff)); -} +//void DumpF32P32(char *name, long long x) { +// printf("%s = %08x.%08x\n", name, (int32_t)((x>>32)&0xffffffff), (int32_t)(x&0xffffffff)); +//} static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuffer, int numSamples) { struct tsf_region* region = v->region; @@ -1501,6 +1502,7 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff while (blockSamples-- && tmpSourceSamplePositionF32P32 < tmpSampleEndF32P32) { unsigned int pos = (unsigned int)(tmpSourceSamplePositionF32P32>>32); + if (pos == 0xffffffff) pos = 0; short val = tsf_read_short_cached(f, pos); int32_t val32 = (int)val * (int)gainMonoFP; From 0f40d832413b136395e47b21cac6856fa8968315 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 8 Aug 2020 15:36:06 -0700 Subject: [PATCH 008/150] Use GitHub CI to run tests (#287) --- .github/workflows/pr-or-master-push.yml | 65 ++++++++++++++++++++++++ .travis.yml | 28 ---------- README.md | 2 +- examples/PlayAACFromPROGMEM/homer.aac | Bin 0 -> 33704 bytes tests/common.sh | 16 ++++-- tests/host/Makefile | 2 +- tests/host/aac.cpp | 6 ++- tests/host/pgmspace.h | 0 tests/host/test_8u_16.wav | Bin 0 -> 25740 bytes tests/host/wav.cpp | 1 - 10 files changed, 82 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/pr-or-master-push.yml delete mode 100644 .travis.yml create mode 100644 examples/PlayAACFromPROGMEM/homer.aac create mode 100644 tests/host/pgmspace.h create mode 100644 tests/host/test_8u_16.wav diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml new file mode 100644 index 00000000..025c4619 --- /dev/null +++ b/.github/workflows/pr-or-master-push.yml @@ -0,0 +1,65 @@ +# Run whenever a PR is generated or updated. + +# Most jobs check out the code, ensure Python3 is installed, and for build +# tests the ESP8266 toolchain is cached when possible to speed up execution. + +name: ESP8266 Arduino CI + +on: + push: + branches: + - master + pull_request: + +jobs: + + build-esp8266: + name: Build ESP8266 + runs-on: ubuntu-latest + strategy: + matrix: + chunk: [0, 1, 2, 3, 4] + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Build Sketches + env: + TRAVIS_BUILD_DIR: ${{ github.workspace }} + TRAVIS_TAG: ${{ github.ref }} + BUILD_TYPE: build + BUILD_MOD: 5 + BUILD_REM: ${{ matrix.chunk }} + run: | + bash ./tests/common.sh + + +# Run host test suite under valgrind for runtime checking of code. + host-tests: + name: Host tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Run host tests + env: + TRAVIS_BUILD_DIR: ${{ github.workspace }} + TRAVIS_TAG: ${{ github.ref }} + run: | + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install valgrind lcov gcc-multilib g++-multilib libc6-dbg:i386 + cd ./tests/host/ + make + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./mp3 + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./aac + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./wav + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./midi + diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7f9d7c90..00000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -sudo: false -language: bash -os: linux -dist: trusty - -matrix: - include: - - env: - - BUILD_TYPE=build -# - env: -# - BUILD_TYPE=build_esp32 - -install: - -script: - - $TRAVIS_BUILD_DIR/tests/common.sh - -deploy: - -notifications: - email: - on_success: change - on_failure: change - webhooks: - urls: - on_success: change # options: [always|never|change] default: always - on_failure: always # options: [always|never|change] default: always - on_start: false # default: false diff --git a/README.md b/README.md index 75105c38..812d7342 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ESP8266Audio - supports ESP8266 & ESP32 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Build Status](https://travis-ci.org/earlephilhower/ESP8266Audio.svg?branch=master)](https://travis-ci.org/earlephilhower/ESP8266Audio) +# ESP8266Audio - supports ESP8266 & ESP32 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTTL files and playing them on an I2S DAC or even using a software-simulated delta-sigma DAC with dynamic 32x-128x oversampling. ESP8266 is fully supported and most mature, but ESP32 is also mostly there with built-in DAC as well as external ones. diff --git a/examples/PlayAACFromPROGMEM/homer.aac b/examples/PlayAACFromPROGMEM/homer.aac new file mode 100644 index 0000000000000000000000000000000000000000..0502be6c68b0a9cb0d5242d4f39c89f26d63ac98 GIT binary patch literal 33704 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 literal 0 HcmV?d00001 diff --git a/tests/common.sh b/tests/common.sh index c54e6757..4ca7e68c 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -41,12 +41,18 @@ function build_sketches() local srcpath=$2 local build_arg=$3 local build_dir=build.tmp + local build_mod=$BUILD_MOD + local build_rem=$BUILD_REM mkdir -p $build_dir local build_cmd="python3 $arduino/$BUILD_PY -p $PWD/$build_dir $build_arg " local sketches=$(find $srcpath -name *.ino) print_size_info >size.log export ARDUINO_IDE_PATH=$arduino for sketch in $sketches; do + testcnt=$(( ($testcnt + 1) % $build_mod )) + if [ $testcnt -ne $build_rem ]; then + continue # Not ours to do + fi rm -rf $build_dir/* local sketchdir=$(dirname $sketch) local sketchdirname=$(basename $sketchdir) @@ -82,11 +88,6 @@ function install_libraries() mkdir -p $HOME/Arduino/libraries cp -a $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/ESP8266Audio git clone https://github.com/earlephilhower/ESP8266SAM $HOME/Arduino/libraries/ESP8266SAM - git clone https://github.com/earlephilhower/ESP8266FastROMFS $HOME/Arduino/libraries/ESP8266FastROMFS - git clone https://github.com/Gianbacchio/ESP8266_Spiram $HOME/Arduino/libraries/ESP8266_Spiram - # Following libs are not to be tested, just used. - rm -rf $HOME/Arduino/libraries/ESP8266_Spiram/examples - rm -rf $HOME/Arduino/libraries/ESP8266FastROMFS/examples } function install_ide() @@ -159,6 +160,11 @@ function build_sketches_with_arduino() set -e +if [ "$BUILD_MOD" == "" ]; then + export BUILD_MOD=1 + export BUILD_REM=0 +fi + if [ "$BUILD_TYPE" = "build" ]; then export BUILD_PY="hardware/esp8266com/esp8266/tools/build.py -b generic -s 4M1M -v -k " install_arduino diff --git a/tests/host/Makefile b/tests/host/Makefile index 345a8799..24196635 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -61,6 +61,6 @@ midi: FORCE echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./midi clean: - rm -f mp3 aac wav *.o + rm -f mp3 aac wav midi *.o FORCE: diff --git a/tests/host/aac.cpp b/tests/host/aac.cpp index a9a99b93..fd7a3a03 100644 --- a/tests/host/aac.cpp +++ b/tests/host/aac.cpp @@ -3,13 +3,15 @@ #include "AudioOutputSTDIO.h" #include "AudioGeneratorAAC.h" +#define AAC "../../examples/PlayAACFromPROGMEM/homer.aac" + int main(int argc, char **argv) { (void) argc; (void) argv; - AudioFileSourceSTDIO *in = new AudioFileSourceSTDIO("jamonit.aac"); + AudioFileSourceSTDIO *in = new AudioFileSourceSTDIO(AAC); AudioOutputSTDIO *out = new AudioOutputSTDIO(); - out->SetFilename("jamonit.aac.wav"); + out->SetFilename("out.aac.wav"); void *space = malloc(28000+60000); AudioGeneratorAAC *aac = new AudioGeneratorAAC(space, 28000+60000); diff --git a/tests/host/pgmspace.h b/tests/host/pgmspace.h new file mode 100644 index 00000000..e69de29b diff --git a/tests/host/test_8u_16.wav b/tests/host/test_8u_16.wav new file mode 100644 index 0000000000000000000000000000000000000000..b582740959f07181b62aae59fe0364d5cde839f5 GIT binary patch literal 25740 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 Z)U;FSzoxF=zn!BI%^@*EKnBJ=|35I$7+3%R literal 0 HcmV?d00001 diff --git a/tests/host/wav.cpp b/tests/host/wav.cpp index f428fd2b..15ed3a7c 100644 --- a/tests/host/wav.cpp +++ b/tests/host/wav.cpp @@ -16,7 +16,6 @@ int main(int argc, char **argv) wav->begin(in, out); while (wav->loop()) { /*noop*/ } wav->stop(); - out->stop(); delete wav; delete out; From f8d5ccf7d070e69155ef8475025af61795c76aa3 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 8 Aug 2020 16:40:21 -0700 Subject: [PATCH 009/150] Add ESP32 build, break out ESP8266 install for CI (#288) Re-enable ESP32 builds in CI Fix examples which do not compile on ESP32 --- .github/workflows/pr-or-master-push.yml | 23 +++++++ examples/TalkingClockI2S/TalkingClockI2S.ino | 13 ++-- tests/common.sh | 67 ++++++++++---------- 3 files changed, 66 insertions(+), 37 deletions(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index 025c4619..ccc6ed78 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -37,6 +37,29 @@ jobs: bash ./tests/common.sh + build-esp32: + name: Build ESP-32 + runs-on: ubuntu-latest + strategy: + matrix: + chunk: [0, 1, 2, 3, 4] + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Build Sketches + env: + TRAVIS_BUILD_DIR: ${{ github.workspace }} + TRAVIS_TAG: ${{ github.ref }} + BUILD_TYPE: build_esp32 + BUILD_MOD: 5 + BUILD_REM: ${{ matrix.chunk }} + run: | + bash ./tests/common.sh + # Run host test suite under valgrind for runtime checking of code. host-tests: name: Host tests diff --git a/examples/TalkingClockI2S/TalkingClockI2S.ino b/examples/TalkingClockI2S/TalkingClockI2S.ino index 1cec38b8..6a2f7312 100644 --- a/examples/TalkingClockI2S/TalkingClockI2S.ino +++ b/examples/TalkingClockI2S/TalkingClockI2S.ino @@ -2,7 +2,12 @@ // https://github.com/going-digital/Talkie/blob/master/Talkie/examples/Vocab_US_Clock/Vocab_US_Clock.ino // Released under GPL v2 -#include +#ifdef ESP32 + #include +#else + #include +#endif + #include #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorTalkie.h" @@ -109,7 +114,7 @@ AudioGeneratorTalkie *talkie; AudioOutputI2S *out; -bool getLocalTime(struct tm * info, uint32_t ms) { +bool GetLocalTime(struct tm * info, uint32_t ms) { uint32_t count = ms / 10; time_t now; @@ -156,7 +161,7 @@ void setup() do { tmstruct.tm_year = 0; Serial.printf("."); - getLocalTime(&tmstruct, 5000); + GetLocalTime(&tmstruct, 5000); delay(100); } while (tmstruct.tm_year < 100); @@ -170,7 +175,7 @@ void loop() { struct tm tmstruct ; tmstruct.tm_year = 0; - getLocalTime(&tmstruct, 5000); + GetLocalTime(&tmstruct, 5000); Serial.printf("\nNow is : %d-%02d-%02d %02d:%02d:%02d\n", tmstruct.tm_year + 1900, tmstruct.tm_mon + 1, tmstruct.tm_mday, tmstruct.tm_hour, diff --git a/tests/common.sh b/tests/common.sh index 4ca7e68c..cabad512 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -#set -x # echo on +set -ex function print_size_info() { @@ -93,9 +93,16 @@ function install_libraries() function install_ide() { local ide_path=$1 - wget -O arduino.tar.xz https://www.arduino.cc/download.php?f=/arduino-nightly-linux64.tar.xz + wget -q -O arduino.tar.xz https://www.arduino.cc/download.php?f=/arduino-nightly-linux64.tar.xz tar xf arduino.tar.xz mv arduino-nightly $ide_path + export PATH="$ide_path:$PATH" +} + +function install_esp8266() +{ + local ide_path=$1 + mkdir -p $ide_path/hardware cd $ide_path/hardware mkdir esp8266com cd esp8266com @@ -109,28 +116,33 @@ function install_ide() git submodule init git submodule update python3 get.py - export PATH="$ide_path:$ide_path/hardware/esp8266com/esp8266/tools/xtensa-lx106-elf/bin:$PATH" + export PATH="$ide_path/hardware/esp8266com/esp8266/tools/xtensa-lx106-elf/bin:$PATH" popd -# cd .. -# mkdir espressif -# cd espressif -# git clone https://github.com/espressif/arduino-esp32 esp32 -# pushd esp32/tools -# git submodule init -# git submodule update -# python3 get.py -# export PATH="$ide_path:$ide_path/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin:$PATH" -# popd + } -function run_host_tests() +function install_esp32() { - pushd host - make - make clean-objects + local ide_path=$1 + sudo pip install pyserial + cd $ide_path/hardware + mkdir espressif + cd espressif + git clone https://github.com/espressif/arduino-esp32.git esp32 + pushd esp32 + # Set custom warnings for all builds (i.e. could add -Wextra at some point) + echo "compiler.c.extra_flags=-Wall -Wextra -Werror $debug_flags" > platform.local.txt + echo "compiler.cpp.extra_flags=-Wall -Wextra -Werror $debug_flags" >> platform.local.txt + echo -e "\n----platform.local.txt----" + cat platform.local.txt + git submodule init + git submodule update + cd tools + python3 get.py + export PATH="$ide_path/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/:$PATH" popd -} +} function install_arduino() { @@ -148,10 +160,8 @@ function build_sketches_with_arduino() { # Compile sketches echo -e "travis_fold:start:sketch_test" -# build_sketches $HOME/arduino_ide $TRAVIS_BUILD_DIR/libraries "-l $HOME/Arduino/libraries" build_sketches $HOME/arduino_ide $HOME/Arduino/libraries "-l $HOME/Arduino/libraries" echo -e "travis_fold:end:sketch_test" - # Generate size report echo -e "travis_fold:start:size_report" cat size.log @@ -168,26 +178,17 @@ fi if [ "$BUILD_TYPE" = "build" ]; then export BUILD_PY="hardware/esp8266com/esp8266/tools/build.py -b generic -s 4M1M -v -k " install_arduino + install_esp8266 "$HOME/arduino_ide" build_sketches_with_arduino elif [ "$BUILD_TYPE" = "build_esp32" ]; then - #export BUILD_PY="hardware/espressif/esp32/tools/build.py -b esp32 -v -k " - #install_arduino - #build_sketches_with_arduino - sudo apt-get update - sudo apt-get upgrade -y python - sudo pip install --upgrade pip - sudo pip install --upgrade 'urllib3[secure]' - export ide_path=$HOME/arduino_ide install_arduino + install_esp32 "$HOME/arduino_ide" + export ide_path=$HOME/arduino_ide export FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR" export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG" source $ide_path/hardware/espressif/esp32/.github/scripts/install-arduino-ide.sh source $ide_path/hardware/espressif/esp32/.github/scripts/install-arduino-core-esp32.sh - build_sketches "$FQBN" "$HOME/Arduino/libraries" 0 1 -elif [ "$BUILD_TYPE" = "host_tests" ]; then - # Run host side tests - cd $TRAVIS_BUILD_DIR/tests - run_host_tests + build_sketches "$FQBN" "$HOME/Arduino/libraries" "$BUILD_REM" "$BUILD_MOD" fi From 05839052fbbc2e81c5f7ab8b85404c3cd18822bb Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 9 Aug 2020 11:21:45 -0700 Subject: [PATCH 010/150] Add FatFS file source (#289) Thanks to Marc Madaule for the patch adding FatFS for the ESP32 as a file source. --- src/AudioFileSourceFATFS.h | 64 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/AudioFileSourceFATFS.h diff --git a/src/AudioFileSourceFATFS.h b/src/AudioFileSourceFATFS.h new file mode 100644 index 00000000..88e43f07 --- /dev/null +++ b/src/AudioFileSourceFATFS.h @@ -0,0 +1,64 @@ +/* + AudioFileSourceFS + Input Arduion "file" to be used by AudioGenerator + + Copyright (C) 2017 Earle F. Philhower, III + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _AUDIOFILESOURCEFATFS_H +#define _AUDIOFILESOURCEFATFS_H + +#ifdef ESP32 + +#include +#include +#include + +#include "AudioFileSource.h" +#include "AudioFileSourceFS.h" + +/* + AudioFileSource for FAT filesystem. + */ +class AudioFileSourceFATFS : public AudioFileSourceFS +{ + public: + AudioFileSourceFATFS() : AudioFileSourceFS(FFat) {}; + AudioFileSourceFATFS(const char *filename) : AudioFileSourceFS(FFat) { + // We call open() ourselves because calling AudioFileSourceFS(FFat, filename) + // would call the parent open() and we do not want that + open(filename); + }; + + virtual bool open(const char *filename) override { + // make sure that the FATFS filesystem has been mounted + if (!FFat.begin()) { + audioLogger->printf_P(PSTR("Unable to initialize FATFS filesystem\n")); + return false; + } else { + // now that the fielsystem has been mounted, we can call the regular parent open() function + return AudioFileSourceFS::open(filename); + } + }; + + // Others are inherited from base +}; + +#endif + + +#endif + From 87742f502ce6daaa36a498993e2d8d7155534f69 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 9 Aug 2020 11:32:02 -0700 Subject: [PATCH 011/150] Update pr-or-master-push.yml --- .github/workflows/pr-or-master-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index ccc6ed78..88d6fca7 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -3,7 +3,7 @@ # Most jobs check out the code, ensure Python3 is installed, and for build # tests the ESP8266 toolchain is cached when possible to speed up execution. -name: ESP8266 Arduino CI +name: ESP8266Audio on: push: From 0d1d849f914705154d69bd6a1f1c5beeb225372b Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 9 Aug 2020 19:01:16 -0700 Subject: [PATCH 012/150] Fix factor-of-2-off MIDI velocity parsing (#290) Velocity in the MIDI format goes from 1...127, so scale the volume of the note generator by /128 instead of /256. Increases volume of all notes by 2x linearly (3dB). Found by Marc Madaule --- src/AudioGeneratorMIDI.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index ba6d0325..e3be2b2d 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -359,7 +359,7 @@ void AudioGeneratorMIDI::PrepareMIDI(AudioFileSource *src) earliest_time = 0; } -// Parses the note on/offs ujntil we are ready to render some more samples. Then return the +// Parses the note on/offs until we are ready to render some more samples. Then return the // total number of samples to render before we need to be called again int AudioGeneratorMIDI::PlayMIDI() { @@ -472,7 +472,7 @@ int AudioGeneratorMIDI::PlayMIDI() if (tg->instrument != midi_chan_instrument[trk->chan]) { /* new instrument for this generator */ tg->instrument = midi_chan_instrument[trk->chan]; } - tsf_note_on (g_tsf, tg->instrument, tg->note, trk->velocity / 256.0); + tsf_note_on (g_tsf, tg->instrument, tg->note, trk->velocity / 127.0); // velocity = 0...127 } else { ++notes_skipped; } From 0266d9af1435b0a17872cc3710c7ed8308b3fe15 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 9 Aug 2020 19:08:56 -0700 Subject: [PATCH 013/150] Fix missed merge in MIDI notegen (#291) Patch 21c07c0bcd702e7adf3db349ac926914b98d17ce was applied to the TSF's original code, but not to the fixed-point generator used by the ESP8266. Apply it to the FP unit as well. Spotted by Marc Madaule --- src/libtinysoundfont/tsf.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index c3368ffc..e1a43221 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -1444,7 +1444,7 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff struct tsf_voice_lowpass tmpLowpass = v->lowpass; TSF_BOOL dynamicLowpass = (region->modLfoToFilterFc || region->modEnvToFilterFc); - float tmpSampleRate, tmpInitialFilterFc, tmpModLfoToFilterFc, tmpModEnvToFilterFc; + float tmpSampleRate = f->outSampleRate, tmpInitialFilterFc, tmpModLfoToFilterFc, tmpModEnvToFilterFc; TSF_BOOL dynamicPitchRatio = (region->modLfoToPitch || region->modEnvToPitch || region->vibLfoToPitch); //double pitchRatio; @@ -1454,8 +1454,8 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff TSF_BOOL dynamicGain = (region->modLfoToVolume != 0); float noteGain, tmpModLfoToVolume; - if (dynamicLowpass) tmpSampleRate = f->outSampleRate, tmpInitialFilterFc = (float)region->initialFilterFc, tmpModLfoToFilterFc = (float)region->modLfoToFilterFc, tmpModEnvToFilterFc = (float)region->modEnvToFilterFc; - else tmpSampleRate = 0, tmpInitialFilterFc = 0, tmpModLfoToFilterFc = 0, tmpModEnvToFilterFc = 0; + if (dynamicLowpass) tmpInitialFilterFc = (float)region->initialFilterFc, tmpModLfoToFilterFc = (float)region->modLfoToFilterFc, tmpModEnvToFilterFc = (float)region->modEnvToFilterFc; + else tmpInitialFilterFc = 0, tmpModLfoToFilterFc = 0, tmpModEnvToFilterFc = 0; if (dynamicPitchRatio) pitchRatioF32P32 = 0, tmpModLfoToPitch = (float)region->modLfoToPitch, tmpVibLfoToPitch = (float)region->vibLfoToPitch, tmpModEnvToPitch = (float)region->modEnvToPitch; else { From 1101b110f92f9c1c9d1852c6aca23e2270f70388 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 9 Aug 2020 19:12:21 -0700 Subject: [PATCH 014/150] Update to release 1.5 because of several bug fixes (#292) --- library.json | 2 +- library.properties | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library.json b/library.json index 91948fb8..5d095349 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.4", + "version": "1.5", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { "SPI": "1.0" diff --git a/library.properties b/library.properties index 05109ff6..926eb3fd 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,9 @@ name=ESP8266Audio -version=1.4 +version=1.5 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines. -paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, and WAV and play on an I2S DAC or a software-driven delta-sigma DAC and 1-transistor amplifier. +paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Talkie, and WAV and play on an I2S DAC or a software-driven delta-sigma DAC and 1-transistor amplifier. category=Signal Input/Output url=https://github.com/earlephilhower/ESP8266Audio architectures=esp8266,esp32 - From 7c379748b1f07df1b5fb13c984b3117a7656f9b0 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 10 Aug 2020 08:52:17 -0700 Subject: [PATCH 015/150] Use semantic version x.y.z (#293) --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 5d095349..3cdf7a46 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.5", + "version": "1.5.0", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { "SPI": "1.0" diff --git a/library.properties b/library.properties index 926eb3fd..0eb36bee 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.5 +version=1.5.0 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines. From fae26d40109d0160c3229c6dc32bb6851faae3e6 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 11 Aug 2020 20:56:13 -0700 Subject: [PATCH 016/150] Add Opus file format (and OGG demux) (#294) Add ported versions of the Opus codec, OpusFile parser, and OGG demuxer from Xiph.org. Only works on the ESP32 due to memory limitations (of opusfile, strangely enough, and not because of opus compression). Adds a basic example and a host test. Fixes #278 --- README.md | 2 + .../PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino | 41 + .../data/gs-16b-2c-44100hz.opus | Bin 0 -> 219956 bytes keywords.txt | 1 + src/AudioGeneratorFLAC.cpp | 2 +- src/AudioGeneratorOpus.cpp | 143 + src/AudioGeneratorOpus.h | 70 + src/libogg/AUTHORS | 7 + src/libogg/CHANGES | 104 + src/libogg/COPYING | 28 + src/libogg/README.esp8266.md | 3 + src/libogg/README.md | 133 + src/libogg/bitwise.c | 1087 ++++++ src/libogg/config.h | 104 + src/libogg/crctable.h | 279 ++ src/libogg/framing.c | 2111 +++++++++++ src/libogg/ogg.pc | 14 + src/libogg/ogg/config_types.h | 26 + src/libogg/ogg/ogg.h | 209 ++ src/libogg/ogg/os_types.h | 158 + src/libopus/AUTHORS | 6 + src/libopus/COPYING | 44 + src/libopus/ChangeLog | 0 src/libopus/INSTALL | 368 ++ src/libopus/NEWS | 0 src/libopus/README | 161 + src/libopus/analysis.h | 103 + src/libopus/celt/_kiss_fft_guts.h | 182 + src/libopus/celt/arch.h | 288 ++ src/libopus/celt/bands.c | 1672 +++++++++ src/libopus/celt/bands.h | 123 + src/libopus/celt/celt.c | 316 ++ src/libopus/celt/celt.h | 251 ++ src/libopus/celt/celt_decoder.c | 1372 +++++++ src/libopus/celt/celt_encoder.c | 2607 +++++++++++++ src/libopus/celt/celt_lpc.c | 296 ++ src/libopus/celt/celt_lpc.h | 66 + src/libopus/celt/cpu_support.h | 70 + src/libopus/celt/cwrs.c | 716 ++++ src/libopus/celt/cwrs.h | 48 + src/libopus/celt/ecintrin.h | 87 + src/libopus/celt/entcode.c | 153 + src/libopus/celt/entcode.h | 152 + src/libopus/celt/entdec.c | 245 ++ src/libopus/celt/entdec.h | 100 + src/libopus/celt/entenc.c | 294 ++ src/libopus/celt/entenc.h | 110 + src/libopus/celt/fixed_debug.h | 791 ++++ src/libopus/celt/fixed_generic.h | 178 + src/libopus/celt/float_cast.h | 146 + src/libopus/celt/kiss_fft.c | 604 +++ src/libopus/celt/kiss_fft.h | 200 + src/libopus/celt/laplace.c | 134 + src/libopus/celt/laplace.h | 48 + src/libopus/celt/mathops.c | 209 ++ src/libopus/celt/mathops.h | 290 ++ src/libopus/celt/mdct.c | 343 ++ src/libopus/celt/mdct.h | 112 + src/libopus/celt/mfrngcod.h | 48 + src/libopus/celt/modes.c | 442 +++ src/libopus/celt/modes.h | 75 + src/libopus/celt/os_support.h | 92 + src/libopus/celt/pitch.c | 537 +++ src/libopus/celt/pitch.h | 192 + src/libopus/celt/quant_bands.c | 563 +++ src/libopus/celt/quant_bands.h | 66 + src/libopus/celt/rate.c | 644 ++++ src/libopus/celt/rate.h | 101 + src/libopus/celt/stack_alloc.h | 184 + src/libopus/celt/static_modes_fixed.h | 892 +++++ src/libopus/celt/static_modes_float.h | 888 +++++ src/libopus/celt/vq.c | 442 +++ src/libopus/celt/vq.h | 79 + src/libopus/config.h | 208 + src/libopus/mapping_matrix.c | 378 ++ src/libopus/mapping_matrix.h | 133 + src/libopus/mlp.h | 60 + src/libopus/opus.c | 356 ++ src/libopus/opus.h | 981 +++++ src/libopus/opus.pc | 16 + src/libopus/opus_custom.h | 342 ++ src/libopus/opus_decoder.c | 1033 +++++ src/libopus/opus_defines.h | 799 ++++ src/libopus/opus_encoder.c | 2783 ++++++++++++++ src/libopus/opus_multistream.c | 92 + src/libopus/opus_multistream.h | 660 ++++ src/libopus/opus_multistream_decoder.c | 549 +++ src/libopus/opus_multistream_encoder.c | 1328 +++++++ src/libopus/opus_private.h | 201 + src/libopus/opus_projection.h | 568 +++ src/libopus/opus_projection_decoder.c | 258 ++ src/libopus/opus_projection_encoder.c | 468 +++ src/libopus/opus_types.h | 166 + src/libopus/repacketizer.c | 349 ++ src/libopus/silk/A2NLSF.c | 267 ++ src/libopus/silk/API.h | 135 + src/libopus/silk/CNG.c | 184 + src/libopus/silk/HP_variable_cutoff.c | 77 + src/libopus/silk/Inlines.h | 188 + src/libopus/silk/LPC_analysis_filter.c | 111 + src/libopus/silk/LPC_fit.c | 81 + src/libopus/silk/LPC_inv_pred_gain.c | 141 + src/libopus/silk/LP_variable_cutoff.c | 135 + src/libopus/silk/MacroCount.h | 710 ++++ src/libopus/silk/MacroDebug.h | 951 +++++ src/libopus/silk/NLSF2A.c | 141 + src/libopus/silk/NLSF_VQ.c | 76 + src/libopus/silk/NLSF_VQ_weights_laroia.c | 80 + src/libopus/silk/NLSF_decode.c | 93 + src/libopus/silk/NLSF_del_dec_quant.c | 215 ++ src/libopus/silk/NLSF_encode.c | 124 + src/libopus/silk/NLSF_stabilize.c | 142 + src/libopus/silk/NLSF_unpack.c | 55 + src/libopus/silk/NSQ.c | 437 +++ src/libopus/silk/NSQ.h | 101 + src/libopus/silk/NSQ_del_dec.c | 733 ++++ src/libopus/silk/PLC.c | 448 +++ src/libopus/silk/PLC.h | 62 + src/libopus/silk/SigProc_FIX.h | 641 ++++ src/libopus/silk/VAD.c | 361 ++ src/libopus/silk/VQ_WMat_EC.c | 131 + src/libopus/silk/ana_filt_bank_1.c | 74 + src/libopus/silk/biquad_alt.c | 121 + src/libopus/silk/bwexpander.c | 51 + src/libopus/silk/bwexpander_32.c | 50 + src/libopus/silk/check_control_input.c | 106 + src/libopus/silk/code_signs.c | 115 + src/libopus/silk/control.h | 150 + src/libopus/silk/control_SNR.c | 113 + src/libopus/silk/control_audio_bandwidth.c | 132 + src/libopus/silk/control_codec.c | 423 +++ src/libopus/silk/debug.c | 170 + src/libopus/silk/debug.h | 266 ++ src/libopus/silk/dec_API.c | 419 +++ src/libopus/silk/decode_core.c | 237 ++ src/libopus/silk/decode_frame.c | 130 + src/libopus/silk/decode_indices.c | 151 + src/libopus/silk/decode_parameters.c | 115 + src/libopus/silk/decode_pitch.c | 77 + src/libopus/silk/decode_pulses.c | 115 + src/libopus/silk/decoder_set_fs.c | 108 + src/libopus/silk/define.h | 234 ++ src/libopus/silk/enc_API.c | 576 +++ src/libopus/silk/encode_indices.c | 181 + src/libopus/silk/encode_pulses.c | 206 + src/libopus/silk/errors.h | 98 + .../silk/fixed/LTP_analysis_filter_FIX.c | 90 + .../silk/fixed/LTP_analysis_filter_FIX.lo | 12 + .../silk/fixed/LTP_analysis_filter_FIX.o | Bin 0 -> 13896 bytes src/libopus/silk/fixed/LTP_scale_ctrl_FIX.c | 53 + src/libopus/silk/fixed/LTP_scale_ctrl_FIX.lo | 12 + src/libopus/silk/fixed/LTP_scale_ctrl_FIX.o | Bin 0 -> 20696 bytes .../silk/fixed/apply_sine_window_FIX.c | 101 + .../silk/fixed/apply_sine_window_FIX.lo | 12 + .../silk/fixed/apply_sine_window_FIX.o | Bin 0 -> 10688 bytes src/libopus/silk/fixed/autocorr_FIX.c | 48 + src/libopus/silk/fixed/autocorr_FIX.lo | 12 + src/libopus/silk/fixed/autocorr_FIX.o | Bin 0 -> 8024 bytes src/libopus/silk/fixed/burg_modified_FIX.c | 280 ++ src/libopus/silk/fixed/burg_modified_FIX.lo | 12 + src/libopus/silk/fixed/burg_modified_FIX.o | Bin 0 -> 30592 bytes src/libopus/silk/fixed/corrMatrix_FIX.c | 150 + src/libopus/silk/fixed/corrMatrix_FIX.lo | 12 + src/libopus/silk/fixed/corrMatrix_FIX.o | Bin 0 -> 17184 bytes src/libopus/silk/fixed/encode_frame_FIX.c | 448 +++ src/libopus/silk/fixed/encode_frame_FIX.lo | 12 + src/libopus/silk/fixed/encode_frame_FIX.o | Bin 0 -> 51152 bytes src/libopus/silk/fixed/find_LPC_FIX.c | 151 + src/libopus/silk/fixed/find_LPC_FIX.lo | 12 + src/libopus/silk/fixed/find_LPC_FIX.o | Bin 0 -> 25216 bytes src/libopus/silk/fixed/find_LTP_FIX.c | 99 + src/libopus/silk/fixed/find_LTP_FIX.lo | 12 + src/libopus/silk/fixed/find_LTP_FIX.o | Bin 0 -> 15008 bytes src/libopus/silk/fixed/find_pitch_lags_FIX.c | 143 + src/libopus/silk/fixed/find_pitch_lags_FIX.lo | 12 + src/libopus/silk/fixed/find_pitch_lags_FIX.o | Bin 0 -> 30744 bytes src/libopus/silk/fixed/find_pred_coefs_FIX.c | 145 + src/libopus/silk/fixed/find_pred_coefs_FIX.lo | 12 + src/libopus/silk/fixed/find_pred_coefs_FIX.o | Bin 0 -> 33464 bytes src/libopus/silk/fixed/k2a_FIX.c | 54 + src/libopus/silk/fixed/k2a_FIX.lo | 12 + src/libopus/silk/fixed/k2a_FIX.o | Bin 0 -> 7632 bytes src/libopus/silk/fixed/k2a_Q16_FIX.c | 54 + src/libopus/silk/fixed/k2a_Q16_FIX.lo | 12 + src/libopus/silk/fixed/k2a_Q16_FIX.o | Bin 0 -> 7592 bytes src/libopus/silk/fixed/main_FIX.h | 244 ++ .../silk/fixed/noise_shape_analysis_FIX.c | 407 ++ .../silk/fixed/noise_shape_analysis_FIX.lo | 12 + .../silk/fixed/noise_shape_analysis_FIX.o | Bin 0 -> 57392 bytes .../silk/fixed/pitch_analysis_core_FIX.c | 721 ++++ .../silk/fixed/pitch_analysis_core_FIX.lo | 12 + .../silk/fixed/pitch_analysis_core_FIX.o | Bin 0 -> 59144 bytes src/libopus/silk/fixed/process_gains_FIX.c | 117 + src/libopus/silk/fixed/process_gains_FIX.lo | 12 + src/libopus/silk/fixed/process_gains_FIX.o | Bin 0 -> 28664 bytes .../silk/fixed/regularize_correlations_FIX.c | 47 + .../silk/fixed/regularize_correlations_FIX.lo | 12 + .../silk/fixed/regularize_correlations_FIX.o | Bin 0 -> 11384 bytes .../silk/fixed/residual_energy16_FIX.c | 103 + .../silk/fixed/residual_energy16_FIX.lo | 12 + .../silk/fixed/residual_energy16_FIX.o | Bin 0 -> 18976 bytes src/libopus/silk/fixed/residual_energy_FIX.c | 98 + src/libopus/silk/fixed/residual_energy_FIX.lo | 12 + src/libopus/silk/fixed/residual_energy_FIX.o | Bin 0 -> 16904 bytes src/libopus/silk/fixed/schur64_FIX.c | 93 + src/libopus/silk/fixed/schur64_FIX.lo | 12 + src/libopus/silk/fixed/schur64_FIX.o | Bin 0 -> 13272 bytes src/libopus/silk/fixed/schur_FIX.c | 107 + src/libopus/silk/fixed/schur_FIX.lo | 12 + src/libopus/silk/fixed/schur_FIX.o | Bin 0 -> 10528 bytes src/libopus/silk/fixed/structs_FIX.h | 116 + src/libopus/silk/fixed/vector_ops_FIX.c | 102 + src/libopus/silk/fixed/vector_ops_FIX.lo | 12 + src/libopus/silk/fixed/vector_ops_FIX.o | Bin 0 -> 10680 bytes .../silk/fixed/warped_autocorrelation_FIX.c | 92 + .../silk/fixed/warped_autocorrelation_FIX.lo | 12 + .../silk/fixed/warped_autocorrelation_FIX.o | Bin 0 -> 15936 bytes src/libopus/silk/gain_quant.c | 142 + src/libopus/silk/init_decoder.c | 57 + src/libopus/silk/init_encoder.c | 64 + src/libopus/silk/inner_prod_aligned.c | 47 + src/libopus/silk/interpolate.c | 51 + src/libopus/silk/lin2log.c | 46 + src/libopus/silk/log2lin.c | 58 + src/libopus/silk/macros.h | 151 + src/libopus/silk/main.h | 476 +++ src/libopus/silk/pitch_est_defines.h | 88 + src/libopus/silk/pitch_est_tables.c | 99 + src/libopus/silk/process_NLSFs.c | 107 + src/libopus/silk/quant_LTP_gains.c | 132 + src/libopus/silk/resampler.c | 215 ++ src/libopus/silk/resampler_down2.c | 74 + src/libopus/silk/resampler_down2_3.c | 103 + src/libopus/silk/resampler_private.h | 88 + src/libopus/silk/resampler_private_AR2.c | 55 + src/libopus/silk/resampler_private_IIR_FIR.c | 107 + src/libopus/silk/resampler_private_down_FIR.c | 194 + src/libopus/silk/resampler_private_up2_HQ.c | 113 + src/libopus/silk/resampler_rom.c | 96 + src/libopus/silk/resampler_rom.h | 68 + src/libopus/silk/resampler_structs.h | 60 + src/libopus/silk/shell_coder.c | 151 + src/libopus/silk/sigm_Q15.c | 77 + src/libopus/silk/sort.c | 154 + src/libopus/silk/stereo_LR_to_MS.c | 229 ++ src/libopus/silk/stereo_MS_to_LR.c | 85 + src/libopus/silk/stereo_decode_pred.c | 73 + src/libopus/silk/stereo_encode_pred.c | 62 + src/libopus/silk/stereo_find_predictor.c | 79 + src/libopus/silk/stereo_quant_pred.c | 73 + src/libopus/silk/structs.h | 329 ++ src/libopus/silk/sum_sqr_shift.c | 83 + src/libopus/silk/table_LSF_cos.c | 70 + src/libopus/silk/tables.h | 114 + src/libopus/silk/tables_LTP.c | 294 ++ src/libopus/silk/tables_NLSF_CB_NB_MB.c | 195 + src/libopus/silk/tables_NLSF_CB_WB.c | 234 ++ src/libopus/silk/tables_gain.c | 63 + src/libopus/silk/tables_other.c | 124 + src/libopus/silk/tables_pitch_lag.c | 69 + src/libopus/silk/tables_pulses_per_block.c | 264 ++ src/libopus/silk/tuning_parameters.h | 155 + src/libopus/silk/typedef.h | 78 + src/libopus/tansig_table.h | 45 + src/opusfile/AUTHORS | 5 + src/opusfile/COPYING | 28 + src/opusfile/README.esp8266.md | 3 + src/opusfile/README.md | 18 + src/opusfile/config.h | 128 + src/opusfile/info.c | 775 ++++ src/opusfile/internal.c | 42 + src/opusfile/internal.h | 259 ++ src/opusfile/opusfile.c | 3343 +++++++++++++++++ src/opusfile/opusfile.h | 2164 +++++++++++ src/opusfile/opusfile.pc | 15 + src/opusfile/stream.c | 415 ++ tests/host/Makefile | 59 +- tests/host/opus.cpp | 25 + 278 files changed, 63024 insertions(+), 3 deletions(-) create mode 100644 examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino create mode 100644 examples/PlayOpusFromSPIFFS/data/gs-16b-2c-44100hz.opus create mode 100644 src/AudioGeneratorOpus.cpp create mode 100644 src/AudioGeneratorOpus.h create mode 100644 src/libogg/AUTHORS create mode 100644 src/libogg/CHANGES create mode 100644 src/libogg/COPYING create mode 100644 src/libogg/README.esp8266.md create mode 100644 src/libogg/README.md create mode 100644 src/libogg/bitwise.c create mode 100644 src/libogg/config.h create mode 100644 src/libogg/crctable.h create mode 100644 src/libogg/framing.c create mode 100644 src/libogg/ogg.pc create mode 100644 src/libogg/ogg/config_types.h create mode 100644 src/libogg/ogg/ogg.h create mode 100644 src/libogg/ogg/os_types.h create mode 100644 src/libopus/AUTHORS create mode 100644 src/libopus/COPYING create mode 100644 src/libopus/ChangeLog create mode 100644 src/libopus/INSTALL create mode 100644 src/libopus/NEWS create mode 100644 src/libopus/README create mode 100644 src/libopus/analysis.h create mode 100644 src/libopus/celt/_kiss_fft_guts.h create mode 100644 src/libopus/celt/arch.h create mode 100644 src/libopus/celt/bands.c create mode 100644 src/libopus/celt/bands.h create mode 100644 src/libopus/celt/celt.c create mode 100644 src/libopus/celt/celt.h create mode 100644 src/libopus/celt/celt_decoder.c create mode 100644 src/libopus/celt/celt_encoder.c create mode 100644 src/libopus/celt/celt_lpc.c create mode 100644 src/libopus/celt/celt_lpc.h create mode 100644 src/libopus/celt/cpu_support.h create mode 100644 src/libopus/celt/cwrs.c create mode 100644 src/libopus/celt/cwrs.h create mode 100644 src/libopus/celt/ecintrin.h create mode 100644 src/libopus/celt/entcode.c create mode 100644 src/libopus/celt/entcode.h create mode 100644 src/libopus/celt/entdec.c create mode 100644 src/libopus/celt/entdec.h create mode 100644 src/libopus/celt/entenc.c create mode 100644 src/libopus/celt/entenc.h create mode 100644 src/libopus/celt/fixed_debug.h create mode 100644 src/libopus/celt/fixed_generic.h create mode 100644 src/libopus/celt/float_cast.h create mode 100644 src/libopus/celt/kiss_fft.c create mode 100644 src/libopus/celt/kiss_fft.h create mode 100644 src/libopus/celt/laplace.c create mode 100644 src/libopus/celt/laplace.h create mode 100644 src/libopus/celt/mathops.c create mode 100644 src/libopus/celt/mathops.h create mode 100644 src/libopus/celt/mdct.c create mode 100644 src/libopus/celt/mdct.h create mode 100644 src/libopus/celt/mfrngcod.h create mode 100644 src/libopus/celt/modes.c create mode 100644 src/libopus/celt/modes.h create mode 100644 src/libopus/celt/os_support.h create mode 100644 src/libopus/celt/pitch.c create mode 100644 src/libopus/celt/pitch.h create mode 100644 src/libopus/celt/quant_bands.c create mode 100644 src/libopus/celt/quant_bands.h create mode 100644 src/libopus/celt/rate.c create mode 100644 src/libopus/celt/rate.h create mode 100644 src/libopus/celt/stack_alloc.h create mode 100644 src/libopus/celt/static_modes_fixed.h create mode 100644 src/libopus/celt/static_modes_float.h create mode 100644 src/libopus/celt/vq.c create mode 100644 src/libopus/celt/vq.h create mode 100644 src/libopus/config.h create mode 100644 src/libopus/mapping_matrix.c create mode 100644 src/libopus/mapping_matrix.h create mode 100644 src/libopus/mlp.h create mode 100644 src/libopus/opus.c create mode 100644 src/libopus/opus.h create mode 100644 src/libopus/opus.pc create mode 100644 src/libopus/opus_custom.h create mode 100644 src/libopus/opus_decoder.c create mode 100644 src/libopus/opus_defines.h create mode 100644 src/libopus/opus_encoder.c create mode 100644 src/libopus/opus_multistream.c create mode 100644 src/libopus/opus_multistream.h create mode 100644 src/libopus/opus_multistream_decoder.c create mode 100644 src/libopus/opus_multistream_encoder.c create mode 100644 src/libopus/opus_private.h create mode 100644 src/libopus/opus_projection.h create mode 100644 src/libopus/opus_projection_decoder.c create mode 100644 src/libopus/opus_projection_encoder.c create mode 100644 src/libopus/opus_types.h create mode 100644 src/libopus/repacketizer.c create mode 100644 src/libopus/silk/A2NLSF.c create mode 100644 src/libopus/silk/API.h create mode 100644 src/libopus/silk/CNG.c create mode 100644 src/libopus/silk/HP_variable_cutoff.c create mode 100644 src/libopus/silk/Inlines.h create mode 100644 src/libopus/silk/LPC_analysis_filter.c create mode 100644 src/libopus/silk/LPC_fit.c create mode 100644 src/libopus/silk/LPC_inv_pred_gain.c create mode 100644 src/libopus/silk/LP_variable_cutoff.c create mode 100644 src/libopus/silk/MacroCount.h create mode 100644 src/libopus/silk/MacroDebug.h create mode 100644 src/libopus/silk/NLSF2A.c create mode 100644 src/libopus/silk/NLSF_VQ.c create mode 100644 src/libopus/silk/NLSF_VQ_weights_laroia.c create mode 100644 src/libopus/silk/NLSF_decode.c create mode 100644 src/libopus/silk/NLSF_del_dec_quant.c create mode 100644 src/libopus/silk/NLSF_encode.c create mode 100644 src/libopus/silk/NLSF_stabilize.c create mode 100644 src/libopus/silk/NLSF_unpack.c create mode 100644 src/libopus/silk/NSQ.c create mode 100644 src/libopus/silk/NSQ.h create mode 100644 src/libopus/silk/NSQ_del_dec.c create mode 100644 src/libopus/silk/PLC.c create mode 100644 src/libopus/silk/PLC.h create mode 100644 src/libopus/silk/SigProc_FIX.h create mode 100644 src/libopus/silk/VAD.c create mode 100644 src/libopus/silk/VQ_WMat_EC.c create mode 100644 src/libopus/silk/ana_filt_bank_1.c create mode 100644 src/libopus/silk/biquad_alt.c create mode 100644 src/libopus/silk/bwexpander.c create mode 100644 src/libopus/silk/bwexpander_32.c create mode 100644 src/libopus/silk/check_control_input.c create mode 100644 src/libopus/silk/code_signs.c create mode 100644 src/libopus/silk/control.h create mode 100644 src/libopus/silk/control_SNR.c create mode 100644 src/libopus/silk/control_audio_bandwidth.c create mode 100644 src/libopus/silk/control_codec.c create mode 100644 src/libopus/silk/debug.c create mode 100644 src/libopus/silk/debug.h create mode 100644 src/libopus/silk/dec_API.c create mode 100644 src/libopus/silk/decode_core.c create mode 100644 src/libopus/silk/decode_frame.c create mode 100644 src/libopus/silk/decode_indices.c create mode 100644 src/libopus/silk/decode_parameters.c create mode 100644 src/libopus/silk/decode_pitch.c create mode 100644 src/libopus/silk/decode_pulses.c create mode 100644 src/libopus/silk/decoder_set_fs.c create mode 100644 src/libopus/silk/define.h create mode 100644 src/libopus/silk/enc_API.c create mode 100644 src/libopus/silk/encode_indices.c create mode 100644 src/libopus/silk/encode_pulses.c create mode 100644 src/libopus/silk/errors.h create mode 100644 src/libopus/silk/fixed/LTP_analysis_filter_FIX.c create mode 100644 src/libopus/silk/fixed/LTP_analysis_filter_FIX.lo create mode 100644 src/libopus/silk/fixed/LTP_analysis_filter_FIX.o create mode 100644 src/libopus/silk/fixed/LTP_scale_ctrl_FIX.c create mode 100644 src/libopus/silk/fixed/LTP_scale_ctrl_FIX.lo create mode 100644 src/libopus/silk/fixed/LTP_scale_ctrl_FIX.o create mode 100644 src/libopus/silk/fixed/apply_sine_window_FIX.c create mode 100644 src/libopus/silk/fixed/apply_sine_window_FIX.lo create mode 100644 src/libopus/silk/fixed/apply_sine_window_FIX.o create mode 100644 src/libopus/silk/fixed/autocorr_FIX.c create mode 100644 src/libopus/silk/fixed/autocorr_FIX.lo create mode 100644 src/libopus/silk/fixed/autocorr_FIX.o create mode 100644 src/libopus/silk/fixed/burg_modified_FIX.c create mode 100644 src/libopus/silk/fixed/burg_modified_FIX.lo create mode 100644 src/libopus/silk/fixed/burg_modified_FIX.o create mode 100644 src/libopus/silk/fixed/corrMatrix_FIX.c create mode 100644 src/libopus/silk/fixed/corrMatrix_FIX.lo create mode 100644 src/libopus/silk/fixed/corrMatrix_FIX.o create mode 100644 src/libopus/silk/fixed/encode_frame_FIX.c create mode 100644 src/libopus/silk/fixed/encode_frame_FIX.lo create mode 100644 src/libopus/silk/fixed/encode_frame_FIX.o create mode 100644 src/libopus/silk/fixed/find_LPC_FIX.c create mode 100644 src/libopus/silk/fixed/find_LPC_FIX.lo create mode 100644 src/libopus/silk/fixed/find_LPC_FIX.o create mode 100644 src/libopus/silk/fixed/find_LTP_FIX.c create mode 100644 src/libopus/silk/fixed/find_LTP_FIX.lo create mode 100644 src/libopus/silk/fixed/find_LTP_FIX.o create mode 100644 src/libopus/silk/fixed/find_pitch_lags_FIX.c create mode 100644 src/libopus/silk/fixed/find_pitch_lags_FIX.lo create mode 100644 src/libopus/silk/fixed/find_pitch_lags_FIX.o create mode 100644 src/libopus/silk/fixed/find_pred_coefs_FIX.c create mode 100644 src/libopus/silk/fixed/find_pred_coefs_FIX.lo create mode 100644 src/libopus/silk/fixed/find_pred_coefs_FIX.o create mode 100644 src/libopus/silk/fixed/k2a_FIX.c create mode 100644 src/libopus/silk/fixed/k2a_FIX.lo create mode 100644 src/libopus/silk/fixed/k2a_FIX.o create mode 100644 src/libopus/silk/fixed/k2a_Q16_FIX.c create mode 100644 src/libopus/silk/fixed/k2a_Q16_FIX.lo create mode 100644 src/libopus/silk/fixed/k2a_Q16_FIX.o create mode 100644 src/libopus/silk/fixed/main_FIX.h create mode 100644 src/libopus/silk/fixed/noise_shape_analysis_FIX.c create mode 100644 src/libopus/silk/fixed/noise_shape_analysis_FIX.lo create mode 100644 src/libopus/silk/fixed/noise_shape_analysis_FIX.o create mode 100644 src/libopus/silk/fixed/pitch_analysis_core_FIX.c create mode 100644 src/libopus/silk/fixed/pitch_analysis_core_FIX.lo create mode 100644 src/libopus/silk/fixed/pitch_analysis_core_FIX.o create mode 100644 src/libopus/silk/fixed/process_gains_FIX.c create mode 100644 src/libopus/silk/fixed/process_gains_FIX.lo create mode 100644 src/libopus/silk/fixed/process_gains_FIX.o create mode 100644 src/libopus/silk/fixed/regularize_correlations_FIX.c create mode 100644 src/libopus/silk/fixed/regularize_correlations_FIX.lo create mode 100644 src/libopus/silk/fixed/regularize_correlations_FIX.o create mode 100644 src/libopus/silk/fixed/residual_energy16_FIX.c create mode 100644 src/libopus/silk/fixed/residual_energy16_FIX.lo create mode 100644 src/libopus/silk/fixed/residual_energy16_FIX.o create mode 100644 src/libopus/silk/fixed/residual_energy_FIX.c create mode 100644 src/libopus/silk/fixed/residual_energy_FIX.lo create mode 100644 src/libopus/silk/fixed/residual_energy_FIX.o create mode 100644 src/libopus/silk/fixed/schur64_FIX.c create mode 100644 src/libopus/silk/fixed/schur64_FIX.lo create mode 100644 src/libopus/silk/fixed/schur64_FIX.o create mode 100644 src/libopus/silk/fixed/schur_FIX.c create mode 100644 src/libopus/silk/fixed/schur_FIX.lo create mode 100644 src/libopus/silk/fixed/schur_FIX.o create mode 100644 src/libopus/silk/fixed/structs_FIX.h create mode 100644 src/libopus/silk/fixed/vector_ops_FIX.c create mode 100644 src/libopus/silk/fixed/vector_ops_FIX.lo create mode 100644 src/libopus/silk/fixed/vector_ops_FIX.o create mode 100644 src/libopus/silk/fixed/warped_autocorrelation_FIX.c create mode 100644 src/libopus/silk/fixed/warped_autocorrelation_FIX.lo create mode 100644 src/libopus/silk/fixed/warped_autocorrelation_FIX.o create mode 100644 src/libopus/silk/gain_quant.c create mode 100644 src/libopus/silk/init_decoder.c create mode 100644 src/libopus/silk/init_encoder.c create mode 100644 src/libopus/silk/inner_prod_aligned.c create mode 100644 src/libopus/silk/interpolate.c create mode 100644 src/libopus/silk/lin2log.c create mode 100644 src/libopus/silk/log2lin.c create mode 100644 src/libopus/silk/macros.h create mode 100644 src/libopus/silk/main.h create mode 100644 src/libopus/silk/pitch_est_defines.h create mode 100644 src/libopus/silk/pitch_est_tables.c create mode 100644 src/libopus/silk/process_NLSFs.c create mode 100644 src/libopus/silk/quant_LTP_gains.c create mode 100644 src/libopus/silk/resampler.c create mode 100644 src/libopus/silk/resampler_down2.c create mode 100644 src/libopus/silk/resampler_down2_3.c create mode 100644 src/libopus/silk/resampler_private.h create mode 100644 src/libopus/silk/resampler_private_AR2.c create mode 100644 src/libopus/silk/resampler_private_IIR_FIR.c create mode 100644 src/libopus/silk/resampler_private_down_FIR.c create mode 100644 src/libopus/silk/resampler_private_up2_HQ.c create mode 100644 src/libopus/silk/resampler_rom.c create mode 100644 src/libopus/silk/resampler_rom.h create mode 100644 src/libopus/silk/resampler_structs.h create mode 100644 src/libopus/silk/shell_coder.c create mode 100644 src/libopus/silk/sigm_Q15.c create mode 100644 src/libopus/silk/sort.c create mode 100644 src/libopus/silk/stereo_LR_to_MS.c create mode 100644 src/libopus/silk/stereo_MS_to_LR.c create mode 100644 src/libopus/silk/stereo_decode_pred.c create mode 100644 src/libopus/silk/stereo_encode_pred.c create mode 100644 src/libopus/silk/stereo_find_predictor.c create mode 100644 src/libopus/silk/stereo_quant_pred.c create mode 100644 src/libopus/silk/structs.h create mode 100644 src/libopus/silk/sum_sqr_shift.c create mode 100644 src/libopus/silk/table_LSF_cos.c create mode 100644 src/libopus/silk/tables.h create mode 100644 src/libopus/silk/tables_LTP.c create mode 100644 src/libopus/silk/tables_NLSF_CB_NB_MB.c create mode 100644 src/libopus/silk/tables_NLSF_CB_WB.c create mode 100644 src/libopus/silk/tables_gain.c create mode 100644 src/libopus/silk/tables_other.c create mode 100644 src/libopus/silk/tables_pitch_lag.c create mode 100644 src/libopus/silk/tables_pulses_per_block.c create mode 100644 src/libopus/silk/tuning_parameters.h create mode 100644 src/libopus/silk/typedef.h create mode 100644 src/libopus/tansig_table.h create mode 100644 src/opusfile/AUTHORS create mode 100644 src/opusfile/COPYING create mode 100644 src/opusfile/README.esp8266.md create mode 100644 src/opusfile/README.md create mode 100644 src/opusfile/config.h create mode 100644 src/opusfile/info.c create mode 100644 src/opusfile/internal.c create mode 100644 src/opusfile/internal.h create mode 100644 src/opusfile/opusfile.c create mode 100644 src/opusfile/opusfile.h create mode 100644 src/opusfile/opusfile.pc create mode 100644 src/opusfile/stream.c create mode 100644 tests/host/opus.cpp diff --git a/README.md b/README.md index 812d7342..c8c92ff6 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ On the ESP32, AAC-SBR is supported (many webradio stations use this to reduce ba MIDI decoding comes from a highly ported [MIDITONES](https://github.com/LenShustek/miditones) combined with a massively memory-optimized [TinySoundFont](https://github.com/schellingb/TinySoundFont), see the respective source files for more information. +Opus, OGG, and OpusFile are from [Xiph.org](https://xiph.org) with the Xiph license and patent described in src/{opusfile,libggg,libopus}/COPYING.. **NOTE** Opus decoding currently only works on the ESP32 due to the large memory requirements of opusfile. PRs to rewrite it to be less memory intensive would be much appreciated. + ## Neat Things People Have Done With ESP8266Audio If you have a neat use for this library, [I'd love to hear about it](mailto:earlephilhower@yahoo.com)! diff --git a/examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino b/examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino new file mode 100644 index 00000000..44db7c4a --- /dev/null +++ b/examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino @@ -0,0 +1,41 @@ +#include +#ifdef ESP32 + #include + #include "SPIFFS.h" +#else + #include +#endif +#include "AudioFileSourceSPIFFS.h" +#include "AudioGeneratorOpus.h" +#include "AudioOutputI2S.h" + +// The includes OPUS file is from Kevin MacLeod (incompetech.com), Licensed under Creative Commons: By Attribution 3.0, http://creativecommons.org/licenses/by/3.0/ + +AudioGeneratorOpus *opus; +AudioFileSourceSPIFFS *file; +AudioOutputI2S *out; + +void setup() +{ + WiFi.mode(WIFI_OFF); + Serial.begin(115200); + delay(1000); + SPIFFS.begin(); + Serial.printf("Sample Opus playback begins...\n"); + + audioLogger = &Serial; + file = new AudioFileSourceSPIFFS("/gs-16b-2c-44100hz.opus"); + out = new AudioOutputI2S(); + opus = new AudioGeneratorOpus(); + opus->begin(file, out); +} + +void loop() +{ + if (opus->isRunning()) { + if (!opus->loop()) opus->stop(); + } else { + Serial.printf("Opus done\n"); + delay(1000); + } +} diff --git a/examples/PlayOpusFromSPIFFS/data/gs-16b-2c-44100hz.opus b/examples/PlayOpusFromSPIFFS/data/gs-16b-2c-44100hz.opus new file mode 100644 index 0000000000000000000000000000000000000000..a66ff2e677146367559c1808c1953b0df2ccabaa GIT binary patch literal 219956 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

fSFMN+ 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

R}Z>On>WZ5i3 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 literal 0 HcmV?d00001 diff --git a/keywords.txt b/keywords.txt index 4cbfb9d8..251f431e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -15,6 +15,7 @@ AudioGeneratorFLAC KEYWORD1 AudioGeneratorMOD KEYWORD1 AudioGeneratorMIDI KEYWORD1 AudioGeneratorMP3 KEYWORD1 +AudioGeneratorOpus KEYWORD1 AudioGeneratorRTTTL KEYWORD1 AudioGeneratorTalkie KEYWORD1 AudioGeneratorWAV KEYWORD1 diff --git a/src/AudioGeneratorFLAC.cpp b/src/AudioGeneratorFLAC.cpp index 4878a6e9..1af00ce3 100644 --- a/src/AudioGeneratorFLAC.cpp +++ b/src/AudioGeneratorFLAC.cpp @@ -96,7 +96,7 @@ bool AudioGeneratorFLAC::loop() // Check for some weird case where above didn't give any data if (buffPtr == buffLen) { - goto done; // At some point the flac better error and we'll retudn + goto done; // At some point the flac better error and we'll return } if (bitsPerSample <= 16) { lastSample[AudioOutput::LEFTCHANNEL] = buff[0][buffPtr] & 0xffff; diff --git a/src/AudioGeneratorOpus.cpp b/src/AudioGeneratorOpus.cpp new file mode 100644 index 00000000..c8b80e89 --- /dev/null +++ b/src/AudioGeneratorOpus.cpp @@ -0,0 +1,143 @@ +/* + AudioGeneratorOpus + Audio output generator that plays Opus audio files + + Copyright (C) 2020 Earle F. Philhower, III + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include + +AudioGeneratorOpus::AudioGeneratorOpus() +{ + of = nullptr; + buff = nullptr; + buffPtr = 0; + buffLen = 0; + running = false; +} + +AudioGeneratorOpus::~AudioGeneratorOpus() +{ + if (of) op_free(of); + of = nullptr; + free(buff); + buff = nullptr; +} + +#define OPUS_BUFF 1024 + +bool AudioGeneratorOpus::begin(AudioFileSource *source, AudioOutput *output) +{ + buff = (int16_t*)malloc(OPUS_BUFF * sizeof(int16_t)); + if (!buff) return false; + + if (!source) return false; + file = source; + if (!output) return false; + this->output = output; + if (!file->isOpen()) return false; // Error + + of = op_open_callbacks((void*)this, &cb, nullptr, 0, nullptr); + if (!of) return false; + + prev_li = -1; + lastSample[0] = 0; + lastSample[1] = 0; + + buffPtr = 0; + buffLen = 0; + + output->begin(); + + // These are fixed by Opus + output->SetRate(48000); + output->SetBitsPerSample(16); + output->SetChannels(2); + + running = true; + return true; +} + +bool AudioGeneratorOpus::loop() +{ + + if (!running) goto done; + + if (!output->ConsumeSample(lastSample)) goto done; // Try and send last buffered sample + + do { + if (buffPtr == buffLen) { + int ret = op_read_stereo(of, (opus_int16 *)buff, OPUS_BUFF); + if (ret == OP_HOLE) { + // fprintf(stderr,"\nHole detected! Corrupt file segment?\n"); + continue; + } else if (ret < 0) { + running = false; + goto done; + } + buffPtr = 0; + buffLen = ret * 2; + } + + lastSample[AudioOutput::LEFTCHANNEL] = buff[buffPtr] & 0xffff; + lastSample[AudioOutput::RIGHTCHANNEL] = buff[buffPtr+1] & 0xffff; + buffPtr += 2; + } while (running && output->ConsumeSample(lastSample)); + +done: + file->loop(); + output->loop(); + + return running; +} + +bool AudioGeneratorOpus::stop() +{ + if (of) op_free(of); + of = nullptr; + free(buff); + buff = nullptr; + running = false; + output->stop(); + return true; +} + +bool AudioGeneratorOpus::isRunning() +{ + return running; +} + + +int AudioGeneratorOpus::read_cb(unsigned char *_ptr, int _nbytes) { + if (_nbytes == 0) return 0; + _nbytes = file->read(_ptr, _nbytes); + if (_nbytes == 0) return -1; + return _nbytes; +} + +int AudioGeneratorOpus::seek_cb(opus_int64 _offset, int _whence) { + if (!file->seek((int32_t)_offset, _whence)) return -1; + return 0; +} + +opus_int64 AudioGeneratorOpus::tell_cb() { + return file->getPos(); +} + +int AudioGeneratorOpus::close_cb() { + // NO OP, we close in main loop + return 0; +} diff --git a/src/AudioGeneratorOpus.h b/src/AudioGeneratorOpus.h new file mode 100644 index 00000000..171bd36d --- /dev/null +++ b/src/AudioGeneratorOpus.h @@ -0,0 +1,70 @@ +/* + AudioGeneratorOpus + Audio output generator that plays Opus audio files + + Copyright (C) 2020 Earle F. Philhower, III + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _AUDIOGENERATOROPUS_H +#define _AUDIOGENERATOROPUS_H + +#include +//#include "libopus/opus.h" +#include "opusfile/opusfile.h" + +class AudioGeneratorOpus : public AudioGenerator +{ + public: + AudioGeneratorOpus(); + virtual ~AudioGeneratorOpus() override; + virtual bool begin(AudioFileSource *source, AudioOutput *output) override; + virtual bool loop() override; + virtual bool stop() override; + virtual bool isRunning() override; + + protected: + // Opus callbacks, need static functions to bounce into C++ from C + static int OPUS_read(void *_stream, unsigned char *_ptr, int _nbytes) { + return static_cast(_stream)->read_cb(_ptr, _nbytes); + } + static int OPUS_seek(void *_stream, opus_int64 _offset, int _whence) { + return static_cast(_stream)->seek_cb(_offset, _whence); + } + static opus_int64 OPUS_tell(void *_stream) { + return static_cast(_stream)->tell_cb(); + } + static int OPUS_close(void *_stream) { + return static_cast(_stream)->close_cb(); + } + + // Actual Opus callbacks + int read_cb(unsigned char *_ptr, int _nbytes); + int seek_cb(opus_int64 _offset, int _whence); + opus_int64 tell_cb(); + int close_cb(); + + private: + OpusFileCallbacks cb = {OPUS_read, OPUS_seek, OPUS_tell, OPUS_close}; + OggOpusFile *of; + int prev_li; // To detect changes in streams + + int16_t *buff; + uint32_t buffPtr; + uint32_t buffLen; +}; + +#endif + diff --git a/src/libogg/AUTHORS b/src/libogg/AUTHORS new file mode 100644 index 00000000..a0023f2c --- /dev/null +++ b/src/libogg/AUTHORS @@ -0,0 +1,7 @@ +Monty +Greg Maxwell +Ralph Giles +Cristian Adam +Tim Terriberry + +and the rest of the Xiph.Org Foundation. diff --git a/src/libogg/CHANGES b/src/libogg/CHANGES new file mode 100644 index 00000000..855b0b16 --- /dev/null +++ b/src/libogg/CHANGES @@ -0,0 +1,104 @@ +Version 1.3.4 (2019 August 30) + +* Faster slice-by-8 CRC32 implementation. + see https://lwn.net/Articles/453931/ for motivation. +* Add CMake build. +* Deprecate Visual Studio project files in favor of CMake. +* configure --disable-crc option for fuzzing. +* Various build fixes. +* Documentation and example code fixes. + +Version 1.3.3 (2017 November 7) + + * Fix an issue with corrupt continued packet handling. + * Update Windows projects and build settings. + * Remove Mac OS 9 build support. + +Version 1.3.2 (2014 May 27) + + * Fix an bug in oggpack_writecopy(). + +Version 1.3.1 (2013 May 12) + +* Guard against very large packets. +* Respect the configure --docdir override. +* Documentation fixes. +* More Windows build fixes. + +Version 1.3.0 (2011 August 4) + +* Add ogg_stream_flush_fill() call + This produces longer packets on flush, similar to + what ogg_stream_pageout_fill() does for single pages. +* Windows build fixes + +Version 1.2.2 (2010 December 07) + +* Build fix (types correction) for Mac OS X +* Update win32 project files to Visual Studio 2008 +* ogg_stream_pageout_fill documentation fix + +Version 1.2.1 (2010 November 01) + +* Various build updates (see SVN) +* Add ogg_stream_pageout_fill() to API to allow applications + greater explicit flexibility in page sizing. +* Documentation updates including multiplexing description, + terminology and API (incl. ogg_packet_clear(), + ogg_stream_pageout_fill()) +* Correct possible buffer overwrite in stream encoding on 32 bit + when a single packet exceed 250MB. +* Correct read-buffer overrun [without side effects] under + similar circumstances. +* Update unit testing to work properly with new page spill + heuristic. + +Version 1.2.0 (2010 March 25) + +* Alter default flushing behavior to span less often and use larger page + sizes when packet sizes are large. +* Build fixes for additional compilers +* Documentation updates + +Version 1.1.4 (2009 June 24) + +* New async error reporting mechanism. Calls made after a fatal error are + now safely handled in the event an error code is ignored +* Added allocation checks useful to some embedded applications +* fix possible read past end of buffer when reading 0 bits +* Updates to API documentation +* Build fixes + +Version 1.1.3 (2005 November 27) + + * Correct a bug in the granulepos field of pages where no packet ends + * New VS2003 and XCode builds, minor fixes to other builds + * documentation fixes and cleanup + +Version 1.1.2 (2004 September 23) + + * fix a bug with multipage packet assembly after seek + +Version 1.1.1 (2004 September 12) + + * various bugfixes + * important bugfix for 64-bit platforms + * various portability fixes + * autotools cleanup from Thomas Vander Stichele + * Symbian OS build support from Colin Ward at CSIRO + * new multiplexed Ogg stream documentation + +Version 1.1 (2003 November 17) + + * big-endian bitpacker routines for Theora + * various portability fixes + * improved API documentation + * RFC 3533 documentation of the format by Silvia Pfeiffer at CSIRO + * RFC 3534 documentation of the application/ogg mime-type by Linus Walleij + +Version 1.0 (2002 July 19) + + * First stable release + * little-endian bitpacker routines for Vorbis + * basic Ogg bitstream sync and coding support + diff --git a/src/libogg/COPYING b/src/libogg/COPYING new file mode 100644 index 00000000..6111c6c5 --- /dev/null +++ b/src/libogg/COPYING @@ -0,0 +1,28 @@ +Copyright (c) 2002, Xiph.org Foundation + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/libogg/README.esp8266.md b/src/libogg/README.esp8266.md new file mode 100644 index 00000000..f63d68f5 --- /dev/null +++ b/src/libogg/README.esp8266.md @@ -0,0 +1,3 @@ +This is libogg from Xiph, modified to build under Arduino by . + +OGG license/etc. unchanged. diff --git a/src/libogg/README.md b/src/libogg/README.md new file mode 100644 index 00000000..63545e28 --- /dev/null +++ b/src/libogg/README.md @@ -0,0 +1,133 @@ +# Ogg + +[![Travis Build Status](https://travis-ci.org/xiph/ogg.svg?branch=master)](https://travis-ci.org/xiph/ogg) +[![Jenkins Build Status](https://mf4.xiph.org/jenkins/job/libogg/badge/icon)](https://mf4.xiph.org/jenkins/job/libogg/) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/xiph/ogg?branch=master&svg=true)](https://ci.appveyor.com/project/rillian/ogg) + +Ogg project codecs use the Ogg bitstream format to arrange the raw, +compressed bitstream into a more robust, useful form. For example, +the Ogg bitstream makes seeking, time stamping and error recovery +possible, as well as mixing several sepearate, concurrent media +streams into a single physical bitstream. + +## What's here ## +This source distribution includes libogg and nothing else. Other modules +(eg, the modules libvorbis, vorbis-tools for the Vorbis music codec, +libtheora for the Theora video codec) contain the codec libraries for +use with Ogg bitstreams. + +Directory: + +- `src` The source for libogg, a BSD-license inplementation of the public domain Ogg bitstream format + +- `include` Library API headers + +- `doc` Ogg specification and libogg API documents + +- `win32` Win32 projects and build automation + +- `macosx` Mac OS X project and build files + +## Contact ## + +The Ogg homepage is located at https://www.xiph.org/ogg/ . +Up to date technical documents, contact information, source code and +pre-built utilities may be found there. + +## Building ## + +#### Building from tarball distributions #### + + ./configure + make + +and optionally (as root): + + make install + +This will install the Ogg libraries (static and shared) into +/usr/local/lib, includes into /usr/local/include and API +documentation into /usr/local/share/doc. + +#### Building from repository source #### + +A standard svn build should consist of nothing more than: + + ./autogen.sh + ./configure + make + +and as root if desired : + + make install + +#### Building on Windows #### + +Use the project file in the win32 directory. It should compile out of the box. + +#### Cross-compiling from Linux to Windows #### + +It is also possible to cross compile from Linux to windows using the MinGW +cross tools and even to run the test suite under Wine, the Linux/*nix +windows emulator. + +On Debian and Ubuntu systems, these cross compiler tools can be installed +by doing: + + sudo apt-get mingw32 mingw32-binutils mingw32-runtime wine + +Once these tools are installed its possible to compile and test by +executing the following commands, or something similar depending on +your system: + + ./configure --host=i586-mingw32msvc --target=i586-mingw32msvc --build=i586-linux + make + make check + +(Build instructions for Ogg codecs such as vorbis are similar and may +be found in those source modules' README files) + +## Building with CMake ## + +Ogg supports building using [CMake](http://www.cmake.org/). CMake is a meta build system that generates native projects for each platform. +To generate projects just run cmake replacing `YOUR-PROJECT-GENERATOR` with a proper generator from a list [here](http://www.cmake.org/cmake/help/v3.2/manual/cmake-generators.7.html): + + mkdir build + cd build + cmake -G YOUR-PROJECT-GENERATOR .. + +Note that by default cmake generates projects that will build static libraries. +To generate projects that will build dynamic library use `BUILD_SHARED_LIBS` option like this: + + cmake -G YOUR-PROJECT-GENERATOR -DBUILD_SHARED_LIBS=1 .. + +After projects are generated use them as usual + +#### Building on Windows #### + +Use proper generator for your Visual Studio version like: + + cmake -G "Visual Studio 12 2013" .. + +#### Building on Mac OS X #### + +Use Xcode generator. To build framework run: + + cmake -G Xcode -DBUILD_FRAMEWORK=1 .. + +#### Building on Linux #### + +Use Makefile generator which is default one. + + cmake .. + make + +## License ## + +THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. +USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS +GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE +IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. + +THE OggVorbis SOURCE CODE IS COPYRIGHT (C) 1994-2019 +by the Xiph.Org Foundation https://www.xiph.org/ diff --git a/src/libogg/bitwise.c b/src/libogg/bitwise.c new file mode 100644 index 00000000..f977d5a0 --- /dev/null +++ b/src/libogg/bitwise.c @@ -0,0 +1,1087 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: packing variable sized words into an octet stream + + ********************************************************************/ + +/* We're 'LSb' endian; if we write a word but read individual bits, + then we'll read the lsb first */ + +#include +#include +#include +#include "ogg/ogg.h" + +#define BUFFER_INCREMENT 256 + +static const unsigned long mask[]= +{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, + 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, + 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, + 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, + 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, + 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, + 0x3fffffff,0x7fffffff,0xffffffff }; + +static const unsigned int mask8B[]= +{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; + +void oggpack_writeinit(oggpack_buffer *b){ + memset(b,0,sizeof(*b)); + b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT); + b->buffer[0]='\0'; + b->storage=BUFFER_INCREMENT; +} + +void oggpackB_writeinit(oggpack_buffer *b){ + oggpack_writeinit(b); +} + +int oggpack_writecheck(oggpack_buffer *b){ + if(!b->ptr || !b->storage)return -1; + return 0; +} + +int oggpackB_writecheck(oggpack_buffer *b){ + return oggpack_writecheck(b); +} + +void oggpack_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask[bits]; + } +} + +void oggpackB_writetrunc(oggpack_buffer *b,long bits){ + long bytes=bits>>3; + if(b->ptr){ + bits-=bytes*8; + b->ptr=b->buffer+bytes; + b->endbit=bits; + b->endbyte=bytes; + *b->ptr&=mask8B[bits]; + } +} + +/* Takes only up to 32 bits. */ +void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value&=mask[bits]; + bits+=b->endbit; + + b->ptr[0]|=value<endbit; + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +/* Takes only up to 32 bits. */ +void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ + if(bits<0 || bits>32) goto err; + if(b->endbyte>=b->storage-4){ + void *ret; + if(!b->ptr)return; + if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; + ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); + if(!ret) goto err; + b->buffer=ret; + b->storage+=BUFFER_INCREMENT; + b->ptr=b->buffer+b->endbyte; + } + + value=(value&mask[bits])<<(32-bits); + bits+=b->endbit; + + b->ptr[0]|=value>>(24+b->endbit); + + if(bits>=8){ + b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); + if(bits>=16){ + b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); + if(bits>=24){ + b->ptr[3]=(unsigned char)(value>>(b->endbit)); + if(bits>=32){ + if(b->endbit) + b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); + else + b->ptr[4]=0; + } + } + } + } + + b->endbyte+=bits/8; + b->ptr+=bits/8; + b->endbit=bits&7; + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpack_write(b,0,bits); +} + +void oggpackB_writealign(oggpack_buffer *b){ + int bits=8-b->endbit; + if(bits<8) + oggpackB_write(b,0,bits); +} + +static void oggpack_writecopy_helper(oggpack_buffer *b, + void *source, + long bits, + void (*w)(oggpack_buffer *, + unsigned long, + int), + int msb){ + unsigned char *ptr=(unsigned char *)source; + + long bytes=bits/8; + long pbytes=(b->endbit+bits)/8; + bits-=bytes*8; + + /* expand storage up-front */ + if(b->endbyte+pbytes>=b->storage){ + void *ret; + if(!b->ptr) goto err; + if(b->storage>b->endbyte+pbytes+BUFFER_INCREMENT) goto err; + b->storage=b->endbyte+pbytes+BUFFER_INCREMENT; + ret=_ogg_realloc(b->buffer,b->storage); + if(!ret) goto err; + b->buffer=ret; + b->ptr=b->buffer+b->endbyte; + } + + /* copy whole octets */ + if(b->endbit){ + int i; + /* unaligned copy. Do it the hard way. */ + for(i=0;iptr,source,bytes); + b->ptr+=bytes; + b->endbyte+=bytes; + *b->ptr=0; + } + + /* copy trailing bits */ + if(bits){ + if(msb) + w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); + else + w(b,(unsigned long)(ptr[bytes]),bits); + } + return; + err: + oggpack_writeclear(b); +} + +void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpack_write,0); +} + +void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ + oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); +} + +void oggpack_reset(oggpack_buffer *b){ + if(!b->ptr)return; + b->ptr=b->buffer; + b->buffer[0]=0; + b->endbit=b->endbyte=0; +} + +void oggpackB_reset(oggpack_buffer *b){ + oggpack_reset(b); +} + +void oggpack_writeclear(oggpack_buffer *b){ + if(b->buffer)_ogg_free(b->buffer); + memset(b,0,sizeof(*b)); +} + +void oggpackB_writeclear(oggpack_buffer *b){ + oggpack_writeclear(b); +} + +void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + memset(b,0,sizeof(*b)); + b->buffer=b->ptr=buf; + b->storage=bytes; +} + +void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ + oggpack_readinit(b,buf,bytes); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpack_look(oggpack_buffer *b,int bits){ + unsigned long ret; + unsigned long m; + + if(bits<0 || bits>32) return -1; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + return(m&ret); +} + +/* Read in bits without advancing the bitptr; bits <= 32 */ +long oggpackB_look(oggpack_buffer *b,int bits){ + unsigned long ret; + int m=32-bits; + + if(m<0 || m>32) return -1; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) return -1; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); +} + +long oggpack_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>b->endbit)&1); +} + +long oggpackB_look1(oggpack_buffer *b){ + if(b->endbyte>=b->storage)return(-1); + return((b->ptr[0]>>(7-b->endbit))&1); +} + +void oggpack_adv(oggpack_buffer *b,int bits){ + bits+=b->endbit; + + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; +} + +void oggpackB_adv(oggpack_buffer *b,int bits){ + oggpack_adv(b,bits); +} + +void oggpack_adv1(oggpack_buffer *b){ + if(++(b->endbit)>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } +} + +void oggpackB_adv1(oggpack_buffer *b){ + oggpack_adv1(b); +} + +/* bits <= 32 */ +long oggpack_read(oggpack_buffer *b,int bits){ + long ret; + unsigned long m; + + if(bits<0 || bits>32) goto err; + m=mask[bits]; + bits+=b->endbit; + + if(b->endbyte >= b->storage-4){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]>>b->endbit; + if(bits>8){ + ret|=b->ptr[1]<<(8-b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(16-b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(24-b->endbit); + if(bits>32 && b->endbit){ + ret|=b->ptr[4]<<(32-b->endbit); + } + } + } + } + ret&=m; + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +/* bits <= 32 */ +long oggpackB_read(oggpack_buffer *b,int bits){ + long ret; + long m=32-bits; + + if(m<0 || m>32) goto err; + bits+=b->endbit; + + if(b->endbyte+4>=b->storage){ + /* not the main path */ + if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; + /* special case to avoid reading b->ptr[0], which might be past the end of + the buffer; also skips some useless accounting */ + else if(!bits)return(0L); + } + + ret=b->ptr[0]<<(24+b->endbit); + if(bits>8){ + ret|=b->ptr[1]<<(16+b->endbit); + if(bits>16){ + ret|=b->ptr[2]<<(8+b->endbit); + if(bits>24){ + ret|=b->ptr[3]<<(b->endbit); + if(bits>32 && b->endbit) + ret|=b->ptr[4]>>(8-b->endbit); + } + } + } + ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); + + b->ptr+=bits/8; + b->endbyte+=bits/8; + b->endbit=bits&7; + return ret; + + overflow: + err: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>b->endbit)&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpackB_read1(oggpack_buffer *b){ + long ret; + + if(b->endbyte >= b->storage) goto overflow; + ret=(b->ptr[0]>>(7-b->endbit))&1; + + b->endbit++; + if(b->endbit>7){ + b->endbit=0; + b->ptr++; + b->endbyte++; + } + return ret; + + overflow: + b->ptr=NULL; + b->endbyte=b->storage; + b->endbit=1; + return -1L; +} + +long oggpack_bytes(oggpack_buffer *b){ + return(b->endbyte+(b->endbit+7)/8); +} + +long oggpack_bits(oggpack_buffer *b){ + return(b->endbyte*8+b->endbit); +} + +long oggpackB_bytes(oggpack_buffer *b){ + return oggpack_bytes(b); +} + +long oggpackB_bits(oggpack_buffer *b){ + return oggpack_bits(b); +} + +unsigned char *oggpack_get_buffer(oggpack_buffer *b){ + return(b->buffer); +} + +unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ + return oggpack_get_buffer(b); +} + +/* Self test of the bitwise routines; everything else is based on + them, so they damned well better be solid. */ + +#ifdef _V_SELFTEST +#include + +static int ilog(unsigned int v){ + int ret=0; + while(v){ + ret++; + v>>=1; + } + return(ret); +} + +oggpack_buffer o; +oggpack_buffer r; + +void report(char *in){ + fprintf(stderr,"%s",in); + exit(1); +} + +void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ + long bytes,i; + unsigned char *buffer; + + oggpack_reset(&o); + for(i=0;i header file. */ +#define HAVE_DLFCN_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 0 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Name of package */ +#define PACKAGE "libogg" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "ogg-dev@xiph.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "libogg" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "libogg 1.3.4" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "libogg" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.3.4" + +/* The size of `int', as computed by sizeof. */ +#define SIZEOF_INT 4 + +/* The size of `int16_t', as computed by sizeof. */ +#define SIZEOF_INT16_T 2 + +/* The size of `int32_t', as computed by sizeof. */ +#define SIZEOF_INT32_T 4 + +/* The size of `int64_t', as computed by sizeof. */ +#define SIZEOF_INT64_T 8 + +/* The size of `long', as computed by sizeof. */ +#define SIZEOF_LONG 4 + +/* The size of `long long', as computed by sizeof. */ +#define SIZEOF_LONG_LONG 8 + +/* The size of `short', as computed by sizeof. */ +#define SIZEOF_SHORT 2 + +/* The size of `uint16_t', as computed by sizeof. */ +#define SIZEOF_UINT16_T 2 + +/* The size of `uint32_t', as computed by sizeof. */ +#define SIZEOF_UINT32_T 4 + +/* The size of `uint64_t', as computed by sizeof. */ +#define SIZEOF_UINT64_T 8 + +/* The size of `u_int16_t', as computed by sizeof. */ +#define SIZEOF_U_INT16_T 2 + +/* The size of `u_int32_t', as computed by sizeof. */ +#define SIZEOF_U_INT32_T 4 + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "1.3.4" + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ diff --git a/src/libogg/crctable.h b/src/libogg/crctable.h new file mode 100644 index 00000000..bf0ff4a3 --- /dev/null +++ b/src/libogg/crctable.h @@ -0,0 +1,279 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ********************************************************************/ + +#include "ogg/os_types.h" +#include + +static const ogg_uint32_t crc_lookup[8][256] PROGMEM ={ +{0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, + 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, + 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, + 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, + 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, + 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, + 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, + 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, + 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, + 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, + 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, + 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, + 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, + 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, + 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, + 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, + 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, + 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, + 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, + 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, + 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, + 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, + 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, + 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, + 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, + 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, + 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, + 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, + 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, + 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, + 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, + 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}, + +{0x00000000,0xd219c1dc,0xa0f29e0f,0x72eb5fd3,0x452421a9,0x973de075,0xe5d6bfa6,0x37cf7e7a, + 0x8a484352,0x5851828e,0x2abadd5d,0xf8a31c81,0xcf6c62fb,0x1d75a327,0x6f9efcf4,0xbd873d28, + 0x10519b13,0xc2485acf,0xb0a3051c,0x62bac4c0,0x5575baba,0x876c7b66,0xf58724b5,0x279ee569, + 0x9a19d841,0x4800199d,0x3aeb464e,0xe8f28792,0xdf3df9e8,0x0d243834,0x7fcf67e7,0xadd6a63b, + 0x20a33626,0xf2baf7fa,0x8051a829,0x524869f5,0x6587178f,0xb79ed653,0xc5758980,0x176c485c, + 0xaaeb7574,0x78f2b4a8,0x0a19eb7b,0xd8002aa7,0xefcf54dd,0x3dd69501,0x4f3dcad2,0x9d240b0e, + 0x30f2ad35,0xe2eb6ce9,0x9000333a,0x4219f2e6,0x75d68c9c,0xa7cf4d40,0xd5241293,0x073dd34f, + 0xbabaee67,0x68a32fbb,0x1a487068,0xc851b1b4,0xff9ecfce,0x2d870e12,0x5f6c51c1,0x8d75901d, + 0x41466c4c,0x935fad90,0xe1b4f243,0x33ad339f,0x04624de5,0xd67b8c39,0xa490d3ea,0x76891236, + 0xcb0e2f1e,0x1917eec2,0x6bfcb111,0xb9e570cd,0x8e2a0eb7,0x5c33cf6b,0x2ed890b8,0xfcc15164, + 0x5117f75f,0x830e3683,0xf1e56950,0x23fca88c,0x1433d6f6,0xc62a172a,0xb4c148f9,0x66d88925, + 0xdb5fb40d,0x094675d1,0x7bad2a02,0xa9b4ebde,0x9e7b95a4,0x4c625478,0x3e890bab,0xec90ca77, + 0x61e55a6a,0xb3fc9bb6,0xc117c465,0x130e05b9,0x24c17bc3,0xf6d8ba1f,0x8433e5cc,0x562a2410, + 0xebad1938,0x39b4d8e4,0x4b5f8737,0x994646eb,0xae893891,0x7c90f94d,0x0e7ba69e,0xdc626742, + 0x71b4c179,0xa3ad00a5,0xd1465f76,0x035f9eaa,0x3490e0d0,0xe689210c,0x94627edf,0x467bbf03, + 0xfbfc822b,0x29e543f7,0x5b0e1c24,0x8917ddf8,0xbed8a382,0x6cc1625e,0x1e2a3d8d,0xcc33fc51, + 0x828cd898,0x50951944,0x227e4697,0xf067874b,0xc7a8f931,0x15b138ed,0x675a673e,0xb543a6e2, + 0x08c49bca,0xdadd5a16,0xa83605c5,0x7a2fc419,0x4de0ba63,0x9ff97bbf,0xed12246c,0x3f0be5b0, + 0x92dd438b,0x40c48257,0x322fdd84,0xe0361c58,0xd7f96222,0x05e0a3fe,0x770bfc2d,0xa5123df1, + 0x189500d9,0xca8cc105,0xb8679ed6,0x6a7e5f0a,0x5db12170,0x8fa8e0ac,0xfd43bf7f,0x2f5a7ea3, + 0xa22feebe,0x70362f62,0x02dd70b1,0xd0c4b16d,0xe70bcf17,0x35120ecb,0x47f95118,0x95e090c4, + 0x2867adec,0xfa7e6c30,0x889533e3,0x5a8cf23f,0x6d438c45,0xbf5a4d99,0xcdb1124a,0x1fa8d396, + 0xb27e75ad,0x6067b471,0x128ceba2,0xc0952a7e,0xf75a5404,0x254395d8,0x57a8ca0b,0x85b10bd7, + 0x383636ff,0xea2ff723,0x98c4a8f0,0x4add692c,0x7d121756,0xaf0bd68a,0xdde08959,0x0ff94885, + 0xc3cab4d4,0x11d37508,0x63382adb,0xb121eb07,0x86ee957d,0x54f754a1,0x261c0b72,0xf405caae, + 0x4982f786,0x9b9b365a,0xe9706989,0x3b69a855,0x0ca6d62f,0xdebf17f3,0xac544820,0x7e4d89fc, + 0xd39b2fc7,0x0182ee1b,0x7369b1c8,0xa1707014,0x96bf0e6e,0x44a6cfb2,0x364d9061,0xe45451bd, + 0x59d36c95,0x8bcaad49,0xf921f29a,0x2b383346,0x1cf74d3c,0xceee8ce0,0xbc05d333,0x6e1c12ef, + 0xe36982f2,0x3170432e,0x439b1cfd,0x9182dd21,0xa64da35b,0x74546287,0x06bf3d54,0xd4a6fc88, + 0x6921c1a0,0xbb38007c,0xc9d35faf,0x1bca9e73,0x2c05e009,0xfe1c21d5,0x8cf77e06,0x5eeebfda, + 0xf33819e1,0x2121d83d,0x53ca87ee,0x81d34632,0xb61c3848,0x6405f994,0x16eea647,0xc4f7679b, + 0x79705ab3,0xab699b6f,0xd982c4bc,0x0b9b0560,0x3c547b1a,0xee4dbac6,0x9ca6e515,0x4ebf24c9}, + +{0x00000000,0x01d8ac87,0x03b1590e,0x0269f589,0x0762b21c,0x06ba1e9b,0x04d3eb12,0x050b4795, + 0x0ec56438,0x0f1dc8bf,0x0d743d36,0x0cac91b1,0x09a7d624,0x087f7aa3,0x0a168f2a,0x0bce23ad, + 0x1d8ac870,0x1c5264f7,0x1e3b917e,0x1fe33df9,0x1ae87a6c,0x1b30d6eb,0x19592362,0x18818fe5, + 0x134fac48,0x129700cf,0x10fef546,0x112659c1,0x142d1e54,0x15f5b2d3,0x179c475a,0x1644ebdd, + 0x3b1590e0,0x3acd3c67,0x38a4c9ee,0x397c6569,0x3c7722fc,0x3daf8e7b,0x3fc67bf2,0x3e1ed775, + 0x35d0f4d8,0x3408585f,0x3661add6,0x37b90151,0x32b246c4,0x336aea43,0x31031fca,0x30dbb34d, + 0x269f5890,0x2747f417,0x252e019e,0x24f6ad19,0x21fdea8c,0x2025460b,0x224cb382,0x23941f05, + 0x285a3ca8,0x2982902f,0x2beb65a6,0x2a33c921,0x2f388eb4,0x2ee02233,0x2c89d7ba,0x2d517b3d, + 0x762b21c0,0x77f38d47,0x759a78ce,0x7442d449,0x714993dc,0x70913f5b,0x72f8cad2,0x73206655, + 0x78ee45f8,0x7936e97f,0x7b5f1cf6,0x7a87b071,0x7f8cf7e4,0x7e545b63,0x7c3daeea,0x7de5026d, + 0x6ba1e9b0,0x6a794537,0x6810b0be,0x69c81c39,0x6cc35bac,0x6d1bf72b,0x6f7202a2,0x6eaaae25, + 0x65648d88,0x64bc210f,0x66d5d486,0x670d7801,0x62063f94,0x63de9313,0x61b7669a,0x606fca1d, + 0x4d3eb120,0x4ce61da7,0x4e8fe82e,0x4f5744a9,0x4a5c033c,0x4b84afbb,0x49ed5a32,0x4835f6b5, + 0x43fbd518,0x4223799f,0x404a8c16,0x41922091,0x44996704,0x4541cb83,0x47283e0a,0x46f0928d, + 0x50b47950,0x516cd5d7,0x5305205e,0x52dd8cd9,0x57d6cb4c,0x560e67cb,0x54679242,0x55bf3ec5, + 0x5e711d68,0x5fa9b1ef,0x5dc04466,0x5c18e8e1,0x5913af74,0x58cb03f3,0x5aa2f67a,0x5b7a5afd, + 0xec564380,0xed8eef07,0xefe71a8e,0xee3fb609,0xeb34f19c,0xeaec5d1b,0xe885a892,0xe95d0415, + 0xe29327b8,0xe34b8b3f,0xe1227eb6,0xe0fad231,0xe5f195a4,0xe4293923,0xe640ccaa,0xe798602d, + 0xf1dc8bf0,0xf0042777,0xf26dd2fe,0xf3b57e79,0xf6be39ec,0xf766956b,0xf50f60e2,0xf4d7cc65, + 0xff19efc8,0xfec1434f,0xfca8b6c6,0xfd701a41,0xf87b5dd4,0xf9a3f153,0xfbca04da,0xfa12a85d, + 0xd743d360,0xd69b7fe7,0xd4f28a6e,0xd52a26e9,0xd021617c,0xd1f9cdfb,0xd3903872,0xd24894f5, + 0xd986b758,0xd85e1bdf,0xda37ee56,0xdbef42d1,0xdee40544,0xdf3ca9c3,0xdd555c4a,0xdc8df0cd, + 0xcac91b10,0xcb11b797,0xc978421e,0xc8a0ee99,0xcdaba90c,0xcc73058b,0xce1af002,0xcfc25c85, + 0xc40c7f28,0xc5d4d3af,0xc7bd2626,0xc6658aa1,0xc36ecd34,0xc2b661b3,0xc0df943a,0xc10738bd, + 0x9a7d6240,0x9ba5cec7,0x99cc3b4e,0x981497c9,0x9d1fd05c,0x9cc77cdb,0x9eae8952,0x9f7625d5, + 0x94b80678,0x9560aaff,0x97095f76,0x96d1f3f1,0x93dab464,0x920218e3,0x906bed6a,0x91b341ed, + 0x87f7aa30,0x862f06b7,0x8446f33e,0x859e5fb9,0x8095182c,0x814db4ab,0x83244122,0x82fceda5, + 0x8932ce08,0x88ea628f,0x8a839706,0x8b5b3b81,0x8e507c14,0x8f88d093,0x8de1251a,0x8c39899d, + 0xa168f2a0,0xa0b05e27,0xa2d9abae,0xa3010729,0xa60a40bc,0xa7d2ec3b,0xa5bb19b2,0xa463b535, + 0xafad9698,0xae753a1f,0xac1ccf96,0xadc46311,0xa8cf2484,0xa9178803,0xab7e7d8a,0xaaa6d10d, + 0xbce23ad0,0xbd3a9657,0xbf5363de,0xbe8bcf59,0xbb8088cc,0xba58244b,0xb831d1c2,0xb9e97d45, + 0xb2275ee8,0xb3fff26f,0xb19607e6,0xb04eab61,0xb545ecf4,0xb49d4073,0xb6f4b5fa,0xb72c197d}, + +{0x00000000,0xdc6d9ab7,0xbc1a28d9,0x6077b26e,0x7cf54c05,0xa098d6b2,0xc0ef64dc,0x1c82fe6b, + 0xf9ea980a,0x258702bd,0x45f0b0d3,0x999d2a64,0x851fd40f,0x59724eb8,0x3905fcd6,0xe5686661, + 0xf7142da3,0x2b79b714,0x4b0e057a,0x97639fcd,0x8be161a6,0x578cfb11,0x37fb497f,0xeb96d3c8, + 0x0efeb5a9,0xd2932f1e,0xb2e49d70,0x6e8907c7,0x720bf9ac,0xae66631b,0xce11d175,0x127c4bc2, + 0xeae946f1,0x3684dc46,0x56f36e28,0x8a9ef49f,0x961c0af4,0x4a719043,0x2a06222d,0xf66bb89a, + 0x1303defb,0xcf6e444c,0xaf19f622,0x73746c95,0x6ff692fe,0xb39b0849,0xd3ecba27,0x0f812090, + 0x1dfd6b52,0xc190f1e5,0xa1e7438b,0x7d8ad93c,0x61082757,0xbd65bde0,0xdd120f8e,0x017f9539, + 0xe417f358,0x387a69ef,0x580ddb81,0x84604136,0x98e2bf5d,0x448f25ea,0x24f89784,0xf8950d33, + 0xd1139055,0x0d7e0ae2,0x6d09b88c,0xb164223b,0xade6dc50,0x718b46e7,0x11fcf489,0xcd916e3e, + 0x28f9085f,0xf49492e8,0x94e32086,0x488eba31,0x540c445a,0x8861deed,0xe8166c83,0x347bf634, + 0x2607bdf6,0xfa6a2741,0x9a1d952f,0x46700f98,0x5af2f1f3,0x869f6b44,0xe6e8d92a,0x3a85439d, + 0xdfed25fc,0x0380bf4b,0x63f70d25,0xbf9a9792,0xa31869f9,0x7f75f34e,0x1f024120,0xc36fdb97, + 0x3bfad6a4,0xe7974c13,0x87e0fe7d,0x5b8d64ca,0x470f9aa1,0x9b620016,0xfb15b278,0x277828cf, + 0xc2104eae,0x1e7dd419,0x7e0a6677,0xa267fcc0,0xbee502ab,0x6288981c,0x02ff2a72,0xde92b0c5, + 0xcceefb07,0x108361b0,0x70f4d3de,0xac994969,0xb01bb702,0x6c762db5,0x0c019fdb,0xd06c056c, + 0x3504630d,0xe969f9ba,0x891e4bd4,0x5573d163,0x49f12f08,0x959cb5bf,0xf5eb07d1,0x29869d66, + 0xa6e63d1d,0x7a8ba7aa,0x1afc15c4,0xc6918f73,0xda137118,0x067eebaf,0x660959c1,0xba64c376, + 0x5f0ca517,0x83613fa0,0xe3168dce,0x3f7b1779,0x23f9e912,0xff9473a5,0x9fe3c1cb,0x438e5b7c, + 0x51f210be,0x8d9f8a09,0xede83867,0x3185a2d0,0x2d075cbb,0xf16ac60c,0x911d7462,0x4d70eed5, + 0xa81888b4,0x74751203,0x1402a06d,0xc86f3ada,0xd4edc4b1,0x08805e06,0x68f7ec68,0xb49a76df, + 0x4c0f7bec,0x9062e15b,0xf0155335,0x2c78c982,0x30fa37e9,0xec97ad5e,0x8ce01f30,0x508d8587, + 0xb5e5e3e6,0x69887951,0x09ffcb3f,0xd5925188,0xc910afe3,0x157d3554,0x750a873a,0xa9671d8d, + 0xbb1b564f,0x6776ccf8,0x07017e96,0xdb6ce421,0xc7ee1a4a,0x1b8380fd,0x7bf43293,0xa799a824, + 0x42f1ce45,0x9e9c54f2,0xfeebe69c,0x22867c2b,0x3e048240,0xe26918f7,0x821eaa99,0x5e73302e, + 0x77f5ad48,0xab9837ff,0xcbef8591,0x17821f26,0x0b00e14d,0xd76d7bfa,0xb71ac994,0x6b775323, + 0x8e1f3542,0x5272aff5,0x32051d9b,0xee68872c,0xf2ea7947,0x2e87e3f0,0x4ef0519e,0x929dcb29, + 0x80e180eb,0x5c8c1a5c,0x3cfba832,0xe0963285,0xfc14ccee,0x20795659,0x400ee437,0x9c637e80, + 0x790b18e1,0xa5668256,0xc5113038,0x197caa8f,0x05fe54e4,0xd993ce53,0xb9e47c3d,0x6589e68a, + 0x9d1cebb9,0x4171710e,0x2106c360,0xfd6b59d7,0xe1e9a7bc,0x3d843d0b,0x5df38f65,0x819e15d2, + 0x64f673b3,0xb89be904,0xd8ec5b6a,0x0481c1dd,0x18033fb6,0xc46ea501,0xa419176f,0x78748dd8, + 0x6a08c61a,0xb6655cad,0xd612eec3,0x0a7f7474,0x16fd8a1f,0xca9010a8,0xaae7a2c6,0x768a3871, + 0x93e25e10,0x4f8fc4a7,0x2ff876c9,0xf395ec7e,0xef171215,0x337a88a2,0x530d3acc,0x8f60a07b}, + +{0x00000000,0x490d678d,0x921acf1a,0xdb17a897,0x20f48383,0x69f9e40e,0xb2ee4c99,0xfbe32b14, + 0x41e90706,0x08e4608b,0xd3f3c81c,0x9afeaf91,0x611d8485,0x2810e308,0xf3074b9f,0xba0a2c12, + 0x83d20e0c,0xcadf6981,0x11c8c116,0x58c5a69b,0xa3268d8f,0xea2bea02,0x313c4295,0x78312518, + 0xc23b090a,0x8b366e87,0x5021c610,0x192ca19d,0xe2cf8a89,0xabc2ed04,0x70d54593,0x39d8221e, + 0x036501af,0x4a686622,0x917fceb5,0xd872a938,0x2391822c,0x6a9ce5a1,0xb18b4d36,0xf8862abb, + 0x428c06a9,0x0b816124,0xd096c9b3,0x999bae3e,0x6278852a,0x2b75e2a7,0xf0624a30,0xb96f2dbd, + 0x80b70fa3,0xc9ba682e,0x12adc0b9,0x5ba0a734,0xa0438c20,0xe94eebad,0x3259433a,0x7b5424b7, + 0xc15e08a5,0x88536f28,0x5344c7bf,0x1a49a032,0xe1aa8b26,0xa8a7ecab,0x73b0443c,0x3abd23b1, + 0x06ca035e,0x4fc764d3,0x94d0cc44,0xddddabc9,0x263e80dd,0x6f33e750,0xb4244fc7,0xfd29284a, + 0x47230458,0x0e2e63d5,0xd539cb42,0x9c34accf,0x67d787db,0x2edae056,0xf5cd48c1,0xbcc02f4c, + 0x85180d52,0xcc156adf,0x1702c248,0x5e0fa5c5,0xa5ec8ed1,0xece1e95c,0x37f641cb,0x7efb2646, + 0xc4f10a54,0x8dfc6dd9,0x56ebc54e,0x1fe6a2c3,0xe40589d7,0xad08ee5a,0x761f46cd,0x3f122140, + 0x05af02f1,0x4ca2657c,0x97b5cdeb,0xdeb8aa66,0x255b8172,0x6c56e6ff,0xb7414e68,0xfe4c29e5, + 0x444605f7,0x0d4b627a,0xd65ccaed,0x9f51ad60,0x64b28674,0x2dbfe1f9,0xf6a8496e,0xbfa52ee3, + 0x867d0cfd,0xcf706b70,0x1467c3e7,0x5d6aa46a,0xa6898f7e,0xef84e8f3,0x34934064,0x7d9e27e9, + 0xc7940bfb,0x8e996c76,0x558ec4e1,0x1c83a36c,0xe7608878,0xae6deff5,0x757a4762,0x3c7720ef, + 0x0d9406bc,0x44996131,0x9f8ec9a6,0xd683ae2b,0x2d60853f,0x646de2b2,0xbf7a4a25,0xf6772da8, + 0x4c7d01ba,0x05706637,0xde67cea0,0x976aa92d,0x6c898239,0x2584e5b4,0xfe934d23,0xb79e2aae, + 0x8e4608b0,0xc74b6f3d,0x1c5cc7aa,0x5551a027,0xaeb28b33,0xe7bfecbe,0x3ca84429,0x75a523a4, + 0xcfaf0fb6,0x86a2683b,0x5db5c0ac,0x14b8a721,0xef5b8c35,0xa656ebb8,0x7d41432f,0x344c24a2, + 0x0ef10713,0x47fc609e,0x9cebc809,0xd5e6af84,0x2e058490,0x6708e31d,0xbc1f4b8a,0xf5122c07, + 0x4f180015,0x06156798,0xdd02cf0f,0x940fa882,0x6fec8396,0x26e1e41b,0xfdf64c8c,0xb4fb2b01, + 0x8d23091f,0xc42e6e92,0x1f39c605,0x5634a188,0xadd78a9c,0xe4daed11,0x3fcd4586,0x76c0220b, + 0xccca0e19,0x85c76994,0x5ed0c103,0x17dda68e,0xec3e8d9a,0xa533ea17,0x7e244280,0x3729250d, + 0x0b5e05e2,0x4253626f,0x9944caf8,0xd049ad75,0x2baa8661,0x62a7e1ec,0xb9b0497b,0xf0bd2ef6, + 0x4ab702e4,0x03ba6569,0xd8adcdfe,0x91a0aa73,0x6a438167,0x234ee6ea,0xf8594e7d,0xb15429f0, + 0x888c0bee,0xc1816c63,0x1a96c4f4,0x539ba379,0xa878886d,0xe175efe0,0x3a624777,0x736f20fa, + 0xc9650ce8,0x80686b65,0x5b7fc3f2,0x1272a47f,0xe9918f6b,0xa09ce8e6,0x7b8b4071,0x328627fc, + 0x083b044d,0x413663c0,0x9a21cb57,0xd32cacda,0x28cf87ce,0x61c2e043,0xbad548d4,0xf3d82f59, + 0x49d2034b,0x00df64c6,0xdbc8cc51,0x92c5abdc,0x692680c8,0x202be745,0xfb3c4fd2,0xb231285f, + 0x8be90a41,0xc2e46dcc,0x19f3c55b,0x50fea2d6,0xab1d89c2,0xe210ee4f,0x390746d8,0x700a2155, + 0xca000d47,0x830d6aca,0x581ac25d,0x1117a5d0,0xeaf48ec4,0xa3f9e949,0x78ee41de,0x31e32653}, + +{0x00000000,0x1b280d78,0x36501af0,0x2d781788,0x6ca035e0,0x77883898,0x5af02f10,0x41d82268, + 0xd9406bc0,0xc26866b8,0xef107130,0xf4387c48,0xb5e05e20,0xaec85358,0x83b044d0,0x989849a8, + 0xb641ca37,0xad69c74f,0x8011d0c7,0x9b39ddbf,0xdae1ffd7,0xc1c9f2af,0xecb1e527,0xf799e85f, + 0x6f01a1f7,0x7429ac8f,0x5951bb07,0x4279b67f,0x03a19417,0x1889996f,0x35f18ee7,0x2ed9839f, + 0x684289d9,0x736a84a1,0x5e129329,0x453a9e51,0x04e2bc39,0x1fcab141,0x32b2a6c9,0x299aabb1, + 0xb102e219,0xaa2aef61,0x8752f8e9,0x9c7af591,0xdda2d7f9,0xc68ada81,0xebf2cd09,0xf0dac071, + 0xde0343ee,0xc52b4e96,0xe853591e,0xf37b5466,0xb2a3760e,0xa98b7b76,0x84f36cfe,0x9fdb6186, + 0x0743282e,0x1c6b2556,0x311332de,0x2a3b3fa6,0x6be31dce,0x70cb10b6,0x5db3073e,0x469b0a46, + 0xd08513b2,0xcbad1eca,0xe6d50942,0xfdfd043a,0xbc252652,0xa70d2b2a,0x8a753ca2,0x915d31da, + 0x09c57872,0x12ed750a,0x3f956282,0x24bd6ffa,0x65654d92,0x7e4d40ea,0x53355762,0x481d5a1a, + 0x66c4d985,0x7decd4fd,0x5094c375,0x4bbcce0d,0x0a64ec65,0x114ce11d,0x3c34f695,0x271cfbed, + 0xbf84b245,0xa4acbf3d,0x89d4a8b5,0x92fca5cd,0xd32487a5,0xc80c8add,0xe5749d55,0xfe5c902d, + 0xb8c79a6b,0xa3ef9713,0x8e97809b,0x95bf8de3,0xd467af8b,0xcf4fa2f3,0xe237b57b,0xf91fb803, + 0x6187f1ab,0x7aaffcd3,0x57d7eb5b,0x4cffe623,0x0d27c44b,0x160fc933,0x3b77debb,0x205fd3c3, + 0x0e86505c,0x15ae5d24,0x38d64aac,0x23fe47d4,0x622665bc,0x790e68c4,0x54767f4c,0x4f5e7234, + 0xd7c63b9c,0xccee36e4,0xe196216c,0xfabe2c14,0xbb660e7c,0xa04e0304,0x8d36148c,0x961e19f4, + 0xa5cb3ad3,0xbee337ab,0x939b2023,0x88b32d5b,0xc96b0f33,0xd243024b,0xff3b15c3,0xe41318bb, + 0x7c8b5113,0x67a35c6b,0x4adb4be3,0x51f3469b,0x102b64f3,0x0b03698b,0x267b7e03,0x3d53737b, + 0x138af0e4,0x08a2fd9c,0x25daea14,0x3ef2e76c,0x7f2ac504,0x6402c87c,0x497adff4,0x5252d28c, + 0xcaca9b24,0xd1e2965c,0xfc9a81d4,0xe7b28cac,0xa66aaec4,0xbd42a3bc,0x903ab434,0x8b12b94c, + 0xcd89b30a,0xd6a1be72,0xfbd9a9fa,0xe0f1a482,0xa12986ea,0xba018b92,0x97799c1a,0x8c519162, + 0x14c9d8ca,0x0fe1d5b2,0x2299c23a,0x39b1cf42,0x7869ed2a,0x6341e052,0x4e39f7da,0x5511faa2, + 0x7bc8793d,0x60e07445,0x4d9863cd,0x56b06eb5,0x17684cdd,0x0c4041a5,0x2138562d,0x3a105b55, + 0xa28812fd,0xb9a01f85,0x94d8080d,0x8ff00575,0xce28271d,0xd5002a65,0xf8783ded,0xe3503095, + 0x754e2961,0x6e662419,0x431e3391,0x58363ee9,0x19ee1c81,0x02c611f9,0x2fbe0671,0x34960b09, + 0xac0e42a1,0xb7264fd9,0x9a5e5851,0x81765529,0xc0ae7741,0xdb867a39,0xf6fe6db1,0xedd660c9, + 0xc30fe356,0xd827ee2e,0xf55ff9a6,0xee77f4de,0xafafd6b6,0xb487dbce,0x99ffcc46,0x82d7c13e, + 0x1a4f8896,0x016785ee,0x2c1f9266,0x37379f1e,0x76efbd76,0x6dc7b00e,0x40bfa786,0x5b97aafe, + 0x1d0ca0b8,0x0624adc0,0x2b5cba48,0x3074b730,0x71ac9558,0x6a849820,0x47fc8fa8,0x5cd482d0, + 0xc44ccb78,0xdf64c600,0xf21cd188,0xe934dcf0,0xa8ecfe98,0xb3c4f3e0,0x9ebce468,0x8594e910, + 0xab4d6a8f,0xb06567f7,0x9d1d707f,0x86357d07,0xc7ed5f6f,0xdcc55217,0xf1bd459f,0xea9548e7, + 0x720d014f,0x69250c37,0x445d1bbf,0x5f7516c7,0x1ead34af,0x058539d7,0x28fd2e5f,0x33d52327}, + +{0x00000000,0x4f576811,0x9eaed022,0xd1f9b833,0x399cbdf3,0x76cbd5e2,0xa7326dd1,0xe86505c0, + 0x73397be6,0x3c6e13f7,0xed97abc4,0xa2c0c3d5,0x4aa5c615,0x05f2ae04,0xd40b1637,0x9b5c7e26, + 0xe672f7cc,0xa9259fdd,0x78dc27ee,0x378b4fff,0xdfee4a3f,0x90b9222e,0x41409a1d,0x0e17f20c, + 0x954b8c2a,0xda1ce43b,0x0be55c08,0x44b23419,0xacd731d9,0xe38059c8,0x3279e1fb,0x7d2e89ea, + 0xc824f22f,0x87739a3e,0x568a220d,0x19dd4a1c,0xf1b84fdc,0xbeef27cd,0x6f169ffe,0x2041f7ef, + 0xbb1d89c9,0xf44ae1d8,0x25b359eb,0x6ae431fa,0x8281343a,0xcdd65c2b,0x1c2fe418,0x53788c09, + 0x2e5605e3,0x61016df2,0xb0f8d5c1,0xffafbdd0,0x17cab810,0x589dd001,0x89646832,0xc6330023, + 0x5d6f7e05,0x12381614,0xc3c1ae27,0x8c96c636,0x64f3c3f6,0x2ba4abe7,0xfa5d13d4,0xb50a7bc5, + 0x9488f9e9,0xdbdf91f8,0x0a2629cb,0x457141da,0xad14441a,0xe2432c0b,0x33ba9438,0x7cedfc29, + 0xe7b1820f,0xa8e6ea1e,0x791f522d,0x36483a3c,0xde2d3ffc,0x917a57ed,0x4083efde,0x0fd487cf, + 0x72fa0e25,0x3dad6634,0xec54de07,0xa303b616,0x4b66b3d6,0x0431dbc7,0xd5c863f4,0x9a9f0be5, + 0x01c375c3,0x4e941dd2,0x9f6da5e1,0xd03acdf0,0x385fc830,0x7708a021,0xa6f11812,0xe9a67003, + 0x5cac0bc6,0x13fb63d7,0xc202dbe4,0x8d55b3f5,0x6530b635,0x2a67de24,0xfb9e6617,0xb4c90e06, + 0x2f957020,0x60c21831,0xb13ba002,0xfe6cc813,0x1609cdd3,0x595ea5c2,0x88a71df1,0xc7f075e0, + 0xbadefc0a,0xf589941b,0x24702c28,0x6b274439,0x834241f9,0xcc1529e8,0x1dec91db,0x52bbf9ca, + 0xc9e787ec,0x86b0effd,0x574957ce,0x181e3fdf,0xf07b3a1f,0xbf2c520e,0x6ed5ea3d,0x2182822c, + 0x2dd0ee65,0x62878674,0xb37e3e47,0xfc295656,0x144c5396,0x5b1b3b87,0x8ae283b4,0xc5b5eba5, + 0x5ee99583,0x11befd92,0xc04745a1,0x8f102db0,0x67752870,0x28224061,0xf9dbf852,0xb68c9043, + 0xcba219a9,0x84f571b8,0x550cc98b,0x1a5ba19a,0xf23ea45a,0xbd69cc4b,0x6c907478,0x23c71c69, + 0xb89b624f,0xf7cc0a5e,0x2635b26d,0x6962da7c,0x8107dfbc,0xce50b7ad,0x1fa90f9e,0x50fe678f, + 0xe5f41c4a,0xaaa3745b,0x7b5acc68,0x340da479,0xdc68a1b9,0x933fc9a8,0x42c6719b,0x0d91198a, + 0x96cd67ac,0xd99a0fbd,0x0863b78e,0x4734df9f,0xaf51da5f,0xe006b24e,0x31ff0a7d,0x7ea8626c, + 0x0386eb86,0x4cd18397,0x9d283ba4,0xd27f53b5,0x3a1a5675,0x754d3e64,0xa4b48657,0xebe3ee46, + 0x70bf9060,0x3fe8f871,0xee114042,0xa1462853,0x49232d93,0x06744582,0xd78dfdb1,0x98da95a0, + 0xb958178c,0xf60f7f9d,0x27f6c7ae,0x68a1afbf,0x80c4aa7f,0xcf93c26e,0x1e6a7a5d,0x513d124c, + 0xca616c6a,0x8536047b,0x54cfbc48,0x1b98d459,0xf3fdd199,0xbcaab988,0x6d5301bb,0x220469aa, + 0x5f2ae040,0x107d8851,0xc1843062,0x8ed35873,0x66b65db3,0x29e135a2,0xf8188d91,0xb74fe580, + 0x2c139ba6,0x6344f3b7,0xb2bd4b84,0xfdea2395,0x158f2655,0x5ad84e44,0x8b21f677,0xc4769e66, + 0x717ce5a3,0x3e2b8db2,0xefd23581,0xa0855d90,0x48e05850,0x07b73041,0xd64e8872,0x9919e063, + 0x02459e45,0x4d12f654,0x9ceb4e67,0xd3bc2676,0x3bd923b6,0x748e4ba7,0xa577f394,0xea209b85, + 0x970e126f,0xd8597a7e,0x09a0c24d,0x46f7aa5c,0xae92af9c,0xe1c5c78d,0x303c7fbe,0x7f6b17af, + 0xe4376989,0xab600198,0x7a99b9ab,0x35ced1ba,0xddabd47a,0x92fcbc6b,0x43050458,0x0c526c49}, + +{0x00000000,0x5ba1dcca,0xb743b994,0xece2655e,0x6a466e9f,0x31e7b255,0xdd05d70b,0x86a40bc1, + 0xd48cdd3e,0x8f2d01f4,0x63cf64aa,0x386eb860,0xbecab3a1,0xe56b6f6b,0x09890a35,0x5228d6ff, + 0xadd8a7cb,0xf6797b01,0x1a9b1e5f,0x413ac295,0xc79ec954,0x9c3f159e,0x70dd70c0,0x2b7cac0a, + 0x79547af5,0x22f5a63f,0xce17c361,0x95b61fab,0x1312146a,0x48b3c8a0,0xa451adfe,0xfff07134, + 0x5f705221,0x04d18eeb,0xe833ebb5,0xb392377f,0x35363cbe,0x6e97e074,0x8275852a,0xd9d459e0, + 0x8bfc8f1f,0xd05d53d5,0x3cbf368b,0x671eea41,0xe1bae180,0xba1b3d4a,0x56f95814,0x0d5884de, + 0xf2a8f5ea,0xa9092920,0x45eb4c7e,0x1e4a90b4,0x98ee9b75,0xc34f47bf,0x2fad22e1,0x740cfe2b, + 0x262428d4,0x7d85f41e,0x91679140,0xcac64d8a,0x4c62464b,0x17c39a81,0xfb21ffdf,0xa0802315, + 0xbee0a442,0xe5417888,0x09a31dd6,0x5202c11c,0xd4a6cadd,0x8f071617,0x63e57349,0x3844af83, + 0x6a6c797c,0x31cda5b6,0xdd2fc0e8,0x868e1c22,0x002a17e3,0x5b8bcb29,0xb769ae77,0xecc872bd, + 0x13380389,0x4899df43,0xa47bba1d,0xffda66d7,0x797e6d16,0x22dfb1dc,0xce3dd482,0x959c0848, + 0xc7b4deb7,0x9c15027d,0x70f76723,0x2b56bbe9,0xadf2b028,0xf6536ce2,0x1ab109bc,0x4110d576, + 0xe190f663,0xba312aa9,0x56d34ff7,0x0d72933d,0x8bd698fc,0xd0774436,0x3c952168,0x6734fda2, + 0x351c2b5d,0x6ebdf797,0x825f92c9,0xd9fe4e03,0x5f5a45c2,0x04fb9908,0xe819fc56,0xb3b8209c, + 0x4c4851a8,0x17e98d62,0xfb0be83c,0xa0aa34f6,0x260e3f37,0x7dafe3fd,0x914d86a3,0xcaec5a69, + 0x98c48c96,0xc365505c,0x2f873502,0x7426e9c8,0xf282e209,0xa9233ec3,0x45c15b9d,0x1e608757, + 0x79005533,0x22a189f9,0xce43eca7,0x95e2306d,0x13463bac,0x48e7e766,0xa4058238,0xffa45ef2, + 0xad8c880d,0xf62d54c7,0x1acf3199,0x416eed53,0xc7cae692,0x9c6b3a58,0x70895f06,0x2b2883cc, + 0xd4d8f2f8,0x8f792e32,0x639b4b6c,0x383a97a6,0xbe9e9c67,0xe53f40ad,0x09dd25f3,0x527cf939, + 0x00542fc6,0x5bf5f30c,0xb7179652,0xecb64a98,0x6a124159,0x31b39d93,0xdd51f8cd,0x86f02407, + 0x26700712,0x7dd1dbd8,0x9133be86,0xca92624c,0x4c36698d,0x1797b547,0xfb75d019,0xa0d40cd3, + 0xf2fcda2c,0xa95d06e6,0x45bf63b8,0x1e1ebf72,0x98bab4b3,0xc31b6879,0x2ff90d27,0x7458d1ed, + 0x8ba8a0d9,0xd0097c13,0x3ceb194d,0x674ac587,0xe1eece46,0xba4f128c,0x56ad77d2,0x0d0cab18, + 0x5f247de7,0x0485a12d,0xe867c473,0xb3c618b9,0x35621378,0x6ec3cfb2,0x8221aaec,0xd9807626, + 0xc7e0f171,0x9c412dbb,0x70a348e5,0x2b02942f,0xada69fee,0xf6074324,0x1ae5267a,0x4144fab0, + 0x136c2c4f,0x48cdf085,0xa42f95db,0xff8e4911,0x792a42d0,0x228b9e1a,0xce69fb44,0x95c8278e, + 0x6a3856ba,0x31998a70,0xdd7bef2e,0x86da33e4,0x007e3825,0x5bdfe4ef,0xb73d81b1,0xec9c5d7b, + 0xbeb48b84,0xe515574e,0x09f73210,0x5256eeda,0xd4f2e51b,0x8f5339d1,0x63b15c8f,0x38108045, + 0x9890a350,0xc3317f9a,0x2fd31ac4,0x7472c60e,0xf2d6cdcf,0xa9771105,0x4595745b,0x1e34a891, + 0x4c1c7e6e,0x17bda2a4,0xfb5fc7fa,0xa0fe1b30,0x265a10f1,0x7dfbcc3b,0x9119a965,0xcab875af, + 0x3548049b,0x6ee9d851,0x820bbd0f,0xd9aa61c5,0x5f0e6a04,0x04afb6ce,0xe84dd390,0xb3ec0f5a, + 0xe1c4d9a5,0xba65056f,0x56876031,0x0d26bcfb,0x8b82b73a,0xd0236bf0,0x3cc10eae,0x6760d264}}; diff --git a/src/libogg/framing.c b/src/libogg/framing.c new file mode 100644 index 00000000..378698f5 --- /dev/null +++ b/src/libogg/framing.c @@ -0,0 +1,2111 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: code raw packets into framed OggSquish stream and + decode Ogg streams back into raw packets + + note: The CRC code is directly derived from public domain code by + Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html + for details. + + ********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include +#include +#include +#include "ogg/ogg.h" + +#include + +/* A complete description of Ogg framing exists in docs/framing.html */ + +int ogg_page_version(const ogg_page *og){ + return((int)(og->header[4])); +} + +int ogg_page_continued(const ogg_page *og){ + return((int)(og->header[5]&0x01)); +} + +int ogg_page_bos(const ogg_page *og){ + return((int)(og->header[5]&0x02)); +} + +int ogg_page_eos(const ogg_page *og){ + return((int)(og->header[5]&0x04)); +} + +ogg_int64_t ogg_page_granulepos(const ogg_page *og){ + unsigned char *page=og->header; + ogg_uint64_t granulepos=page[13]&(0xff); + granulepos= (granulepos<<8)|(page[12]&0xff); + granulepos= (granulepos<<8)|(page[11]&0xff); + granulepos= (granulepos<<8)|(page[10]&0xff); + granulepos= (granulepos<<8)|(page[9]&0xff); + granulepos= (granulepos<<8)|(page[8]&0xff); + granulepos= (granulepos<<8)|(page[7]&0xff); + granulepos= (granulepos<<8)|(page[6]&0xff); + return((ogg_int64_t)granulepos); +} + +int ogg_page_serialno(const ogg_page *og){ + return((int)((ogg_uint32_t)og->header[14]) | + ((ogg_uint32_t)og->header[15]<<8) | + ((ogg_uint32_t)og->header[16]<<16) | + ((ogg_uint32_t)og->header[17]<<24)); +} + +long ogg_page_pageno(const ogg_page *og){ + return((long)((ogg_uint32_t)og->header[18]) | + ((ogg_uint32_t)og->header[19]<<8) | + ((ogg_uint32_t)og->header[20]<<16) | + ((ogg_uint32_t)og->header[21]<<24)); +} + + + +/* returns the number of packets that are completed on this page (if + the leading packet is begun on a previous page, but ends on this + page, it's counted */ + +/* NOTE: + If a page consists of a packet begun on a previous page, and a new + packet begun (but not completed) on this page, the return will be: + ogg_page_packets(page) ==1, + ogg_page_continued(page) !=0 + + If a page happens to be a single packet that was begun on a + previous page, and spans to the next page (in the case of a three or + more page packet), the return will be: + ogg_page_packets(page) ==0, + ogg_page_continued(page) !=0 +*/ + +int ogg_page_packets(const ogg_page *og){ + int i,n=og->header[26],count=0; + for(i=0;iheader[27+i]<255)count++; + return(count); +} + + +#if 0 +/* helper to initialize lookup for direct-table CRC (illustrative; we + use the static init in crctable.h) */ + +static void _ogg_crc_init(){ + int i, j; + ogg_uint32_t polynomial, crc; + polynomial = 0x04c11db7; /* The same as the ethernet generator + polynomial, although we use an + unreflected alg and an init/final + of 0, not 0xffffffff */ + for (i = 0; i <= 0xFF; i++){ + crc = i << 24; + + for (j = 0; j < 8; j++) + crc = (crc << 1) ^ (crc & (1 << 31) ? polynomial : 0); + + crc_lookup[0][i] = crc; + } + + for (i = 0; i <= 0xFF; i++) + for (j = 1; j < 8; j++) + crc_lookup[j][i] = crc_lookup[0][(crc_lookup[j - 1][i] >> 24) & 0xFF] ^ (crc_lookup[j - 1][i] << 8); +} +#endif + +#include "crctable.h" + +/* init the encode/decode logical stream state */ + +int ogg_stream_init(ogg_stream_state *os,int serialno){ + if(os){ + memset(os,0,sizeof(*os)); + os->body_storage=16*1024; + os->lacing_storage=1024; + + os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); + os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); + os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); + + if(!os->body_data || !os->lacing_vals || !os->granule_vals){ + ogg_stream_clear(os); + return -1; + } + + os->serialno=serialno; + + return(0); + } + return(-1); +} + +/* async/delayed error detection for the ogg_stream_state */ +int ogg_stream_check(ogg_stream_state *os){ + if(!os || !os->body_data) return -1; + return 0; +} + +/* _clear does not free os, only the non-flat storage within */ +int ogg_stream_clear(ogg_stream_state *os){ + if(os){ + if(os->body_data)_ogg_free(os->body_data); + if(os->lacing_vals)_ogg_free(os->lacing_vals); + if(os->granule_vals)_ogg_free(os->granule_vals); + + memset(os,0,sizeof(*os)); + } + return(0); +} + +int ogg_stream_destroy(ogg_stream_state *os){ + if(os){ + ogg_stream_clear(os); + _ogg_free(os); + } + return(0); +} + +/* Helpers for ogg_stream_encode; this keeps the structure and + what's happening fairly clear */ + +static int _os_body_expand(ogg_stream_state *os,long needed){ + if(os->body_storage-needed<=os->body_fill){ + long body_storage; + void *ret; + if(os->body_storage>LONG_MAX-needed){ + ogg_stream_clear(os); + return -1; + } + body_storage=os->body_storage+needed; + if(body_storagebody_data,body_storage*sizeof(*os->body_data)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->body_storage=body_storage; + os->body_data=ret; + } + return 0; +} + +static int _os_lacing_expand(ogg_stream_state *os,long needed){ + if(os->lacing_storage-needed<=os->lacing_fill){ + long lacing_storage; + void *ret; + if(os->lacing_storage>LONG_MAX-needed){ + ogg_stream_clear(os); + return -1; + } + lacing_storage=os->lacing_storage+needed; + if(lacing_storagelacing_vals,lacing_storage*sizeof(*os->lacing_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->lacing_vals=ret; + ret=_ogg_realloc(os->granule_vals,lacing_storage* + sizeof(*os->granule_vals)); + if(!ret){ + ogg_stream_clear(os); + return -1; + } + os->granule_vals=ret; + os->lacing_storage=lacing_storage; + } + return 0; +} + +/* checksum the page */ +/* Direct table CRC; note that this will be faster in the future if we + perform the checksum simultaneously with other copies */ + +static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int size){ + while (size>=8){ + crc^=((ogg_uint32_t)buffer[0]<<24)|((ogg_uint32_t)buffer[1]<<16)|((ogg_uint32_t)buffer[2]<<8)|((ogg_uint32_t)buffer[3]); + + crc=crc_lookup[7][ crc>>24 ]^crc_lookup[6][(crc>>16)&0xFF]^ + crc_lookup[5][(crc>> 8)&0xFF]^crc_lookup[4][ crc &0xFF]^ + crc_lookup[3][buffer[4] ]^crc_lookup[2][buffer[5] ]^ + crc_lookup[1][buffer[6] ]^crc_lookup[0][buffer[7] ]; + + buffer+=8; + size-=8; + } + + while (size--) + crc=(crc<<8)^crc_lookup[0][((crc >> 24)&0xff)^*buffer++]; + return crc; +} + +void ogg_page_checksum_set(ogg_page *og){ + if(og){ + ogg_uint32_t crc_reg=0; + + /* safety; needed for API behavior, but not framing code */ + og->header[22]=0; + og->header[23]=0; + og->header[24]=0; + og->header[25]=0; + + crc_reg=_os_update_crc(crc_reg,og->header,og->header_len); + crc_reg=_os_update_crc(crc_reg,og->body,og->body_len); + + og->header[22]=(unsigned char)(crc_reg&0xff); + og->header[23]=(unsigned char)((crc_reg>>8)&0xff); + og->header[24]=(unsigned char)((crc_reg>>16)&0xff); + og->header[25]=(unsigned char)((crc_reg>>24)&0xff); + } +} + +/* submit data to the internal buffer of the framing engine */ +int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, + long e_o_s, ogg_int64_t granulepos){ + + long bytes = 0, lacing_vals; + int i; + + if(ogg_stream_check(os)) return -1; + if(!iov) return 0; + + for (i = 0; i < count; ++i){ + if(iov[i].iov_len>LONG_MAX) return -1; + if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1; + bytes += (long)iov[i].iov_len; + } + lacing_vals=bytes/255+1; + + if(os->body_returned){ + /* advance packet data according to the body_returned pointer. We + had to keep it around to return a pointer into the buffer last + call */ + + os->body_fill-=os->body_returned; + if(os->body_fill) + memmove(os->body_data,os->body_data+os->body_returned, + os->body_fill); + os->body_returned=0; + } + + /* make sure we have the buffer storage */ + if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) + return -1; + + /* Copy in the submitted packet. Yes, the copy is a waste; this is + the liability of overly clean abstraction for the time being. It + will actually be fairly easy to eliminate the extra copy in the + future */ + + for (i = 0; i < count; ++i) { + memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len); + os->body_fill += (int)iov[i].iov_len; + } + + /* Store lacing vals for this packet */ + for(i=0;ilacing_vals[os->lacing_fill+i]=255; + os->granule_vals[os->lacing_fill+i]=os->granulepos; + } + os->lacing_vals[os->lacing_fill+i]=bytes%255; + os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos; + + /* flag the first segment as the beginning of the packet */ + os->lacing_vals[os->lacing_fill]|= 0x100; + + os->lacing_fill+=lacing_vals; + + /* for the sake of completeness */ + os->packetno++; + + if(e_o_s)os->e_o_s=1; + + return(0); +} + +int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ + ogg_iovec_t iov; + iov.iov_base = op->packet; + iov.iov_len = op->bytes; + return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos); +} + +/* Conditionally flush a page; force==0 will only flush nominal-size + pages, force==1 forces us to flush a page regardless of page size + so long as there's any data available at all. */ +static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ + int i; + int vals=0; + int maxvals=(os->lacing_fill>255?255:os->lacing_fill); + int bytes=0; + long acc=0; + ogg_int64_t granule_pos=-1; + + if(ogg_stream_check(os)) return(0); + if(maxvals==0) return(0); + + /* construct a page */ + /* decide how many segments to include */ + + /* If this is the initial header case, the first page must only include + the initial header packet */ + if(os->b_o_s==0){ /* 'initial header page' case */ + granule_pos=0; + for(vals=0;valslacing_vals[vals]&0x0ff)<255){ + vals++; + break; + } + } + }else{ + + /* The extra packets_done, packet_just_done logic here attempts to do two things: + 1) Don't unnecessarily span pages. + 2) Unless necessary, don't flush pages if there are less than four packets on + them; this expands page size to reduce unnecessary overhead if incoming packets + are large. + These are not necessary behaviors, just 'always better than naive flushing' + without requiring an application to explicitly request a specific optimized + behavior. We'll want an explicit behavior setup pathway eventually as well. */ + + int packets_done=0; + int packet_just_done=0; + for(vals=0;valsnfill && packet_just_done>=4){ + force=1; + break; + } + acc+=os->lacing_vals[vals]&0x0ff; + if((os->lacing_vals[vals]&0xff)<255){ + granule_pos=os->granule_vals[vals]; + packet_just_done=++packets_done; + }else + packet_just_done=0; + } + if(vals==255)force=1; + } + + if(!force) return(0); + + /* construct the header in temp storage */ + memcpy(os->header,"OggS",4); + + /* stream structure version */ + os->header[4]=0x00; + + /* continued packet flag? */ + os->header[5]=0x00; + if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; + /* first page flag? */ + if(os->b_o_s==0)os->header[5]|=0x02; + /* last page flag? */ + if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; + os->b_o_s=1; + + /* 64 bits of PCM position */ + for(i=6;i<14;i++){ + os->header[i]=(unsigned char)(granule_pos&0xff); + granule_pos>>=8; + } + + /* 32 bits of stream serial number */ + { + long serialno=os->serialno; + for(i=14;i<18;i++){ + os->header[i]=(unsigned char)(serialno&0xff); + serialno>>=8; + } + } + + /* 32 bits of page counter (we have both counter and page header + because this val can roll over) */ + if(os->pageno==-1)os->pageno=0; /* because someone called + stream_reset; this would be a + strange thing to do in an + encode stream, but it has + plausible uses */ + { + long pageno=os->pageno++; + for(i=18;i<22;i++){ + os->header[i]=(unsigned char)(pageno&0xff); + pageno>>=8; + } + } + + /* zero for computation; filled in later */ + os->header[22]=0; + os->header[23]=0; + os->header[24]=0; + os->header[25]=0; + + /* segment table */ + os->header[26]=(unsigned char)(vals&0xff); + for(i=0;iheader[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); + + /* set pointers in the ogg_page struct */ + og->header=os->header; + og->header_len=os->header_fill=vals+27; + og->body=os->body_data+os->body_returned; + og->body_len=bytes; + + /* advance the lacing data and set the body_returned pointer */ + + os->lacing_fill-=vals; + memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); + os->body_returned+=bytes; + + /* calculate the checksum */ + + ogg_page_checksum_set(og); + + /* done */ + return(1); +} + +/* This will flush remaining packets into a page (returning nonzero), + even if there is not enough data to trigger a flush normally + (undersized page). If there are no packets or partial packets to + flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will + try to flush a normal sized page like ogg_stream_pageout; a call to + ogg_stream_flush does not guarantee that all packets have flushed. + Only a return value of 0 from ogg_stream_flush indicates all packet + data is flushed into pages. + + since ogg_stream_flush will flush the last page in a stream even if + it's undersized, you almost certainly want to use ogg_stream_pageout + (and *not* ogg_stream_flush) unless you specifically need to flush + a page regardless of size in the middle of a stream. */ + +int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ + return ogg_stream_flush_i(os,og,1,4096); +} + +/* Like the above, but an argument is provided to adjust the nominal + page size for applications which are smart enough to provide their + own delay based flushing */ + +int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ + return ogg_stream_flush_i(os,og,1,nfill); +} + +/* This constructs pages from buffered packet segments. The pointers +returned are to static buffers; do not free. The returned buffers are +good only until the next call (using the same ogg_stream_state) */ + +int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,4096)); +} + +/* Like the above, but an argument is provided to adjust the nominal +page size for applications which are smart enough to provide their +own delay based flushing */ + +int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ + int force=0; + if(ogg_stream_check(os)) return 0; + + if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ + (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ + force=1; + + return(ogg_stream_flush_i(os,og,force,nfill)); +} + +int ogg_stream_eos(ogg_stream_state *os){ + if(ogg_stream_check(os)) return 1; + return os->e_o_s; +} + +/* DECODING PRIMITIVES: packet streaming layer **********************/ + +/* This has two layers to place more of the multi-serialno and paging + control in the application's hands. First, we expose a data buffer + using ogg_sync_buffer(). The app either copies into the + buffer, or passes it directly to read(), etc. We then call + ogg_sync_wrote() to tell how many bytes we just added. + + Pages are returned (pointers into the buffer in ogg_sync_state) + by ogg_sync_pageout(). The page is then submitted to + ogg_stream_pagein() along with the appropriate + ogg_stream_state* (ie, matching serialno). We then get raw + packets out calling ogg_stream_packetout() with a + ogg_stream_state. */ + +/* initialize the struct to a known state */ +int ogg_sync_init(ogg_sync_state *oy){ + if(oy){ + oy->storage = -1; /* used as a readiness flag */ + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +/* clear non-flat storage within */ +int ogg_sync_clear(ogg_sync_state *oy){ + if(oy){ + if(oy->data)_ogg_free(oy->data); + memset(oy,0,sizeof(*oy)); + } + return(0); +} + +int ogg_sync_destroy(ogg_sync_state *oy){ + if(oy){ + ogg_sync_clear(oy); + _ogg_free(oy); + } + return(0); +} + +int ogg_sync_check(ogg_sync_state *oy){ + if(oy->storage<0) return -1; + return 0; +} + +char *ogg_sync_buffer(ogg_sync_state *oy, long size){ + if(ogg_sync_check(oy)) return NULL; + + /* first, clear out any space that has been previously returned */ + if(oy->returned){ + oy->fill-=oy->returned; + if(oy->fill>0) + memmove(oy->data,oy->data+oy->returned,oy->fill); + oy->returned=0; + } + + if(size>oy->storage-oy->fill){ + /* We need to extend the internal buffer */ + long newsize=size+oy->fill+4096; /* an extra page to be nice */ + void *ret; + + if(oy->data) + ret=_ogg_realloc(oy->data,newsize); + else + ret=_ogg_malloc(newsize); + if(!ret){ + ogg_sync_clear(oy); + return NULL; + } + oy->data=ret; + oy->storage=newsize; + } + + /* expose a segment at least as large as requested at the fill mark */ + return((char *)oy->data+oy->fill); +} + +int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ + if(ogg_sync_check(oy))return -1; + if(oy->fill+bytes>oy->storage)return -1; + oy->fill+=bytes; + return(0); +} + +/* sync the stream. This is meant to be useful for finding page + boundaries. + + return values for this: + -n) skipped n bytes + 0) page not ready; more data (no bytes skipped) + n) page synced at current location; page length n bytes + +*/ + +long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ + unsigned char *page=oy->data+oy->returned; + unsigned char *next; + long bytes=oy->fill-oy->returned; + + if(ogg_sync_check(oy))return 0; + + if(oy->headerbytes==0){ + int headerbytes,i; + if(bytes<27)return(0); /* not enough for a header */ + + /* verify capture pattern */ + if(memcmp(page,"OggS",4))goto sync_fail; + + headerbytes=page[26]+27; + if(bytesbodybytes+=page[27+i]; + oy->headerbytes=headerbytes; + } + + if(oy->bodybytes+oy->headerbytes>bytes)return(0); + + /* The whole test page is buffered. Verify the checksum */ + { + /* Grab the checksum bytes, set the header field to zero */ + char chksum[4]; + ogg_page log; + + memcpy(chksum,page+22,4); + memset(page+22,0,4); + + /* set up a temp page struct and recompute the checksum */ + log.header=page; + log.header_len=oy->headerbytes; + log.body=page+oy->headerbytes; + log.body_len=oy->bodybytes; + ogg_page_checksum_set(&log); + + /* Compare */ + if(memcmp(chksum,page+22,4)){ + /* D'oh. Mismatch! Corrupt page (or miscapture and not a page + at all) */ + /* replace the computed checksum with the one actually read in */ + memcpy(page+22,chksum,4); + +#ifndef DISABLE_CRC + /* Bad checksum. Lose sync */ + goto sync_fail; +#endif + } + } + + /* yes, have a whole page all ready to go */ + { + if(og){ + og->header=page; + og->header_len=oy->headerbytes; + og->body=page+oy->headerbytes; + og->body_len=oy->bodybytes; + } + + oy->unsynced=0; + oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); + oy->headerbytes=0; + oy->bodybytes=0; + return(bytes); + } + + sync_fail: + + oy->headerbytes=0; + oy->bodybytes=0; + + /* search for possible capture */ + next=memchr(page+1,'O',bytes-1); + if(!next) + next=oy->data+oy->fill; + + oy->returned=(int)(next-oy->data); + return((long)-(next-page)); +} + +/* sync the stream and get a page. Keep trying until we find a page. + Suppress 'sync errors' after reporting the first. + + return values: + -1) recapture (hole in data) + 0) need more data + 1) page returned + + Returns pointers into buffered data; invalidated by next call to + _stream, _clear, _init, or _buffer */ + +int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ + + if(ogg_sync_check(oy))return 0; + + /* all we need to do is verify a page at the head of the stream + buffer. If it doesn't verify, we look for the next potential + frame */ + + for(;;){ + long ret=ogg_sync_pageseek(oy,og); + if(ret>0){ + /* have a page */ + return(1); + } + if(ret==0){ + /* need more data */ + return(0); + } + + /* head did not start a synced page... skipped some bytes */ + if(!oy->unsynced){ + oy->unsynced=1; + return(-1); + } + + /* loop. keep looking */ + + } +} + +/* add the incoming page to the stream state; we decompose the page + into packet segments here as well. */ + +int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ + unsigned char *header=og->header; + unsigned char *body=og->body; + long bodysize=og->body_len; + int segptr=0; + + int version=ogg_page_version(og); + int continued=ogg_page_continued(og); + int bos=ogg_page_bos(og); + int eos=ogg_page_eos(og); + ogg_int64_t granulepos=ogg_page_granulepos(og); + int serialno=ogg_page_serialno(og); + long pageno=ogg_page_pageno(og); + int segments=header[26]; + + if(ogg_stream_check(os)) return -1; + + /* clean up 'returned data' */ + { + long lr=os->lacing_returned; + long br=os->body_returned; + + /* body data */ + if(br){ + os->body_fill-=br; + if(os->body_fill) + memmove(os->body_data,os->body_data+br,os->body_fill); + os->body_returned=0; + } + + if(lr){ + /* segment table */ + if(os->lacing_fill-lr){ + memmove(os->lacing_vals,os->lacing_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); + memmove(os->granule_vals,os->granule_vals+lr, + (os->lacing_fill-lr)*sizeof(*os->granule_vals)); + } + os->lacing_fill-=lr; + os->lacing_packet-=lr; + os->lacing_returned=0; + } + } + + /* check the serial number */ + if(serialno!=os->serialno)return(-1); + if(version>0)return(-1); + + if(_os_lacing_expand(os,segments+1)) return -1; + + /* are we in sequence? */ + if(pageno!=os->pageno){ + int i; + + /* unroll previous partial packet (if any) */ + for(i=os->lacing_packet;ilacing_fill;i++) + os->body_fill-=os->lacing_vals[i]&0xff; + os->lacing_fill=os->lacing_packet; + + /* make a note of dropped data in segment table */ + if(os->pageno!=-1){ + os->lacing_vals[os->lacing_fill++]=0x400; + os->lacing_packet++; + } + } + + /* are we a 'continued packet' page? If so, we may need to skip + some segments */ + if(continued){ + if(os->lacing_fill<1 || + (os->lacing_vals[os->lacing_fill-1]&0xff)<255 || + os->lacing_vals[os->lacing_fill-1]==0x400){ + bos=0; + for(;segptrbody_data+os->body_fill,body,bodysize); + os->body_fill+=bodysize; + } + + { + int saved=-1; + while(segptrlacing_vals[os->lacing_fill]=val; + os->granule_vals[os->lacing_fill]=-1; + + if(bos){ + os->lacing_vals[os->lacing_fill]|=0x100; + bos=0; + } + + if(val<255)saved=os->lacing_fill; + + os->lacing_fill++; + segptr++; + + if(val<255)os->lacing_packet=os->lacing_fill; + } + + /* set the granulepos on the last granuleval of the last full packet */ + if(saved!=-1){ + os->granule_vals[saved]=granulepos; + } + + } + + if(eos){ + os->e_o_s=1; + if(os->lacing_fill>0) + os->lacing_vals[os->lacing_fill-1]|=0x200; + } + + os->pageno=pageno+1; + + return(0); +} + +/* clear things to an initial state. Good to call, eg, before seeking */ +int ogg_sync_reset(ogg_sync_state *oy){ + if(ogg_sync_check(oy))return -1; + + oy->fill=0; + oy->returned=0; + oy->unsynced=0; + oy->headerbytes=0; + oy->bodybytes=0; + return(0); +} + +int ogg_stream_reset(ogg_stream_state *os){ + if(ogg_stream_check(os)) return -1; + + os->body_fill=0; + os->body_returned=0; + + os->lacing_fill=0; + os->lacing_packet=0; + os->lacing_returned=0; + + os->header_fill=0; + + os->e_o_s=0; + os->b_o_s=0; + os->pageno=-1; + os->packetno=0; + os->granulepos=0; + + return(0); +} + +int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ + if(ogg_stream_check(os)) return -1; + ogg_stream_reset(os); + os->serialno=serialno; + return(0); +} + +static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ + + /* The last part of decode. We have the stream broken into packet + segments. Now we need to group them into packets (or return the + out of sync markers) */ + + int ptr=os->lacing_returned; + + if(os->lacing_packet<=ptr)return(0); + + if(os->lacing_vals[ptr]&0x400){ + /* we need to tell the codec there's a gap; it might need to + handle previous packet dependencies. */ + os->lacing_returned++; + os->packetno++; + return(-1); + } + + if(!op && !adv)return(1); /* just using peek as an inexpensive way + to ask if there's a whole packet + waiting */ + + /* Gather the whole packet. We'll have no holes or a partial packet */ + { + int size=os->lacing_vals[ptr]&0xff; + long bytes=size; + int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ + int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ + + while(size==255){ + int val=os->lacing_vals[++ptr]; + size=val&0xff; + if(val&0x200)eos=0x200; + bytes+=size; + } + + if(op){ + op->e_o_s=eos; + op->b_o_s=bos; + op->packet=os->body_data+os->body_returned; + op->packetno=os->packetno; + op->granulepos=os->granule_vals[ptr]; + op->bytes=bytes; + } + + if(adv){ + os->body_returned+=bytes; + os->lacing_returned=ptr+1; + os->packetno++; + } + } + return(1); +} + +int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,1); +} + +int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ + if(ogg_stream_check(os)) return 0; + return _packetout(os,op,0); +} + +void ogg_packet_clear(ogg_packet *op) { + _ogg_free(op->packet); + memset(op, 0, sizeof(*op)); +} + +#ifdef _V_SELFTEST +#include + +ogg_stream_state os_en, os_de; +ogg_sync_state oy; + +void checkpacket(ogg_packet *op,long len, int no, long pos){ + long j; + static int sequence=0; + static int lastno=0; + + if(op->bytes!=len){ + fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len); + exit(1); + } + if(op->granulepos!=pos){ + fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos); + exit(1); + } + + /* packet number just follows sequence/gap; adjust the input number + for that */ + if(no==0){ + sequence=0; + }else{ + sequence++; + if(no>lastno+1) + sequence++; + } + lastno=no; + if(op->packetno!=sequence){ + fprintf(stderr,"incorrect packet sequence %ld != %d\n", + (long)(op->packetno),sequence); + exit(1); + } + + /* Test data */ + for(j=0;jbytes;j++) + if(op->packet[j]!=((j+no)&0xff)){ + fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", + j,op->packet[j],(j+no)&0xff); + exit(1); + } +} + +void check_page(unsigned char *data,const int *header,ogg_page *og){ + long j; + /* Test data */ + for(j=0;jbody_len;j++) + if(og->body[j]!=data[j]){ + fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", + j,data[j],og->body[j]); + exit(1); + } + + /* Test header */ + for(j=0;jheader_len;j++){ + if(og->header[j]!=header[j]){ + fprintf(stderr,"header content mismatch at pos %ld:\n",j); + for(j=0;jheader[j]); + fprintf(stderr,"\n"); + exit(1); + } + } + if(og->header_len!=header[26]+27){ + fprintf(stderr,"header length incorrect! (%ld!=%d)\n", + og->header_len,header[26]+27); + exit(1); + } +} + +void print_header(ogg_page *og){ + int j; + fprintf(stderr,"\nHEADER:\n"); + fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", + og->header[0],og->header[1],og->header[2],og->header[3], + (int)og->header[4],(int)og->header[5]); + + fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", + (og->header[9]<<24)|(og->header[8]<<16)| + (og->header[7]<<8)|og->header[6], + (og->header[17]<<24)|(og->header[16]<<16)| + (og->header[15]<<8)|og->header[14], + ((long)(og->header[21])<<24)|(og->header[20]<<16)| + (og->header[19]<<8)|og->header[18]); + + fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", + (int)og->header[22],(int)og->header[23], + (int)og->header[24],(int)og->header[25], + (int)og->header[26]); + + for(j=27;jheader_len;j++) + fprintf(stderr,"%d ",(int)og->header[j]); + fprintf(stderr,")\n\n"); +} + +void copy_page(ogg_page *og){ + unsigned char *temp=_ogg_malloc(og->header_len); + memcpy(temp,og->header,og->header_len); + og->header=temp; + + temp=_ogg_malloc(og->body_len); + memcpy(temp,og->body,og->body_len); + og->body=temp; +} + +void free_page(ogg_page *og){ + _ogg_free (og->header); + _ogg_free (og->body); +} + +void error(void){ + fprintf(stderr,"error!\n"); + exit(1); +} + +/* 17 only */ +const int head1_0[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x15,0xed,0xec,0x91, + 1, + 17}; + +/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ +const int head1_1[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x59,0x10,0x6c,0x2c, + 1, + 17}; +const int head2_1[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x89,0x33,0x85,0xce, + 13, + 254,255,0,255,1,255,245,255,255,0, + 255,255,90}; + +/* nil packets; beginning,middle,end */ +const int head1_2[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; +const int head2_2[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x5c,0x3f,0x66,0xcb, + 17, + 17,254,255,0,0,255,1,0,255,245,255,255,0, + 255,255,90,0}; + +/* large initial packet */ +const int head1_3[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0x01,0x27,0x31,0xaa, + 18, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10}; + +const int head2_3[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x7f,0x4e,0x8a,0xd2, + 4, + 255,4,255,0}; + + +/* continuing packet test */ +const int head1_4[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x00, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xf8,0x3c,0x19,0x79, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head3_4[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x38,0xe6,0xb6,0x28, + 6, + 255,220,255,4,255,0}; + + +/* spill expansion test */ +const int head1_4b[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_4b[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xce,0x8f,0x17,0x1a, + 23, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0}; + + +const int head3_4b[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x9b,0xb2,0x50,0xa1, + 1, + 0}; + +/* page with the 255 segment limit */ +const int head1_5[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_5[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0xed,0x2a,0x2e,0xa7, + 255, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10}; + +const int head3_5[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x04, + 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0x6c,0x3b,0x82,0x3d, + 1, + 50}; + + +/* packet that overspans over an entire page */ +const int head1_6[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_6[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_6[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x01, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xf4,0x87,0xba,0xf3, + 255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255}; + +const int head4_6[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,3,0,0,0, + 0xf7,0x2f,0x6c,0x60, + 5, + 254,255,4,255,0}; + +/* packet that overspans over an entire page */ +const int head1_7[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x02, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,0,0,0,0, + 0xff,0x7b,0x23,0x17, + 1, + 0}; + +const int head2_7[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x00, + 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,1,0,0,0, + 0x68,0x22,0x7c,0x3d, + 255, + 100, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255,255,255, + 255,255,255,255,255,255}; + +const int head3_7[] PROGMEM = {0x4f,0x67,0x67,0x53,0,0x05, + 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, + 0x01,0x02,0x03,0x04,2,0,0,0, + 0xd4,0xe0,0x60,0xe5, + 1, + 0}; + +int compare_packet(const ogg_packet *op1, const ogg_packet *op2){ + if(op1->packet!=op2->packet){ + fprintf(stderr,"op1->packet != op2->packet\n"); + return(1); + } + if(op1->bytes!=op2->bytes){ + fprintf(stderr,"op1->bytes != op2->bytes\n"); + return(1); + } + if(op1->b_o_s!=op2->b_o_s){ + fprintf(stderr,"op1->b_o_s != op2->b_o_s\n"); + return(1); + } + if(op1->e_o_s!=op2->e_o_s){ + fprintf(stderr,"op1->e_o_s != op2->e_o_s\n"); + return(1); + } + if(op1->granulepos!=op2->granulepos){ + fprintf(stderr,"op1->granulepos != op2->granulepos\n"); + return(1); + } + if(op1->packetno!=op2->packetno){ + fprintf(stderr,"op1->packetno != op2->packetno\n"); + return(1); + } + return(0); +} + +void test_pack(const int *pl, const int **headers, int byteskip, + int pageskip, int packetskip){ + unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ + long inptr=0; + long outptr=0; + long deptr=0; + long depacket=0; + long granule_pos=7,pageno=0; + int i,j,packets,pageout=pageskip; + int eosflag=0; + int bosflag=0; + + int byteskipcount=0; + + ogg_stream_reset(&os_en); + ogg_stream_reset(&os_de); + ogg_sync_reset(&oy); + + for(packets=0;packetsbyteskip){ + memcpy(next,og.header,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + byteskipcount+=og.body_len; + if(byteskipcount>byteskip){ + memcpy(next,og.body,byteskipcount-byteskip); + next+=byteskipcount-byteskip; + byteskipcount=byteskip; + } + + ogg_sync_wrote(&oy,next-buf); + + while(1){ + int ret=ogg_sync_pageout(&oy,&og_de); + if(ret==0)break; + if(ret<0)continue; + /* got a page. Happy happy. Verify that it's good. */ + + fprintf(stderr,"(%d), ",pageout); + + check_page(data+deptr,headers[pageout],&og_de); + deptr+=og_de.body_len; + pageout++; + + /* submit it to deconstitution */ + ogg_stream_pagein(&os_de,&og_de); + + /* packets out? */ + while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ + ogg_stream_packetpeek(&os_de,NULL); + ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ + + /* verify peek and out match */ + if(compare_packet(&op_de,&op_de2)){ + fprintf(stderr,"packetout != packetpeek! pos=%ld\n", + depacket); + exit(1); + } + + /* verify the packet! */ + /* check data */ + if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ + fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", + depacket); + exit(1); + } + /* check bos flag */ + if(bosflag==0 && op_de.b_o_s==0){ + fprintf(stderr,"b_o_s flag not set on packet!\n"); + exit(1); + } + if(bosflag && op_de.b_o_s){ + fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); + exit(1); + } + bosflag=1; + depacket+=op_de.bytes; + + /* check eos flag */ + if(eosflag){ + fprintf(stderr,"Multiple decoded packets with eos flag!\n"); + exit(1); + } + + if(op_de.e_o_s)eosflag=1; + + /* check granulepos flag */ + if(op_de.granulepos!=-1){ + fprintf(stderr," granule:%ld ",(long)op_de.granulepos); + } + } + } + } + } + } + } + _ogg_free(data); + if(headers[pageno]!=NULL){ + fprintf(stderr,"did not write last page!\n"); + exit(1); + } + if(headers[pageout]!=NULL){ + fprintf(stderr,"did not decode last page!\n"); + exit(1); + } + if(inptr!=outptr){ + fprintf(stderr,"encoded page data incomplete!\n"); + exit(1); + } + if(inptr!=deptr){ + fprintf(stderr,"decoded page data incomplete!\n"); + exit(1); + } + if(inptr!=depacket){ + fprintf(stderr,"decoded packet data incomplete!\n"); + exit(1); + } + if(!eosflag){ + fprintf(stderr,"Never got a packet with EOS set!\n"); + exit(1); + } + fprintf(stderr,"ok.\n"); +} + +int main(void){ + + ogg_stream_init(&os_en,0x04030201); + ogg_stream_init(&os_de,0x04030201); + ogg_sync_init(&oy); + + /* Exercise each code path in the framing code. Also verify that + the checksums are working. */ + + { + /* 17 only */ + const int packets[]={17, -1}; + const int *headret[]={head1_0,NULL}; + + fprintf(stderr,"testing single page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ + const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; + const int *headret[]={head1_1,head2_1,NULL}; + + fprintf(stderr,"testing basic page encoding... "); + test_pack(packets,headret,0,0,0); + } + + { + /* nil packets; beginning,middle,end */ + const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; + const int *headret[]={head1_2,head2_2,NULL}; + + fprintf(stderr,"testing basic nil packets... "); + test_pack(packets,headret,0,0,0); + } + + { + /* large initial packet */ + const int packets[]={4345,259,255,-1}; + const int *headret[]={head1_3,head2_3,NULL}; + + fprintf(stderr,"testing initial-packet lacing > 4k... "); + test_pack(packets,headret,0,0,0); + } + + { + /* continuing packet test; with page spill expansion, we have to + overflow the lacing table. */ + const int packets[]={0,65500,259,255,-1}; + const int *headret[]={head1_4,head2_4,head3_4,NULL}; + + fprintf(stderr,"testing single packet page span... "); + test_pack(packets,headret,0,0,0); + } + + { + /* spill expand packet test */ + const int packets[]={0,4345,259,255,0,0,-1}; + const int *headret[]={head1_4b,head2_4b,head3_4b,NULL}; + + fprintf(stderr,"testing page spill expansion... "); + test_pack(packets,headret,0,0,0); + } + + /* page with the 255 segment limit */ + { + + const int packets[] PROGMEM ={0,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,50,-1}; + const int *headret[] PROGMEM ={head1_5,head2_5,head3_5,NULL}; + + fprintf(stderr,"testing max packet segments... "); + test_pack(packets,headret,0,0,0); + } + + { + /* packet that overspans over an entire page */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing very large packets... "); + test_pack(packets,headret,0,0,0); + } + +#ifndef DISABLE_CRC + { + /* test for the libogg 1.1.1 resync in large continuation bug + found by Josh Coalson) */ + const int packets[]={0,100,130049,259,255,-1}; + const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; + + fprintf(stderr,"testing continuation resync in very large packets... "); + test_pack(packets,headret,100,2,3); + } +#else + fprintf(stderr,"Skipping continuation resync test due to --disable-crc\n"); +#endif + + { + /* term only page. why not? */ + const int packets[]={0,100,64770,-1}; + const int *headret[]={head1_7,head2_7,head3_7,NULL}; + + fprintf(stderr,"testing zero data page (1 nil packet)... "); + test_pack(packets,headret,0,0,0); + } + + + + { + /* build a bunch of pages for testing */ + unsigned char *data=_ogg_malloc(1024*1024); + int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; + int inptr=0,i,j; + ogg_page og[5]; + + ogg_stream_reset(&os_en); + + for(i=0;pl[i]!=-1;i++){ + ogg_packet op; + int len=pl[i]; + + op.packet=data+inptr; + op.bytes=len; + op.e_o_s=(pl[i+1]<0?1:0); + op.granulepos=(i+1)*1000; + + for(j=0;j0)error(); + + /* Test fractional page inputs: incomplete fixed header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete header */ + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, + 5); + ogg_sync_wrote(&oy,5); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + /* Test fractional page inputs: incomplete body */ + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, + og[1].header_len-28); + ogg_sync_wrote(&oy,og[1].header_len-28); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); + ogg_sync_wrote(&oy,1000); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, + og[1].body_len-1000); + ogg_sync_wrote(&oy,og[1].body_len-1000); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test fractional page inputs: page + incomplete capture */ + { + ogg_page og_de; + fprintf(stderr,"Testing sync on 1+partial inputs... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, + og[1].header_len-20); + ogg_sync_wrote(&oy,og[1].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + + /* Test recapture: garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing search for capture... "); + ogg_sync_reset(&oy); + + /* 'garbage' */ + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + 20); + ogg_sync_wrote(&oy,20); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, + og[2].header_len-20); + ogg_sync_wrote(&oy,og[2].header_len-20); + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len); + ogg_sync_wrote(&oy,og[2].body_len); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } + +#ifndef DISABLE_CRC + /* Test recapture: page + garbage + page */ + { + ogg_page og_de; + fprintf(stderr,"Testing recapture... "); + ogg_sync_reset(&oy); + + memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, + og[1].header_len); + ogg_sync_wrote(&oy,og[1].header_len); + + memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, + og[1].body_len); + ogg_sync_wrote(&oy,og[1].body_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, + og[2].header_len); + ogg_sync_wrote(&oy,og[2].header_len); + + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, + og[2].body_len-5); + ogg_sync_wrote(&oy,og[2].body_len-5); + + memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, + og[3].header_len); + ogg_sync_wrote(&oy,og[3].header_len); + + memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, + og[3].body_len); + ogg_sync_wrote(&oy,og[3].body_len); + + if(ogg_sync_pageout(&oy,&og_de)>0)error(); + if(ogg_sync_pageout(&oy,&og_de)<=0)error(); + + fprintf(stderr,"ok.\n"); + } +#else + fprintf(stderr,"Skipping recapture test due to --disable-crc\n"); +#endif + + /* Free page data that was previously copied */ + { + for(i=0;i<5;i++){ + free_page(&og[i]); + } + } + } + ogg_sync_clear(&oy); + ogg_stream_clear(&os_en); + ogg_stream_clear(&os_de); + + return(0); +} + +#endif diff --git a/src/libogg/ogg.pc b/src/libogg/ogg.pc new file mode 100644 index 00000000..78755cec --- /dev/null +++ b/src/libogg/ogg.pc @@ -0,0 +1,14 @@ +# ogg pkg-config file + +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: ogg +Description: ogg is a library for manipulating ogg bitstreams +Version: 1.3.4 +Requires: +Conflicts: +Libs: -L${libdir} -logg +Cflags: -I${includedir} diff --git a/src/libogg/ogg/config_types.h b/src/libogg/ogg/config_types.h new file mode 100644 index 00000000..1a87df64 --- /dev/null +++ b/src/libogg/ogg/config_types.h @@ -0,0 +1,26 @@ +#ifndef __CONFIG_TYPES_H__ +#define __CONFIG_TYPES_H__ + +/* these are filled in by configure or cmake*/ +#define INCLUDE_INTTYPES_H 1 +#define INCLUDE_STDINT_H 1 +#define INCLUDE_SYS_TYPES_H 1 + +#if INCLUDE_INTTYPES_H +# include +#endif +#if INCLUDE_STDINT_H +# include +#endif +#if INCLUDE_SYS_TYPES_H +# include +#endif + +typedef int16_t ogg_int16_t; +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 diff --git a/src/libogg/ogg/ogg.h b/src/libogg/ogg/ogg.h new file mode 100644 index 00000000..330ea3c6 --- /dev/null +++ b/src/libogg/ogg/ogg.h @@ -0,0 +1,209 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: toplevel libogg include + + ********************************************************************/ +#ifndef _OGG_H +#define _OGG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "os_types.h" + +typedef struct { + void *iov_base; + size_t iov_len; +} ogg_iovec_t; + +typedef struct { + long endbyte; + int endbit; + + unsigned char *buffer; + unsigned char *ptr; + long storage; +} oggpack_buffer; + +/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ + +typedef struct { + unsigned char *header; + long header_len; + unsigned char *body; + long body_len; +} ogg_page; + +/* ogg_stream_state contains the current encode/decode state of a logical + Ogg bitstream **********************************************************/ + +typedef struct { + unsigned char *body_data; /* bytes from packet bodies */ + long body_storage; /* storage elements allocated */ + long body_fill; /* elements stored; fill mark */ + long body_returned; /* elements of fill returned */ + + + int *lacing_vals; /* The values that will go to the segment table */ + ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact + this way, but it is simple coupled to the + lacing fifo */ + long lacing_storage; + long lacing_fill; + long lacing_packet; + long lacing_returned; + + unsigned char header[282]; /* working space for header encode */ + int header_fill; + + int e_o_s; /* set when we have buffered the last packet in the + logical bitstream */ + int b_o_s; /* set after we've written the initial page + of a logical bitstream */ + long serialno; + long pageno; + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ + ogg_int64_t granulepos; + +} ogg_stream_state; + +/* ogg_packet is used to encapsulate the data and metadata belonging + to a single raw Ogg/Vorbis packet *************************************/ + +typedef struct { + unsigned char *packet; + long bytes; + long b_o_s; + long e_o_s; + + ogg_int64_t granulepos; + + ogg_int64_t packetno; /* sequence number for decode; the framing + knows where there's a hole in the data, + but we need coupling so that the codec + (which is in a separate abstraction + layer) also knows about the gap */ +} ogg_packet; + +typedef struct { + unsigned char *data; + int storage; + int fill; + int returned; + + int unsynced; + int headerbytes; + int bodybytes; +} ogg_sync_state; + +/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ + +extern void oggpack_writeinit(oggpack_buffer *b); +extern int oggpack_writecheck(oggpack_buffer *b); +extern void oggpack_writetrunc(oggpack_buffer *b,long bits); +extern void oggpack_writealign(oggpack_buffer *b); +extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpack_reset(oggpack_buffer *b); +extern void oggpack_writeclear(oggpack_buffer *b); +extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpack_look(oggpack_buffer *b,int bits); +extern long oggpack_look1(oggpack_buffer *b); +extern void oggpack_adv(oggpack_buffer *b,int bits); +extern void oggpack_adv1(oggpack_buffer *b); +extern long oggpack_read(oggpack_buffer *b,int bits); +extern long oggpack_read1(oggpack_buffer *b); +extern long oggpack_bytes(oggpack_buffer *b); +extern long oggpack_bits(oggpack_buffer *b); +extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); + +extern void oggpackB_writeinit(oggpack_buffer *b); +extern int oggpackB_writecheck(oggpack_buffer *b); +extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); +extern void oggpackB_writealign(oggpack_buffer *b); +extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); +extern void oggpackB_reset(oggpack_buffer *b); +extern void oggpackB_writeclear(oggpack_buffer *b); +extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); +extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); +extern long oggpackB_look(oggpack_buffer *b,int bits); +extern long oggpackB_look1(oggpack_buffer *b); +extern void oggpackB_adv(oggpack_buffer *b,int bits); +extern void oggpackB_adv1(oggpack_buffer *b); +extern long oggpackB_read(oggpack_buffer *b,int bits); +extern long oggpackB_read1(oggpack_buffer *b); +extern long oggpackB_bytes(oggpack_buffer *b); +extern long oggpackB_bits(oggpack_buffer *b); +extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); + +/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ + +extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); +extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, + int count, long e_o_s, ogg_int64_t granulepos); +extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); +extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); + +/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ + +extern int ogg_sync_init(ogg_sync_state *oy); +extern int ogg_sync_clear(ogg_sync_state *oy); +extern int ogg_sync_reset(ogg_sync_state *oy); +extern int ogg_sync_destroy(ogg_sync_state *oy); +extern int ogg_sync_check(ogg_sync_state *oy); + +extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); +extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); +extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); +extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); +extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); +extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); +extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); + +/* Ogg BITSTREAM PRIMITIVES: general ***************************/ + +extern int ogg_stream_init(ogg_stream_state *os,int serialno); +extern int ogg_stream_clear(ogg_stream_state *os); +extern int ogg_stream_reset(ogg_stream_state *os); +extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); +extern int ogg_stream_destroy(ogg_stream_state *os); +extern int ogg_stream_check(ogg_stream_state *os); +extern int ogg_stream_eos(ogg_stream_state *os); + +extern void ogg_page_checksum_set(ogg_page *og); + +extern int ogg_page_version(const ogg_page *og); +extern int ogg_page_continued(const ogg_page *og); +extern int ogg_page_bos(const ogg_page *og); +extern int ogg_page_eos(const ogg_page *og); +extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); +extern int ogg_page_serialno(const ogg_page *og); +extern long ogg_page_pageno(const ogg_page *og); +extern int ogg_page_packets(const ogg_page *og); + +extern void ogg_packet_clear(ogg_packet *op); + + +#ifdef __cplusplus +} +#endif + +#endif /* _OGG_H */ diff --git a/src/libogg/ogg/os_types.h b/src/libogg/ogg/os_types.h new file mode 100644 index 00000000..644e3750 --- /dev/null +++ b/src/libogg/ogg/os_types.h @@ -0,0 +1,158 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * + * by the Xiph.Org Foundation http://www.xiph.org/ * + * * + ******************************************************************** + + function: Define a consistent set of types on each platform. + + ********************************************************************/ +#ifndef _OS_TYPES_H +#define _OS_TYPES_H + +/* make it easy on the folks that want to compile the libs with a + different malloc than stdlib */ +#define _ogg_malloc malloc +#define _ogg_calloc calloc +#define _ogg_realloc realloc +#define _ogg_free free + +#if defined(_WIN32) + +# if defined(__CYGWIN__) +# include + typedef int16_t ogg_int16_t; + 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; +# elif defined(__MINGW32__) +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + 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(__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; + typedef unsigned short ogg_uint16_t; +# else +# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */ +# include + typedef int16_t ogg_int16_t; + 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; +# else + /* MSVC/Borland */ + 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 +# endif + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t ogg_int16_t; + 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; + +#elif defined(__HAIKU__) + + /* Haiku */ +# include + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + 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__) + + /* Be */ +# include + typedef int16_t ogg_int16_t; + 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; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + 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) + + /* DJGPP */ + typedef short ogg_int16_t; + 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; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + 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__) + + /* TI C64x compiler */ + typedef signed short ogg_int16_t; + typedef unsigned short ogg_uint16_t; + 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 + +# include "config_types.h" + +#endif + +#endif /* _OS_TYPES_H */ diff --git a/src/libopus/AUTHORS b/src/libopus/AUTHORS new file mode 100644 index 00000000..b3d22a20 --- /dev/null +++ b/src/libopus/AUTHORS @@ -0,0 +1,6 @@ +Jean-Marc Valin (jmvalin@jmvalin.ca) +Koen Vos (koenvos74@gmail.com) +Timothy Terriberry (tterribe@xiph.org) +Karsten Vandborg Sorensen (karsten.vandborg.sorensen@skype.net) +Soren Skak Jensen (ssjensen@gn.com) +Gregory Maxwell (greg@xiph.org) diff --git a/src/libopus/COPYING b/src/libopus/COPYING new file mode 100644 index 00000000..9c739c34 --- /dev/null +++ b/src/libopus/COPYING @@ -0,0 +1,44 @@ +Copyright 2001-2011 Xiph.Org, Skype Limited, Octasic, + Jean-Marc Valin, Timothy B. Terriberry, + CSIRO, Gregory Maxwell, Mark Borgerding, + Erik de Castro Lopo + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Opus is subject to the royalty-free patent licenses which are +specified at: + +Xiph.Org Foundation: +https://datatracker.ietf.org/ipr/1524/ + +Microsoft Corporation: +https://datatracker.ietf.org/ipr/1914/ + +Broadcom Corporation: +https://datatracker.ietf.org/ipr/1526/ diff --git a/src/libopus/ChangeLog b/src/libopus/ChangeLog new file mode 100644 index 00000000..e69de29b diff --git a/src/libopus/INSTALL b/src/libopus/INSTALL new file mode 100644 index 00000000..8865734f --- /dev/null +++ b/src/libopus/INSTALL @@ -0,0 +1,368 @@ +Installation Instructions +************************* + + Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software +Foundation, Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell command './configure && make && make install' +should configure, build, and install this package. The following +more-detailed instructions are generic; see the 'README' file for +instructions specific to this package. Some packages provide this +'INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The 'configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a 'Makefile' in each directory of the package. +It may also create one or more '.h' files containing system-dependent +definitions. Finally, it creates a shell script 'config.status' that +you can run in the future to recreate the current configuration, and a +file 'config.log' containing compiler output (useful mainly for +debugging 'configure'). + + It can also use an optional file (typically called 'config.cache' and +enabled with '--cache-file=config.cache' or simply '-C') that saves the +results of its tests to speed up reconfiguring. Caching is disabled by +default to prevent problems with accidental use of stale cache files. + + If you need to do unusual things to compile the package, please try +to figure out how 'configure' could check whether to do them, and mail +diffs or instructions to the address given in the 'README' so they can +be considered for the next release. If you are using the cache, and at +some point 'config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file 'configure.ac' (or 'configure.in') is used to create +'configure' by a program called 'autoconf'. You need 'configure.ac' if +you want to change it or regenerate 'configure' using a newer version of +'autoconf'. + + The simplest way to compile this package is: + + 1. 'cd' to the directory containing the package's source code and type + './configure' to configure the package for your system. + + Running 'configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type 'make' to compile the package. + + 3. Optionally, type 'make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type 'make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the 'make install' phase executed with root + privileges. + + 5. Optionally, type 'make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior 'make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing 'make clean'. To also remove the + files that 'configure' created (so you can compile the package for + a different kind of computer), type 'make distclean'. There is + also a 'make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type 'make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide 'make + distcheck', which can by used by developers to test that all other + targets like 'make install' and 'make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the 'configure' script does not know about. Run './configure --help' +for details on some of the pertinent environment variables. + + You can give 'configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here is +an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU 'make'. 'cd' to the +directory where you want the object files and executables to go and run +the 'configure' script. 'configure' automatically checks for the source +code in the directory that 'configure' is in and in '..'. This is known +as a "VPATH" build. + + With a non-GNU 'make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use 'make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple '-arch' options to the +compiler but only a single '-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the 'lipo' tool if you have problems. + +Installation Names +================== + + By default, 'make install' installs the package's commands under +'/usr/local/bin', include files under '/usr/local/include', etc. You +can specify an installation prefix other than '/usr/local' by giving +'configure' the option '--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option '--exec-prefix=PREFIX' to 'configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like '--bindir=DIR' to specify different values for particular +kinds of files. Run 'configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the default +for these options is expressed in terms of '${prefix}', so that +specifying just '--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to 'configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +'make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, 'make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +'${prefix}'. Any directories that were specified during 'configure', +but not in terms of '${prefix}', must each be overridden at install time +for the entire installation to be relocated. The approach of makefile +variable overrides for each directory variable is required by the GNU +Coding Standards, and ideally causes no recompilation. However, some +platforms have known limitations with the semantics of shared libraries +that end up requiring recompilation when using this method, particularly +noticeable in packages that use GNU Libtool. + + The second method involves providing the 'DESTDIR' variable. For +example, 'make install DESTDIR=/alternate/directory' will prepend +'/alternate/directory' before all installation names. The approach of +'DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of '${prefix}' +at 'configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving 'configure' the +option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. + + Some packages pay attention to '--enable-FEATURE' options to +'configure', where FEATURE indicates an optional part of the package. +They may also pay attention to '--with-PACKAGE' options, where PACKAGE +is something like 'gnu-as' or 'x' (for the X Window System). The +'README' should mention any '--enable-' and '--with-' options that the +package recognizes. + + For packages that use the X Window System, 'configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the 'configure' options '--x-includes=DIR' and +'--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of 'make' will be. For these packages, running './configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with 'make V=1'; while running './configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with 'make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC +is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX 'make' updates targets which have the same time stamps as their +prerequisites, which makes it generally unusable when shipped generated +files such as 'configure' are involved. Use GNU 'make' instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its '' header file. The option '-nodtk' can be used as a +workaround. If GNU CC is not installed, it is therefore recommended to +try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put '/usr/ucb' early in your 'PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in '/usr/bin'. So, if you need '/usr/ucb' +in your 'PATH', put it _after_ '/usr/bin'. + + On Haiku, software installed for all users goes in '/boot/common', +not '/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features 'configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, 'configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +'--build=TYPE' option. TYPE can either be a short name for the system +type, such as 'sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file 'config.sub' for the possible values of each field. If +'config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option '--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with '--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for 'configure' scripts to share, +you can create a site shell script called 'config.site' that gives +default values for variables like 'CC', 'cache_file', and 'prefix'. +'configure' looks for 'PREFIX/share/config.site' if it exists, then +'PREFIX/etc/config.site' if it exists. Or, you can set the +'CONFIG_SITE' environment variable to the location of the site script. +A warning: not all 'configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to 'configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the 'configure' command line, using 'VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified 'gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an +Autoconf limitation. Until the limitation is lifted, you can use this +workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +'configure' Invocation +====================== + + 'configure' recognizes the following options to control how it +operates. + +'--help' +'-h' + Print a summary of all of the options to 'configure', and exit. + +'--help=short' +'--help=recursive' + Print a summary of the options unique to this package's + 'configure', and exit. The 'short' variant lists options used only + in the top level, while the 'recursive' variant lists options also + present in any nested packages. + +'--version' +'-V' + Print the version of Autoconf used to generate the 'configure' + script, and exit. + +'--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally 'config.cache'. FILE defaults to '/dev/null' to + disable caching. + +'--config-cache' +'-C' + Alias for '--cache-file=config.cache'. + +'--quiet' +'--silent' +'-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to '/dev/null' (any error + messages will still be shown). + +'--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + 'configure' can determine that directory automatically. + +'--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: for + more details, including other options available for fine-tuning the + installation locations. + +'--no-create' +'-n' + Run the configure checks, but stop before creating any output + files. + +'configure' also accepts some other, not widely useful, options. Run +'configure --help' for more details. diff --git a/src/libopus/NEWS b/src/libopus/NEWS new file mode 100644 index 00000000..e69de29b diff --git a/src/libopus/README b/src/libopus/README new file mode 100644 index 00000000..27fddf96 --- /dev/null +++ b/src/libopus/README @@ -0,0 +1,161 @@ +== Opus audio codec == + +Opus is a codec for interactive speech and audio transmission over the Internet. + + Opus can handle a wide range of interactive audio applications, including +Voice over IP, videoconferencing, in-game chat, and even remote live music +performances. It can scale from low bit-rate narrowband speech to very high +quality stereo music. + + Opus, when coupled with an appropriate container format, is also suitable +for non-realtime stored-file applications such as music distribution, game +soundtracks, portable music players, jukeboxes, and other applications that +have historically used high latency formats such as MP3, AAC, or Vorbis. + + Opus is specified by IETF RFC 6716: + https://tools.ietf.org/html/rfc6716 + + The Opus format and this implementation of it are subject to the royalty- +free patent and copyright licenses specified in the file COPYING. + +This package implements a shared library for encoding and decoding raw Opus +bitstreams. Raw Opus bitstreams should be used over RTP according to + https://tools.ietf.org/html/rfc7587 + +The package also includes a number of test tools used for testing the +correct operation of the library. The bitstreams read/written by these +tools should not be used for Opus file distribution: They include +additional debugging data and cannot support seeking. + +Opus stored in files should use the Ogg encapsulation for Opus which is +described at: + https://tools.ietf.org/html/rfc7845 + +An opus-tools package is available which provides encoding and decoding of +Ogg encapsulated Opus files and includes a number of useful features. + +Opus-tools can be found at: + https://git.xiph.org/?p=opus-tools.git +or on the main Opus website: + https://opus-codec.org/ + +== Compiling libopus == + +To build from a distribution tarball, you only need to do the following: + + % ./configure + % make + +To build from the git repository, the following steps are necessary: + +0) Set up a development environment: + +On an Ubuntu or Debian family Linux distribution: + + % sudo apt-get install git autoconf automake libtool gcc make + +On a Fedora/Redhat based Linux: + + % sudo dnf install git autoconf automake libtool gcc make + +Or for older Redhat/Centos Linux releases: + + % sudo yum install git autoconf automake libtool gcc make + +On Apple macOS, install Xcode and brew.sh, then in the Terminal enter: + + % brew install autoconf automake libtool + +1) Clone the repository: + + % git clone https://git.xiph.org/opus.git + % cd opus + +2) Compiling the source + + % ./autogen.sh + % ./configure + % make + +3) Install the codec libraries (optional) + + % sudo make install + +Once you have compiled the codec, there will be a opus_demo executable +in the top directory. + +Usage: opus_demo [-e] + [options] + opus_demo -d [options] + + +mode: voip | audio | restricted-lowdelay +options: + -e : only runs the encoder (output the bit-stream) + -d : only runs the decoder (reads the bit-stream as input) + -cbr : enable constant bitrate; default: variable bitrate + -cvbr : enable constrained variable bitrate; default: + unconstrained + -bandwidth + : audio bandwidth (from narrowband to fullband); + default: sampling rate + -framesize <2.5|5|10|20|40|60> + : frame size in ms; default: 20 + -max_payload + : maximum payload size in bytes, default: 1024 + -complexity + : complexity, 0 (lowest) ... 10 (highest); default: 10 + -inbandfec : enable SILK inband FEC + -forcemono : force mono encoding, even for stereo input + -dtx : enable SILK DTX + -loss : simulate packet loss, in percent (0-100); default: 0 + +input and output are little-endian signed 16-bit PCM files or opus +bitstreams with simple opus_demo proprietary framing. + +== Testing == + +This package includes a collection of automated unit and system tests +which SHOULD be run after compiling the package especially the first +time it is run on a new platform. + +To run the integrated tests: + + % make check + +There is also collection of standard test vectors which are not +included in this package for size reasons but can be obtained from: +https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + +To run compare the code to these test vectors: + + % curl -OL https://opus-codec.org/docs/opus_testvectors-rfc8251.tar.gz + % tar -zxf opus_testvectors-rfc8251.tar.gz + % ./tests/run_vectors.sh ./ opus_newvectors 48000 + +== Portability notes == + +This implementation uses floating-point by default but can be compiled to +use only fixed-point arithmetic by setting --enable-fixed-point (if using +autoconf) or by defining the FIXED_POINT macro (if building manually). +The fixed point implementation has somewhat lower audio quality and is +slower on platforms with fast FPUs, it is normally only used in embedded +environments. + +The implementation can be compiled with either a C89 or a C99 compiler. +While it does not rely on any _undefined behavior_ as defined by C89 or +C99, it relies on common _implementation-defined behavior_ for two's +complement architectures: + +o Right shifts of negative values are consistent with two's + complement arithmetic, so that a>>b is equivalent to + floor(a/(2^b)), + +o For conversion to a signed integer of N bits, the value is reduced + modulo 2^N to be within range of the type, + +o The result of integer division of a negative value is truncated + towards zero, and + +o The compiler provides a 64-bit integer type (a C99 requirement + which is supported by most C89 compilers). diff --git a/src/libopus/analysis.h b/src/libopus/analysis.h new file mode 100644 index 00000000..553c0e7c --- /dev/null +++ b/src/libopus/analysis.h @@ -0,0 +1,103 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ANALYSIS_H +#define ANALYSIS_H + +#include "celt/celt.h" +#include "opus_private.h" +#include "mlp.h" + +#define NB_FRAMES 8 +#define NB_TBANDS 18 +#define ANALYSIS_BUF_SIZE 720 /* 30 ms at 24 kHz */ + +/* At that point we can stop counting frames because it no longer matters. */ +#define ANALYSIS_COUNT_MAX 10000 + +#define DETECT_SIZE 100 + +/* Uncomment this to print the MLP features on stdout. */ +/*#define MLP_TRAINING*/ + +typedef struct { + int arch; + int application; + opus_int32 Fs; +#define TONALITY_ANALYSIS_RESET_START angle + float angle[240]; + float d_angle[240]; + float d2_angle[240]; + opus_val32 inmem[ANALYSIS_BUF_SIZE]; + int mem_fill; /* number of usable samples in the buffer */ + float prev_band_tonality[NB_TBANDS]; + float prev_tonality; + int prev_bandwidth; + float E[NB_FRAMES][NB_TBANDS]; + float logE[NB_FRAMES][NB_TBANDS]; + float lowE[NB_TBANDS]; + float highE[NB_TBANDS]; + float meanE[NB_TBANDS+1]; + float mem[32]; + float cmean[8]; + float std[9]; + float Etracker; + float lowECount; + int E_count; + int count; + int analysis_offset; + int write_pos; + int read_pos; + int read_subframe; + float hp_ener_accum; + int initialized; + float rnn_state[MAX_NEURONS]; + opus_val32 downmix_state[3]; + AnalysisInfo info[DETECT_SIZE]; +} TonalityAnalysisState; + +/** Initialize a TonalityAnalysisState struct. + * + * This performs some possibly slow initialization steps which should + * not be repeated every analysis step. No allocated memory is retained + * by the state struct, so no cleanup call is required. + */ +void tonality_analysis_init(TonalityAnalysisState *analysis, opus_int32 Fs); + +/** Reset a TonalityAnalysisState stuct. + * + * Call this when there's a discontinuity in the data. + */ +void tonality_analysis_reset(TonalityAnalysisState *analysis); + +void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len); + +void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm, + int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs, + int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info); + +#endif diff --git a/src/libopus/celt/_kiss_fft_guts.h b/src/libopus/celt/_kiss_fft_guts.h new file mode 100644 index 00000000..17392b3e --- /dev/null +++ b/src/libopus/celt/_kiss_fft_guts.h @@ -0,0 +1,182 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +#ifndef KISS_FFT_GUTS_H +#define KISS_FFT_GUTS_H + +#define MIN(a,b) ((a)<(b) ? (a):(b)) +#define MAX(a,b) ((a)>(b) ? (a):(b)) + +/* kiss_fft.h + defines kiss_fft_scalar as either short or a float type + and defines + typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ +#include "kiss_fft.h" + +/* + Explanation of macros dealing with complex math: + + C_MUL(m,a,b) : m = a*b + C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise + C_SUB( res, a,b) : res = a - b + C_SUBFROM( res , a) : res -= a + C_ADDTO( res , a) : res += a + * */ +#ifdef FIXED_POINT +#include "arch.h" + + +#define SAMP_MAX 2147483647 +#define TWID_MAX 32767 +#define TRIG_UPSCALE 1 + +#define SAMP_MIN -SAMP_MAX + + +# define S_MUL(a,b) MULT16_32_Q15(b, a) + +# define C_MUL(m,a,b) \ + do{ (m).r = SUB32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = ADD32_ovflw(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0) + +# define C_MULC(m,a,b) \ + do{ (m).r = ADD32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \ + (m).i = SUB32_ovflw(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0) + +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r = S_MUL( (c).r , s ) ;\ + (c).i = S_MUL( (c).i , s ) ; }while(0) + +# define DIVSCALAR(x,k) \ + (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 ) + +# define C_FIXDIV(c,div) \ + do { DIVSCALAR( (c).r , div); \ + DIVSCALAR( (c).i , div); }while (0) + +#define C_ADD( res, a,b)\ + do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \ + }while(0) +#define C_SUB( res, a,b)\ + do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \ + }while(0) +#define C_ADDTO( res , a)\ + do {(res).r = ADD32_ovflw((res).r, (a).r); (res).i = ADD32_ovflw((res).i,(a).i);\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {(res).r = ADD32_ovflw((res).r,(a).r); (res).i = SUB32_ovflw((res).i,(a).i); \ + }while(0) + +#if defined(OPUS_ARM_INLINE_ASM) +#include "arm/kiss_fft_armv4.h" +#endif + +#if defined(OPUS_ARM_INLINE_EDSP) +#include "arm/kiss_fft_armv5e.h" +#endif +#if defined(MIPSr1_ASM) +#include "mips/kiss_fft_mipsr1.h" +#endif + +#else /* not FIXED_POINT*/ + +# define S_MUL(a,b) ( (a)*(b) ) +#define C_MUL(m,a,b) \ + do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ + (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) +#define C_MULC(m,a,b) \ + do{ (m).r = (a).r*(b).r + (a).i*(b).i;\ + (m).i = (a).i*(b).r - (a).r*(b).i; }while(0) + +#define C_MUL4(m,a,b) C_MUL(m,a,b) + +# define C_FIXDIV(c,div) /* NOOP */ +# define C_MULBYSCALAR( c, s ) \ + do{ (c).r *= (s);\ + (c).i *= (s); }while(0) +#endif + +#ifndef CHECK_OVERFLOW_OP +# define CHECK_OVERFLOW_OP(a,op,b) /* noop */ +#endif + +#ifndef C_ADD +#define C_ADD( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,+,(b).r)\ + CHECK_OVERFLOW_OP((a).i,+,(b).i)\ + (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ + }while(0) +#define C_SUB( res, a,b)\ + do { \ + CHECK_OVERFLOW_OP((a).r,-,(b).r)\ + CHECK_OVERFLOW_OP((a).i,-,(b).i)\ + (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ + }while(0) +#define C_ADDTO( res , a)\ + do { \ + CHECK_OVERFLOW_OP((res).r,+,(a).r)\ + CHECK_OVERFLOW_OP((res).i,+,(a).i)\ + (res).r += (a).r; (res).i += (a).i;\ + }while(0) + +#define C_SUBFROM( res , a)\ + do {\ + CHECK_OVERFLOW_OP((res).r,-,(a).r)\ + CHECK_OVERFLOW_OP((res).i,-,(a).i)\ + (res).r -= (a).r; (res).i -= (a).i; \ + }while(0) +#endif /* C_ADD defined */ + +#ifdef FIXED_POINT +/*# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase)))) +# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))*/ +# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase)) +# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase)) +# define HALF_OF(x) ((x)>>1) +#elif defined(USE_SIMD) +# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) +# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) +# define HALF_OF(x) ((x)*_mm_set1_ps(.5f)) +#else +# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) +# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) +# define HALF_OF(x) ((x)*.5f) +#endif + +#define kf_cexp(x,phase) \ + do{ \ + (x)->r = KISS_FFT_COS(phase);\ + (x)->i = KISS_FFT_SIN(phase);\ + }while(0) + +#define kf_cexp2(x,phase) \ + do{ \ + (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\ + (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\ +}while(0) + +#endif /* KISS_FFT_GUTS_H */ diff --git a/src/libopus/celt/arch.h b/src/libopus/celt/arch.h new file mode 100644 index 00000000..0db602d4 --- /dev/null +++ b/src/libopus/celt/arch.h @@ -0,0 +1,288 @@ +/* Copyright (c) 2003-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file arch.h + @brief Various architecture definitions for CELT +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ARCH_H +#define ARCH_H + +#include "../opus_types.h" +#include "../opus_defines.h" + +# if !defined(__GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define __GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define __GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if OPUS_GNUC_PREREQ(3, 0) +#define opus_likely(x) (__builtin_expect(!!(x), 1)) +#define opus_unlikely(x) (__builtin_expect(!!(x), 0)) +#else +#define opus_likely(x) (!!(x)) +#define opus_unlikely(x) (!!(x)) +#endif + +#define CELT_SIG_SCALE 32768.f + +#define CELT_FATAL(str) celt_fatal(str, __FILE__, __LINE__); + +#if defined(ENABLE_ASSERTIONS) || defined(ENABLE_HARDENING) +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line); + +#if defined(CELT_C) && !defined(OVERRIDE_celt_fatal) +#include +#include +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +void celt_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +#endif + +#define celt_assert(cond) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond);}} +#define celt_assert2(cond, message) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond "\n" message);}} +#define MUST_SUCCEED(call) celt_assert((call) == OPUS_OK) +#else +#define celt_assert(cond) +#define celt_assert2(cond, message) +#define MUST_SUCCEED(call) do {if((call) != OPUS_OK) {RESTORE_STACK; return OPUS_INTERNAL_ERROR;} } while (0) +#endif + +#if defined(ENABLE_ASSERTIONS) +#define celt_sig_assert(cond) {if (!(cond)) {CELT_FATAL("signal assertion failed: " #cond);}} +#else +#define celt_sig_assert(cond) +#endif + +#define IMUL32(a,b) ((a)*(b)) + +#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */ +#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */ +#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */ +#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */ +#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */ +#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */ +#define UADD32(a,b) ((a)+(b)) +#define USUB32(a,b) ((a)-(b)) + +/* Set this if opus_int64 is a native type of the CPU. */ +/* Assume that all LP64 architectures have fast 64-bit types; also x86_64 + (which can be ILP32 for x32) and Win64 (which is LLP64). */ +#if defined(__x86_64__) || defined(__LP64__) || defined(_WIN64) +#define OPUS_FAST_INT64 1 +#else +#define OPUS_FAST_INT64 0 +#endif + +#define PRINT_MIPS(file) + +#ifdef FIXED_POINT + +typedef opus_int16 opus_val16; +typedef opus_int32 opus_val32; +typedef opus_int64 opus_val64; + +typedef opus_val32 celt_sig; +typedef opus_val16 celt_norm; +typedef opus_val32 celt_ener; + +#define celt_isnan(x) 0 + +#define Q15ONE 32767 + +#define SIG_SHIFT 12 +/* Safe saturation value for 32-bit signals. Should be less than + 2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/ +#define SIG_SAT (300000000) + +#define NORM_SCALING 16384 + +#define DB_SHIFT 10 + +#define EPSILON 1 +#define VERY_SMALL 0 +#define VERY_LARGE16 ((opus_val16)32767) +#define Q15_ONE ((opus_val16)32767) + +#define SCALEIN(a) (a) +#define SCALEOUT(a) (a) + +#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) +#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) + +static OPUS_INLINE opus_int16 SAT16(opus_int32 x) { + return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x; +} + +#ifdef FIXED_DEBUG +#include "fixed_debug.h" +#else + +#include "fixed_generic.h" + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/fixed_arm64.h" +#elif defined (OPUS_ARM_INLINE_EDSP) +#include "arm/fixed_armv5e.h" +#elif defined (OPUS_ARM_INLINE_ASM) +#include "arm/fixed_armv4.h" +#elif defined (BFIN_ASM) +#include "fixed_bfin.h" +#elif defined (TI_C5X_ASM) +#include "fixed_c5x.h" +#elif defined (TI_C6X_ASM) +#include "fixed_c6x.h" +#endif + +#endif + +#else /* FIXED_POINT */ + +typedef float opus_val16; +typedef float opus_val32; +typedef float opus_val64; + +typedef float celt_sig; +typedef float celt_norm; +typedef float celt_ener; + +#ifdef FLOAT_APPROX +/* This code should reliably detect NaN/inf even when -ffast-math is used. + Assumes IEEE 754 format. */ +static OPUS_INLINE int celt_isnan(float x) +{ + union {float f; opus_uint32 i;} in; + in.f = x; + return ((in.i>>23)&0xFF)==0xFF && (in.i&0x007FFFFF)!=0; +} +#else +#ifdef __FAST_MATH__ +#error Cannot build libopus with -ffast-math unless FLOAT_APPROX is defined. This could result in crashes on extreme (e.g. NaN) input +#endif +#define celt_isnan(x) ((x)!=(x)) +#endif + +#define Q15ONE 1.0f + +#define NORM_SCALING 1.f + +#define EPSILON 1e-15f +#define VERY_SMALL 1e-30f +#define VERY_LARGE16 1e15f +#define Q15_ONE ((opus_val16)1.f) + +/* This appears to be the same speed as C99's fabsf() but it's more portable. */ +#define ABS16(x) ((float)fabs(x)) +#define ABS32(x) ((float)fabs(x)) + +#define QCONST16(x,bits) (x) +#define QCONST32(x,bits) (x) + +#define NEG16(x) (-(x)) +#define NEG32(x) (-(x)) +#define NEG32_ovflw(x) (-(x)) +#define EXTRACT16(x) (x) +#define EXTEND32(x) (x) +#define SHR16(a,shift) (a) +#define SHL16(a,shift) (a) +#define SHR32(a,shift) (a) +#define SHL32(a,shift) (a) +#define PSHR32(a,shift) (a) +#define VSHR32(a,shift) (a) + +#define PSHR(a,shift) (a) +#define SHR(a,shift) (a) +#define SHL(a,shift) (a) +#define SATURATE(x,a) (x) +#define SATURATE16(x) (x) + +#define ROUND16(a,shift) (a) +#define SROUND16(a,shift) (a) +#define HALF16(x) (.5f*(x)) +#define HALF32(x) (.5f*(x)) + +#define ADD16(a,b) ((a)+(b)) +#define SUB16(a,b) ((a)-(b)) +#define ADD32(a,b) ((a)+(b)) +#define SUB32(a,b) ((a)-(b)) +#define ADD32_ovflw(a,b) ((a)+(b)) +#define SUB32_ovflw(a,b) ((a)-(b)) +#define MULT16_16_16(a,b) ((a)*(b)) +#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b)) +#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b)) + +#define MULT16_32_Q15(a,b) ((a)*(b)) +#define MULT16_32_Q16(a,b) ((a)*(b)) + +#define MULT32_32_Q31(a,b) ((a)*(b)) + +#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b)) +#define MAC16_32_Q16(c,a,b) ((c)+(a)*(b)) + +#define MULT16_16_Q11_32(a,b) ((a)*(b)) +#define MULT16_16_Q11(a,b) ((a)*(b)) +#define MULT16_16_Q13(a,b) ((a)*(b)) +#define MULT16_16_Q14(a,b) ((a)*(b)) +#define MULT16_16_Q15(a,b) ((a)*(b)) +#define MULT16_16_P15(a,b) ((a)*(b)) +#define MULT16_16_P13(a,b) ((a)*(b)) +#define MULT16_16_P14(a,b) ((a)*(b)) +#define MULT16_32_P16(a,b) ((a)*(b)) + +#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b)) +#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b)) + +#define SCALEIN(a) ((a)*CELT_SIG_SCALE) +#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE)) + +#define SIG2WORD16(x) (x) + +#endif /* !FIXED_POINT */ + +#ifndef GLOBAL_STACK_SIZE +#ifdef FIXED_POINT +#define GLOBAL_STACK_SIZE 120000 +#else +#define GLOBAL_STACK_SIZE 120000 +#endif +#endif + +#endif /* ARCH_H */ diff --git a/src/libopus/celt/bands.c b/src/libopus/celt/bands.c new file mode 100644 index 00000000..ea5c4a3f --- /dev/null +++ b/src/libopus/celt/bands.c @@ -0,0 +1,1672 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2009 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include +#include "bands.h" +#include "modes.h" +#include "vq.h" +#include "cwrs.h" +#include "stack_alloc.h" +#include "os_support.h" +#include "mathops.h" +#include "rate.h" +#include "quant_bands.h" +#include "pitch.h" + +int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev) +{ + int i; + for (i=0;iprev && val < thresholds[prev]+hysteresis[prev]) + i=prev; + if (i thresholds[prev-1]-hysteresis[prev-1]) + i=prev; + return i; +} + +opus_uint32 celt_lcg_rand(opus_uint32 seed) +{ + return 1664525 * seed + 1013904223; +} + +/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness + with this approximation is important because it has an impact on the bit allocation */ +opus_int16 bitexact_cos(opus_int16 x) +{ + opus_int32 tmp; + opus_int16 x2; + tmp = (4096+((opus_int32)(x)*(x)))>>13; + celt_sig_assert(tmp<=32767); + x2 = tmp; + x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2))))); + celt_sig_assert(x2<=32766); + return 1+x2; +} + +int bitexact_log2tan(int isin,int icos) +{ + int lc; + int ls; + lc=EC_ILOG(icos); + ls=EC_ILOG(isin); + icos<<=15-lc; + isin<<=15-ls; + return (ls-lc)*(1<<11) + +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932) + -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932); +} + +#ifdef FIXED_POINT +/* Compute the amplitude (sqrt energy) in each of the bands */ +void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch) +{ + int i, c, N; + const opus_int16 *eBands = m->eBands; + (void)arch; + N = m->shortMdctSize< 0) + { + int shift = celt_ilog2(maxval) - 14 + (((m->logN[i]>>BITRES)+LM+1)>>1); + j=eBands[i]<0) + { + do { + sum = MAC16_16(sum, EXTRACT16(SHR32(X[j+c*N],shift)), + EXTRACT16(SHR32(X[j+c*N],shift))); + } while (++jnbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift); + } else { + bandE[i+c*m->nbEBands] = EPSILON; + } + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + i=0; do { + opus_val16 g; + int j,shift; + opus_val16 E; + shift = celt_zlog2(bandE[i+c*m->nbEBands])-13; + E = VSHR32(bandE[i+c*m->nbEBands], shift); + g = EXTRACT16(celt_rcp(SHL32(E,3))); + j=M*eBands[i]; do { + X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g); + } while (++jeBands; + N = m->shortMdctSize<nbEBands] = celt_sqrt(sum); + /*printf ("%f ", bandE[i+c*m->nbEBands]);*/ + } + } while (++ceBands; + N = M*m->shortMdctSize; + c=0; do { + for (i=0;inbEBands]); + for (j=M*eBands[i];jeBands; + N = M*m->shortMdctSize; + bound = M*eBands[end]; + if (downsample!=1) + bound = IMIN(bound, N/downsample); + if (silence) + { + bound = 0; + start = end = 0; + } + f = freq; + x = X+M*eBands[start]; + for (i=0;i>DB_SHIFT); + if (shift>31) + { + shift=0; + g=0; + } else { + /* Handle the fractional part. */ + g = celt_exp2_frac(lg&((1< 16384 we'd be likely to overflow, so we're + capping the gain here, which is equivalent to a cap of 18 on lg. + This shouldn't trigger unless the bitstream is already corrupted. */ + if (shift <= -2) + { + g = 16384; + shift = -2; + } + do { + *f++ = SHL32(MULT16_16(*x++, g), -shift); + } while (++jeBands[i+1]-m->eBands[i]; + /* depth in 1/8 bits */ + celt_sig_assert(pulses[i]>=0); + depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM; + +#ifdef FIXED_POINT + thresh32 = SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1); + thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,thresh32)); + { + opus_val32 t; + t = N0<>1; + t = SHL32(t, (7-shift)<<1); + sqrt_1 = celt_rsqrt_norm(t); + } +#else + thresh = .5f*celt_exp2(-.125f*depth); + sqrt_1 = celt_rsqrt(N0<nbEBands+i]; + prev2 = prev2logE[c*m->nbEBands+i]; + if (C==1) + { + prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]); + prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]); + } + Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2)); + Ediff = MAX32(0, Ediff); + +#ifdef FIXED_POINT + if (Ediff < 16384) + { + opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1); + r = 2*MIN16(16383,r32); + } else { + r = 0; + } + if (LM==3) + r = MULT16_16_Q14(23170, MIN32(23169, r)); + r = SHR16(MIN16(thresh, r),1); + r = SHR32(MULT16_16_Q15(sqrt_1, r),shift); +#else + /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because + short blocks don't have the same energy as long */ + r = 2.f*celt_exp2(-Ediff); + if (LM==3) + r *= 1.41421356f; + r = MIN16(thresh, r); + r = r*sqrt_1; +#endif + X = X_+c*size+(m->eBands[i]<nbEBands]))-13; +#endif + left = VSHR32(bandE[i],shift); + right = VSHR32(bandE[i+m->nbEBands],shift); + norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right)); + a1 = DIV32_16(SHL32(EXTEND32(left),14),norm); + a2 = DIV32_16(SHL32(EXTEND32(right),14),norm); + for (j=0;j>1; + kr = celt_ilog2(Er)>>1; +#endif + t = VSHR32(El, (kl-7)<<1); + lgain = celt_rsqrt_norm(t); + t = VSHR32(Er, (kr-7)<<1); + rgain = celt_rsqrt_norm(t); + +#ifdef FIXED_POINT + if (kl < 7) + kl = 7; + if (kr < 7) + kr = 7; +#endif + + for (j=0;jeBands; + int decision; + int hf_sum=0; + + celt_assert(end>0); + + N0 = M*m->shortMdctSize; + + if (M*(eBands[end]-eBands[end-1]) <= 8) + return SPREAD_NONE; + c=0; do { + for (i=0;im->nbEBands-4) + hf_sum += celt_udiv(32*(tcount[1]+tcount[0]), N); + tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N); + sum += tmp*spread_weight[i]; + nbBands+=spread_weight[i]; + } + } while (++cnbEBands+end)); + *hf_average = (*hf_average+hf_sum)>>1; + hf_sum = *hf_average; + if (*tapset_decision==2) + hf_sum += 4; + else if (*tapset_decision==0) + hf_sum -= 4; + if (hf_sum > 22) + *tapset_decision=2; + else if (hf_sum > 18) + *tapset_decision=1; + else + *tapset_decision=0; + } + /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/ + celt_assert(nbBands>0); /* end has to be non-zero */ + celt_assert(sum>=0); + sum = celt_udiv((opus_int32)sum<<8, nbBands); + /* Recursive averaging */ + sum = (sum+*average)>>1; + *average = sum; + /* Hysteresis */ + sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2; + if (sum < 80) + { + decision = SPREAD_AGGRESSIVE; + } else if (sum < 256) + { + decision = SPREAD_NORMAL; + } else if (sum < 384) + { + decision = SPREAD_LIGHT; + } else { + decision = SPREAD_NONE; + } +#ifdef FUZZING + decision = rand()&0x3; + *tapset_decision=rand()%3; +#endif + return decision; +} + +/* Indexing table for converting from natural Hadamard to ordery Hadamard + This is essentially a bit-reversed Gray, on top of which we've added + an inversion of the order because we want the DC at the end rather than + the beginning. The lines are for N=2, 4, 8, 16 */ +static const int ordery_table[] = { + 1, 0, + 3, 0, 2, 1, + 7, 0, 4, 3, 6, 1, 5, 2, + 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5, +}; + +static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard) +{ + int i,j; + VARDECL(celt_norm, tmp); + int N; + SAVE_STACK; + N = N0*stride; + ALLOC(tmp, N, celt_norm); + celt_assert(stride>0); + if (hadamard) + { + const int *ordery = ordery_table+stride-2; + for (i=0;i>= 1; + for (i=0;i>1)) { + qn = 1; + } else { + qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES)); + qn = (qn+1)>>1<<1; + } + celt_assert(qn <= 256); + return qn; +} + +struct band_ctx { + int encode; + int resynth; + const CELTMode *m; + int i; + int intensity; + int spread; + int tf_change; + ec_ctx *ec; + opus_int32 remaining_bits; + const celt_ener *bandE; + opus_uint32 seed; + int arch; + int theta_round; + int disable_inv; + int avoid_split_noise; +}; + +struct split_ctx { + int inv; + int imid; + int iside; + int delta; + int itheta; + int qalloc; +}; + +static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx, + celt_norm *X, celt_norm *Y, int N, int *b, int B, int B0, + int LM, + int stereo, int *fill) +{ + int qn; + int itheta=0; + int delta; + int imid, iside; + int qalloc; + int pulse_cap; + int offset; + opus_int32 tell; + int inv=0; + int encode; + const CELTMode *m; + int i; + int intensity; + ec_ctx *ec; + const celt_ener *bandE; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + intensity = ctx->intensity; + ec = ctx->ec; + bandE = ctx->bandE; + + /* Decide on the resolution to give to the split parameter theta */ + pulse_cap = m->logN[i]+LM*(1<>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET); + qn = compute_qn(N, *b, offset, pulse_cap, stereo); + if (stereo && i>=intensity) + qn = 1; + if (encode) + { + /* theta is the atan() of the ratio between the (normalized) + side and mid. With just that parameter, we can re-scale both + mid and side because we know that 1) they have unit norm and + 2) they are orthogonal. */ + itheta = stereo_itheta(X, Y, stereo, N, ctx->arch); + } + tell = ec_tell_frac(ec); + if (qn!=1) + { + if (encode) + { + if (!stereo || ctx->theta_round == 0) + { + itheta = (itheta*(opus_int32)qn+8192)>>14; + if (!stereo && ctx->avoid_split_noise && itheta > 0 && itheta < qn) + { + /* Check if the selected value of theta will cause the bit allocation + to inject noise on one side. If so, make sure the energy of that side + is zero. */ + int unquantized = celt_udiv((opus_int32)itheta*16384, qn); + imid = bitexact_cos((opus_int16)unquantized); + iside = bitexact_cos((opus_int16)(16384-unquantized)); + delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid)); + if (delta > *b) + itheta = qn; + else if (delta < -*b) + itheta = 0; + } + } else { + int down; + /* Bias quantization towards itheta=0 and itheta=16384. */ + int bias = itheta > 8192 ? 32767/qn : -32767/qn; + down = IMIN(qn-1, IMAX(0, (itheta*(opus_int32)qn + bias)>>14)); + if (ctx->theta_round < 0) + itheta = down; + else + itheta = down+1; + } + } + /* Entropy coding of the angle. We use a uniform pdf for the + time split, a step for stereo, and a triangular one for the rest. */ + if (stereo && N>2) + { + int p0 = 3; + int x = itheta; + int x0 = qn/2; + int ft = p0*(x0+1) + x0; + /* Use a probability of p0 up to itheta=8192 and then use 1 after */ + if (encode) + { + ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + } else { + int fs; + fs=ec_decode(ec,ft); + if (fs<(x0+1)*p0) + x=fs/p0; + else + x=x0+1+(fs-(x0+1)*p0); + ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft); + itheta = x; + } + } else if (B0>1 || stereo) { + /* Uniform pdf */ + if (encode) + ec_enc_uint(ec, itheta, qn+1); + else + itheta = ec_dec_uint(ec, qn+1); + } else { + int fs=1, ft; + ft = ((qn>>1)+1)*((qn>>1)+1); + if (encode) + { + int fl; + + fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta; + fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 : + ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + + ec_encode(ec, fl, fl+fs, ft); + } else { + /* Triangular pdf */ + int fl=0; + int fm; + fm = ec_decode(ec, ft); + + if (fm < ((qn>>1)*((qn>>1) + 1)>>1)) + { + itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1; + fs = itheta + 1; + fl = itheta*(itheta + 1)>>1; + } + else + { + itheta = (2*(qn + 1) + - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1; + fs = qn + 1 - itheta; + fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1); + } + + ec_dec_update(ec, fl, fl+fs, ft); + } + } + celt_assert(itheta>=0); + itheta = celt_udiv((opus_int32)itheta*16384, qn); + if (encode && stereo) + { + if (itheta==0) + intensity_stereo(m, X, Y, bandE, i, N); + else + stereo_split(X, Y, N); + } + /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate. + Let's do that at higher complexity */ + } else if (stereo) { + if (encode) + { + inv = itheta > 8192 && !ctx->disable_inv; + if (inv) + { + int j; + for (j=0;j2<remaining_bits > 2<disable_inv) + inv = 0; + itheta = 0; + } + qalloc = ec_tell_frac(ec) - tell; + *b -= qalloc; + + if (itheta == 0) + { + imid = 32767; + iside = 0; + *fill &= (1<inv = inv; + sctx->imid = imid; + sctx->iside = iside; + sctx->delta = delta; + sctx->itheta = itheta; + sctx->qalloc = qalloc; +} +static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b, + celt_norm *lowband_out) +{ + int c; + int stereo; + celt_norm *x = X; + int encode; + ec_ctx *ec; + + encode = ctx->encode; + ec = ctx->ec; + + stereo = Y != NULL; + c=0; do { + int sign=0; + if (ctx->remaining_bits>=1<remaining_bits -= 1<resynth) + x[0] = sign ? -NORM_SCALING : NORM_SCALING; + x = Y; + } while (++c<1+stereo); + if (lowband_out) + lowband_out[0] = SHR16(X[0],4); + return 1; +} + +/* This function is responsible for encoding and decoding a mono partition. + It can split the band in two and transmit the energy difference with + the two half-bands. It can be called recursively so bands can end up being + split in 8 parts. */ +static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, + opus_val16 gain, int fill) +{ + const unsigned char *cache; + int q; + int curr_bits; + int imid=0, iside=0; + int B0=B; + opus_val16 mid=0, side=0; + unsigned cm=0; + celt_norm *Y=NULL; + int encode; + const CELTMode *m; + int i; + int spread; + ec_ctx *ec; + + encode = ctx->encode; + m = ctx->m; + i = ctx->i; + spread = ctx->spread; + ec = ctx->ec; + + /* If we need 1.5 more bit than we can produce, split the band in two. */ + cache = m->cache.bits + m->cache.index[(LM+1)*m->nbEBands+i]; + if (LM != -1 && b > cache[cache[0]]+12 && N>2) + { + int mbits, sbits, delta; + int itheta; + int qalloc; + struct split_ctx sctx; + celt_norm *next_lowband2=NULL; + opus_int32 rebalance; + + N >>= 1; + Y = X+N; + LM -= 1; + if (B==1) + fill = (fill&1)|(fill<<1); + B = (B+1)>>1; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B0, LM, 0, &fill); + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* Give more bits to low-energy MDCTs than they would otherwise deserve */ + if (B0>1 && (itheta&0x3fff)) + { + if (itheta > 8192) + /* Rough approximation for pre-echo masking */ + delta -= delta>>(4-LM); + else + /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */ + delta = IMIN(0, delta + (N<>(5-LM))); + } + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + if (lowband) + next_lowband2 = lowband+N; /* >32-bit split case */ + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + cm = quant_partition(ctx, X, N, mbits, B, lowband, LM, + MULT16_16_P15(gain,mid), fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B)<<(B0>>1); + } else { + cm = quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM, + MULT16_16_P15(gain,side), fill>>B)<<(B0>>1); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<remaining_bits -= curr_bits; + + /* Ensures we can never bust the budget */ + while (ctx->remaining_bits < 0 && q > 0) + { + ctx->remaining_bits += curr_bits; + q--; + curr_bits = pulses2bits(m, i, LM, q); + ctx->remaining_bits -= curr_bits; + } + + if (q!=0) + { + int K = get_pulses(q); + + /* Finally do the actual quantization */ + if (encode) + { + cm = alg_quant(X, N, K, spread, B, ec, gain, ctx->resynth, ctx->arch); + } else { + cm = alg_unquant(X, N, K, spread, B, ec, gain); + } + } else { + /* If there's no pulse, fill the band anyway */ + int j; + if (ctx->resynth) + { + unsigned cm_mask; + /* B can be as large as 16, so this shift might overflow an int on a + 16-bit platform; use a long to get defined behavior.*/ + cm_mask = (unsigned)(1UL<seed = celt_lcg_rand(ctx->seed); + X[j] = (celt_norm)((opus_int32)ctx->seed>>20); + } + cm = cm_mask; + } else { + /* Folded spectrum */ + for (j=0;jseed = celt_lcg_rand(ctx->seed); + /* About 48 dB below the "normal" folding level */ + tmp = QCONST16(1.0f/256, 10); + tmp = (ctx->seed)&0x8000 ? tmp : -tmp; + X[j] = lowband[j]+tmp; + } + cm = fill; + } + renormalise_vector(X, N, gain, ctx->arch); + } + } + } + } + + return cm; +} + + +/* This function is responsible for encoding and decoding a band for the mono case. */ +static unsigned quant_band(struct band_ctx *ctx, celt_norm *X, + int N, int b, int B, celt_norm *lowband, + int LM, celt_norm *lowband_out, + opus_val16 gain, celt_norm *lowband_scratch, int fill) +{ + int N0=N; + int N_B=N; + int N_B0; + int B0=B; + int time_divide=0; + int recombine=0; + int longBlocks; + unsigned cm=0; + int k; + int encode; + int tf_change; + + encode = ctx->encode; + tf_change = ctx->tf_change; + + longBlocks = B0==1; + + N_B = celt_udiv(N_B, B); + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, NULL, b, lowband_out); + } + + if (tf_change>0) + recombine = tf_change; + /* Band recombining to increase frequency resolution */ + + if (lowband_scratch && lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1)) + { + OPUS_COPY(lowband_scratch, lowband, N); + lowband = lowband_scratch; + } + + for (k=0;k>k, 1<>k, 1<>4]<<2; + } + B>>=recombine; + N_B<<=recombine; + + /* Increasing the time resolution */ + while ((N_B&1) == 0 && tf_change<0) + { + if (encode) + haar1(X, N_B, B); + if (lowband) + haar1(lowband, N_B, B); + fill |= fill<>= 1; + time_divide++; + tf_change++; + } + B0=B; + N_B0 = N_B; + + /* Reorganize the samples in time order instead of frequency order */ + if (B0>1) + { + if (encode) + deinterleave_hadamard(X, N_B>>recombine, B0<>recombine, B0<resynth) + { + /* Undo the sample reorganization going from time order to frequency order */ + if (B0>1) + interleave_hadamard(X, N_B>>recombine, B0<>= 1; + N_B <<= 1; + cm |= cm>>B; + haar1(X, N_B, B); + } + + for (k=0;k>k, 1<encode; + ec = ctx->ec; + + /* Special case for one sample */ + if (N==1) + { + return quant_band_n1(ctx, X, Y, b, lowband_out); + } + + orig_fill = fill; + + compute_theta(ctx, &sctx, X, Y, N, &b, B, B, LM, 1, &fill); + inv = sctx.inv; + imid = sctx.imid; + iside = sctx.iside; + delta = sctx.delta; + itheta = sctx.itheta; + qalloc = sctx.qalloc; +#ifdef FIXED_POINT + mid = imid; + side = iside; +#else + mid = (1.f/32768)*imid; + side = (1.f/32768)*iside; +#endif + + /* This is a special case for N=2 that only works for stereo and takes + advantage of the fact that mid and side are orthogonal to encode + the side with just one bit. */ + if (N==2) + { + int c; + int sign=0; + celt_norm *x2, *y2; + mbits = b; + sbits = 0; + /* Only need one bit for the side. */ + if (itheta != 0 && itheta != 16384) + sbits = 1< 8192; + ctx->remaining_bits -= qalloc+sbits; + + x2 = c ? Y : X; + y2 = c ? X : Y; + if (sbits) + { + if (encode) + { + /* Here we only need to encode a sign for the side. */ + sign = x2[0]*y2[1] - x2[1]*y2[0] < 0; + ec_enc_bits(ec, sign, 1); + } else { + sign = ec_dec_bits(ec, 1); + } + } + sign = 1-2*sign; + /* We use orig_fill here because we want to fold the side, but if + itheta==16384, we'll have cleared the low bits of fill. */ + cm = quant_band(ctx, x2, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, orig_fill); + /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), + and there's no need to worry about mixing with the other channel. */ + y2[0] = -sign*x2[1]; + y2[1] = sign*x2[0]; + if (ctx->resynth) + { + celt_norm tmp; + X[0] = MULT16_16_Q15(mid, X[0]); + X[1] = MULT16_16_Q15(mid, X[1]); + Y[0] = MULT16_16_Q15(side, Y[0]); + Y[1] = MULT16_16_Q15(side, Y[1]); + tmp = X[0]; + X[0] = SUB16(tmp,Y[0]); + Y[0] = ADD16(tmp,Y[0]); + tmp = X[1]; + X[1] = SUB16(tmp,Y[1]); + Y[1] = ADD16(tmp,Y[1]); + } + } else { + /* "Normal" split code */ + opus_int32 rebalance; + + mbits = IMAX(0, IMIN(b, (b-delta)/2)); + sbits = b-mbits; + ctx->remaining_bits -= qalloc; + + rebalance = ctx->remaining_bits; + if (mbits >= sbits) + { + /* In stereo mode, we do not apply a scaling to the mid because we need the normalized + mid for folding later. */ + cm = quant_band(ctx, X, N, mbits, B, lowband, LM, lowband_out, Q15ONE, + lowband_scratch, fill); + rebalance = mbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<>B); + } else { + /* For a stereo split, the high bits of fill are always zero, so no + folding will be done to the side. */ + cm = quant_band(ctx, Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill>>B); + rebalance = sbits - (rebalance-ctx->remaining_bits); + if (rebalance > 3<resynth) + { + if (N!=2) + stereo_merge(X, Y, mid, N, ctx->arch); + if (inv) + { + int j; + for (j=0;jeBands; + n1 = M*(eBands[start+1]-eBands[start]); + n2 = M*(eBands[start+2]-eBands[start+1]); + /* Duplicate enough of the first band folding data to be able to fold the second band. + Copies no data for CELT-only mode. */ + OPUS_COPY(&norm[n1], &norm[2*n1 - n2], n2-n1); + if (dual_stereo) + OPUS_COPY(&norm2[n1], &norm2[2*n1 - n2], n2-n1); +} + +void quant_all_bands(int encode, const CELTMode *m, int start, int end, + celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks, + const celt_ener *bandE, int *pulses, int shortBlocks, int spread, + int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits, + opus_int32 balance, ec_ctx *ec, int LM, int codedBands, + opus_uint32 *seed, int complexity, int arch, int disable_inv) +{ + int i; + opus_int32 remaining_bits; + const opus_int16 * OPUS_RESTRICT eBands = m->eBands; + celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2; + VARDECL(celt_norm, _norm); + VARDECL(celt_norm, _lowband_scratch); + VARDECL(celt_norm, X_save); + VARDECL(celt_norm, Y_save); + VARDECL(celt_norm, X_save2); + VARDECL(celt_norm, Y_save2); + VARDECL(celt_norm, norm_save2); + int resynth_alloc; + celt_norm *lowband_scratch; + int B; + int M; + int lowband_offset; + int update_lowband = 1; + int C = Y_ != NULL ? 2 : 1; + int norm_offset; + int theta_rdo = encode && Y_!=NULL && !dual_stereo && complexity>=8; +#ifdef RESYNTH + int resynth = 1; +#else + int resynth = !encode || theta_rdo; +#endif + struct band_ctx ctx; + SAVE_STACK; + + M = 1<nbEBands-1]-norm_offset), celt_norm); + norm = _norm; + norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset; + + /* For decoding, we can use the last band as scratch space because we don't need that + scratch space for the last band and we don't care about the data there until we're + decoding the last band. */ + if (encode && resynth) + resynth_alloc = M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]); + else + resynth_alloc = ALLOC_NONE; + ALLOC(_lowband_scratch, resynth_alloc, celt_norm); + if (encode && resynth) + lowband_scratch = _lowband_scratch; + else + lowband_scratch = X_+M*eBands[m->nbEBands-1]; + ALLOC(X_save, resynth_alloc, celt_norm); + ALLOC(Y_save, resynth_alloc, celt_norm); + ALLOC(X_save2, resynth_alloc, celt_norm); + ALLOC(Y_save2, resynth_alloc, celt_norm); + ALLOC(norm_save2, resynth_alloc, celt_norm); + + lowband_offset = 0; + ctx.bandE = bandE; + ctx.ec = ec; + ctx.encode = encode; + ctx.intensity = intensity; + ctx.m = m; + ctx.seed = *seed; + ctx.spread = spread; + ctx.arch = arch; + ctx.disable_inv = disable_inv; + ctx.resynth = resynth; + ctx.theta_round = 0; + /* Avoid injecting noise in the first band on transients. */ + ctx.avoid_split_noise = B > 1; + for (i=start;i 0); + tell = ec_tell_frac(ec); + + /* Compute how many bits we want to allocate to this band */ + if (i != start) + balance -= tell; + remaining_bits = total_bits-tell-1; + ctx.remaining_bits = remaining_bits; + if (i <= codedBands-1) + { + curr_balance = celt_sudiv(balance, IMIN(3, codedBands-i)); + b = IMAX(0, IMIN(16383, IMIN(remaining_bits+1,pulses[i]+curr_balance))); + } else { + b = 0; + } + +#ifndef DISABLE_UPDATE_DRAFT + if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0)) + lowband_offset = i; + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#else + if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0)) + lowband_offset = i; +#endif + + tf_change = tf_res[i]; + ctx.tf_change = tf_change; + if (i>=m->effEBands) + { + X=norm; + if (Y_!=NULL) + Y = norm; + lowband_scratch = NULL; + } + if (last && !theta_rdo) + lowband_scratch = NULL; + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0)) + { + int fold_start; + int fold_end; + int fold_i; + /* This ensures we never repeat spectral content within one band */ + effective_lowband = IMAX(0, M*eBands[lowband_offset]-norm_offset-N); + fold_start = lowband_offset; + while(M*eBands[--fold_start] > effective_lowband+norm_offset); + fold_end = lowband_offset-1; +#ifndef DISABLE_UPDATE_DRAFT + while(++fold_end < i && M*eBands[fold_end] < effective_lowband+norm_offset+N); +#else + while(M*eBands[++fold_end] < effective_lowband+norm_offset+N); +#endif + x_cm = y_cm = 0; + fold_i = fold_start; do { + x_cm |= collapse_masks[fold_i*C+0]; + y_cm |= collapse_masks[fold_i*C+C-1]; + } while (++fold_inbEBands], w); + /* Make a copy. */ + cm = x_cm|y_cm; + ec_save = *ec; + ctx_save = ctx; + OPUS_COPY(X_save, X, N); + OPUS_COPY(Y_save, Y, N); + /* Encode and round down. */ + ctx.theta_round = -1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist0 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + + /* Save first result. */ + cm2 = x_cm; + ec_save2 = *ec; + ctx_save2 = ctx; + OPUS_COPY(X_save2, X, N); + OPUS_COPY(Y_save2, Y, N); + if (!last) + OPUS_COPY(norm_save2, norm+M*eBands[i]-norm_offset, N); + nstart_bytes = ec_save.offs; + nend_bytes = ec_save.storage; + bytes_buf = ec_save.buf+nstart_bytes; + save_bytes = nend_bytes-nstart_bytes; + OPUS_COPY(bytes_save, bytes_buf, save_bytes); + + /* Restore */ + *ec = ec_save; + ctx = ctx_save; + OPUS_COPY(X, X_save, N); + OPUS_COPY(Y, Y_save, N); +#ifndef DISABLE_UPDATE_DRAFT + if (i == start+1) + special_hybrid_folding(m, norm, norm2, start, M, dual_stereo); +#endif + /* Encode and round up. */ + ctx.theta_round = 1; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm); + dist1 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch)); + if (dist0 >= dist1) { + x_cm = cm2; + *ec = ec_save2; + ctx = ctx_save2; + OPUS_COPY(X, X_save2, N); + OPUS_COPY(Y, Y_save2, N); + if (!last) + OPUS_COPY(norm+M*eBands[i]-norm_offset, norm_save2, N); + OPUS_COPY(bytes_buf, bytes_save, save_bytes); + } + } else { + ctx.theta_round = 0; + x_cm = quant_band_stereo(&ctx, X, Y, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm); + } + } else { + x_cm = quant_band(&ctx, X, N, b, B, + effective_lowband != -1 ? norm+effective_lowband : NULL, LM, + last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm); + } + y_cm = x_cm; + } + collapse_masks[i*C+0] = (unsigned char)x_cm; + collapse_masks[i*C+C-1] = (unsigned char)y_cm; + balance += pulses[i] + tell; + + /* Update the folding position only as long as we have 1 bit/sample depth. */ + update_lowband = b>(N< +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +#ifndef PACKAGE_VERSION +#define PACKAGE_VERSION "unknown" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/celt_mipsr1.h" +#endif + + +int resampling_factor(opus_int32 rate) +{ + int ret; + switch (rate) + { + case 48000: + ret = 1; + break; + case 24000: + ret = 2; + break; + case 16000: + ret = 3; + break; + case 12000: + ret = 4; + break; + case 8000: + ret = 6; + break; + default: +#ifndef CUSTOM_MODES + celt_assert(0); +#endif + ret = 0; + break; + } + return ret; +} + +#if !defined(OVERRIDE_COMB_FILTER_CONST) || defined(NON_STATIC_COMB_FILTER_CONST_C) +/* This version should be faster on ARM */ +#ifdef OPUS_ARM_ASM +#ifndef NON_STATIC_COMB_FILTER_CONST_C +static +#endif +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12) +{ + opus_val32 x0, x1, x2, x3, x4; + int i; + x4 = SHL32(x[-T-2], 1); + x3 = SHL32(x[-T-1], 1); + x2 = SHL32(x[-T], 1); + x1 = SHL32(x[-T+1], 1); + for (i=0;inbEBands;i++) + { + int N; + N=(m->eBands[i+1]-m->eBands[i])<cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2; + } +} + + + +const char *opus_strerror(int error) +{ + static const char * const error_strings[8] = { + "success", + "invalid argument", + "buffer too small", + "internal error", + "corrupted stream", + "request not implemented", + "invalid state", + "memory allocation failed" + }; + if (error > 0 || error < -7) + return "unknown error"; + else + return error_strings[-error]; +} + +const char *opus_get_version_string(void) +{ + return "libopus " PACKAGE_VERSION + /* Applications may rely on the presence of this substring in the version + string to determine if they have a fixed-point or floating-point build + at runtime. */ +#ifdef FIXED_POINT + "-fixed" +#endif +#ifdef FUZZING + "-fuzzing" +#endif + ; +} diff --git a/src/libopus/celt/celt.h b/src/libopus/celt/celt.h new file mode 100644 index 00000000..34549521 --- /dev/null +++ b/src/libopus/celt/celt.h @@ -0,0 +1,251 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/** + @file celt.h + @brief Contains all the functions for encoding and decoding audio + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CELT_H +#define CELT_H + +#include "../opus_types.h" +#include "../opus_defines.h" +#include "../opus_custom.h" +#include "entenc.h" +#include "entdec.h" +#include "arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CELTEncoder OpusCustomEncoder +#define CELTDecoder OpusCustomDecoder +#define CELTMode OpusCustomMode + +#define LEAK_BANDS 19 + +typedef struct { + int valid; + float tonality; + float tonality_slope; + float noisiness; + float activity; + float music_prob; + float music_prob_min; + float music_prob_max; + int bandwidth; + float activity_probability; + float max_pitch_ratio; + /* Store as Q6 char to save space. */ + unsigned char leak_boost[LEAK_BANDS]; +} AnalysisInfo; + +typedef struct { + int signalType; + int offset; +} SILKInfo; + +#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr))) + +#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr))) + +#define __celt_check_silkinfo_ptr(ptr) ((ptr) + ((ptr) - (const SILKInfo*)(ptr))) + +/* Encoder/decoder Requests */ + + +#define CELT_SET_PREDICTION_REQUEST 10002 +/** Controls the use of interframe prediction. + 0=Independent frames + 1=Short term interframe prediction allowed + 2=Long term prediction allowed + */ +#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x) + +#define CELT_SET_INPUT_CLIPPING_REQUEST 10004 +#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x) + +#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007 +#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x) + +#define CELT_SET_CHANNELS_REQUEST 10008 +#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x) + + +/* Internal */ +#define CELT_SET_START_BAND_REQUEST 10010 +#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x) + +#define CELT_SET_END_BAND_REQUEST 10012 +#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x) + +#define CELT_GET_MODE_REQUEST 10015 +/** Get the CELTMode used by an encoder or decoder */ +#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x) + +#define CELT_SET_SIGNALLING_REQUEST 10016 +#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x) + +#define CELT_SET_TONALITY_REQUEST 10018 +#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x) +#define CELT_SET_TONALITY_SLOPE_REQUEST 10020 +#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x) + +#define CELT_SET_ANALYSIS_REQUEST 10022 +#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x) + +#define OPUS_SET_LFE_REQUEST 10024 +#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x) + +#define OPUS_SET_ENERGY_MASK_REQUEST 10026 +#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x) + +#define CELT_SET_SILK_INFO_REQUEST 10028 +#define CELT_SET_SILK_INFO(x) CELT_SET_SILK_INFO_REQUEST, __celt_check_silkinfo_ptr(x) + +/* Encoder stuff */ + +int celt_encoder_get_size(int channels); + +int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch); + + + +/* Decoder stuff */ + +int celt_decoder_get_size(int channels); + + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels); + +int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum); + +#define celt_encoder_ctl opus_custom_encoder_ctl +#define celt_decoder_ctl opus_custom_decoder_ctl + + +#ifdef CUSTOM_MODES +#define OPUS_CUSTOM_NOSTATIC +#else +#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE +#endif + +static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0}; +/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */ +static const unsigned char spread_icdf[4] = {25, 23, 2, 0}; + +static const unsigned char tapset_icdf[3]={2,1,0}; + +#ifdef CUSTOM_MODES +static const unsigned char toOpusTable[20] = { + 0xE0, 0xE8, 0xF0, 0xF8, + 0xC0, 0xC8, 0xD0, 0xD8, + 0xA0, 0xA8, 0xB0, 0xB8, + 0x00, 0x00, 0x00, 0x00, + 0x80, 0x88, 0x90, 0x98, +}; + +static const unsigned char fromOpusTable[16] = { + 0x80, 0x88, 0x90, 0x98, + 0x40, 0x48, 0x50, 0x58, + 0x20, 0x28, 0x30, 0x38, + 0x00, 0x08, 0x10, 0x18 +}; + +static OPUS_INLINE int toOpus(unsigned char c) +{ + int ret=0; + if (c<0xA0) + ret = toOpusTable[c>>3]; + if (ret == 0) + return -1; + else + return ret|(c&0x7); +} + +static OPUS_INLINE int fromOpus(unsigned char c) +{ + if (c<0x80) + return -1; + else + return fromOpusTable[(c>>3)-16] | (c&0x7); +} +#endif /* CUSTOM_MODES */ + +#define COMBFILTER_MAXPERIOD 1024 +#define COMBFILTER_MINPERIOD 15 + +extern const signed char tf_select_table[4][8]; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +void validate_celt_decoder(CELTDecoder *st); +#define VALIDATE_CELT_DECODER(st) validate_celt_decoder(st) +#else +#define VALIDATE_CELT_DECODER(st) +#endif + +int resampling_factor(opus_int32 rate); + +void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp, + int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip); + +void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N, + opus_val16 g0, opus_val16 g1, int tapset0, int tapset1, + const opus_val16 *window, int overlap, int arch); + +#ifdef NON_STATIC_COMB_FILTER_CONST_C +void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N, + opus_val16 g10, opus_val16 g11, opus_val16 g12); +#endif + +#ifndef OVERRIDE_COMB_FILTER_CONST +# define comb_filter_const(y, x, T, N, g10, g11, g12, arch) \ + ((void)(arch),comb_filter_const_c(y, x, T, N, g10, g11, g12)) +#endif + +void init_caps(const CELTMode *m,int *cap,int LM,int C); + +#ifdef RESYNTH +void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem); +void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[], + opus_val16 *oldBandE, int start, int effEnd, int C, int CC, int isTransient, + int LM, int downsample, int silence); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* CELT_H */ diff --git a/src/libopus/celt/celt_decoder.c b/src/libopus/celt/celt_decoder.c new file mode 100644 index 00000000..329b6f6c --- /dev/null +++ b/src/libopus/celt/celt_decoder.c @@ -0,0 +1,1372 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#define CELT_DECODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + +/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save + CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The + current value corresponds to a pitch of 66.67 Hz. */ +#define PLC_PITCH_LAG_MAX (720) +/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a + pitch of 480 Hz. */ +#define PLC_PITCH_LAG_MIN (100) + +#if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT) +#define NORM_ALIASING_HACK +#endif +/**********************************************************************/ +/* */ +/* DECODER */ +/* */ +/**********************************************************************/ +#define DECODE_BUFFER_SIZE 2048 + +/** Decoder state + @brief Decoder state + */ +struct OpusCustomDecoder { + const OpusCustomMode *mode; + int overlap; + int channels; + int stream_channels; + + int downsample; + int start, end; + int signalling; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define DECODER_RESET_START rng + + opus_uint32 rng; + int error; + int last_pitch_index; + int loss_count; + int skip_plc; + int postfilter_period; + int postfilter_period_old; + opus_val16 postfilter_gain; + opus_val16 postfilter_gain_old; + int postfilter_tapset; + int postfilter_tapset_old; + + celt_sig preemph_memD[2]; + + celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */ + /* opus_val16 lpc[], Size = channels*LPC_ORDER */ + /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */ + /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */ +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +/* Make basic checks on the CELT state to ensure we don't end + up writing all over memory. */ +void validate_celt_decoder(CELTDecoder *st) +{ +#ifndef CUSTOM_MODES + celt_assert(st->mode == opus_custom_mode_create(48000, 960, NULL)); + celt_assert(st->overlap == 120); +#endif + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); + celt_assert(st->downsample > 0); + celt_assert(st->start == 0 || st->start == 17); + celt_assert(st->start < st->end); + celt_assert(st->end <= 21); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->last_pitch_index <= PLC_PITCH_LAG_MAX); + celt_assert(st->last_pitch_index >= PLC_PITCH_LAG_MIN || st->last_pitch_index == 0); + celt_assert(st->postfilter_period < MAX_PERIOD); + celt_assert(st->postfilter_period >= COMBFILTER_MINPERIOD || st->postfilter_period == 0); + celt_assert(st->postfilter_period_old < MAX_PERIOD); + celt_assert(st->postfilter_period_old >= COMBFILTER_MINPERIOD || st->postfilter_period_old == 0); + celt_assert(st->postfilter_tapset <= 2); + celt_assert(st->postfilter_tapset >= 0); + celt_assert(st->postfilter_tapset_old <= 2); + celt_assert(st->postfilter_tapset_old >= 0); +} +#endif + +int celt_decoder_get_size(int channels) +{ + const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_decoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTDecoder) + + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig) + + channels*LPC_ORDER*sizeof(opus_val16) + + 4*2*mode->nbEBands*sizeof(opus_val16); + return size; +} + +#ifdef CUSTOM_MODES +CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels)); + ret = opus_custom_decoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_decoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels) +{ + int ret; + ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels); + if (ret != OPUS_OK) + return ret; + st->downsample = resampling_factor(sampling_rate); + if (st->downsample==0) + return OPUS_BAD_ARG; + else + return OPUS_OK; +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels)); + + st->mode = mode; + st->overlap = mode->overlap; + st->stream_channels = st->channels = channels; + + st->downsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; +#ifndef DISABLE_UPDATE_DRAFT + st->disable_inv = channels == 1; +#else + st->disable_inv = 0; +#endif + st->arch = opus_select_arch(); + + opus_custom_decoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_decoder_destroy(CELTDecoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + +#ifndef CUSTOM_MODES +/* Special case for stereo with no downsampling and no accumulation. This is + quite common and we can make it faster by processing both channels in the + same loop, reducing overhead due to the dependency loop in the IIR filter. */ +static void deemphasis_stereo_simple(celt_sig *in[], opus_val16 *pcm, int N, const opus_val16 coef0, + celt_sig *mem) +{ + celt_sig * OPUS_RESTRICT x0; + celt_sig * OPUS_RESTRICT x1; + celt_sig m0, m1; + int j; + x0=in[0]; + x1=in[1]; + m0 = mem[0]; + m1 = mem[1]; + for (j=0;j1) + { + /* Shortcut for the standard (non-custom modes) case */ + for (j=0;joverlap; + nbEBands = mode->nbEBands; + N = mode->shortMdctSize<shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + NB = mode->shortMdctSize<maxLM-LM; + } + + if (CC==2&&C==1) + { + /* Copying a mono streams to two channels */ + celt_sig *freq2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Store a temporary copy in the output buffer because the IMDCT destroys its input. */ + freq2 = out_syn[1]+overlap/2; + OPUS_COPY(freq2, freq, N); + for (b=0;bmdct, &freq2[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + for (b=0;bmdct, &freq[b], out_syn[1]+NB*b, mode->window, overlap, shift, B, arch); + } else if (CC==1&&C==2) + { + /* Downmixing a stereo stream to mono */ + celt_sig *freq2; + freq2 = out_syn[0]+overlap/2; + denormalise_bands(mode, X, freq, oldBandE, start, effEnd, M, + downsample, silence); + /* Use the output buffer as temp array before downmixing. */ + denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M, + downsample, silence); + for (i=0;imdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch); + } else { + /* Normal case (mono or stereo) */ + c=0; do { + denormalise_bands(mode, X+c*N, freq, oldBandE+c*nbEBands, start, effEnd, M, + downsample, silence); + for (b=0;bmdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch); + } while (++cstorage*8; + tell = ec_tell(dec); + logp = isTransient ? 2 : 4; + tf_select_rsv = LM>0 && tell+logp+1<=budget; + budget -= tf_select_rsv; + tf_changed = curr = 0; + for (i=start;i>1, opus_val16 ); + pitch_downsample(decode_mem, lp_pitch_buf, + DECODE_BUFFER_SIZE, C, arch); + pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf, + DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX, + PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch); + pitch_index = PLC_PITCH_LAG_MAX-pitch_index; + RESTORE_STACK; + return pitch_index; +} + +static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM) +{ + int c; + int i; + const int C = st->channels; + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + int start; + int loss_count; + int noise_based; + const opus_int16 *eBands; + SAVE_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C); + oldBandE = lpc+C*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + + loss_count = st->loss_count; + start = st->start; + noise_based = loss_count >= 5 || start != 0 || st->skip_plc; + if (noise_based) + { + /* Noise-based PLC/CNG */ +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + opus_uint32 seed; + int end; + int effEnd; + opus_val16 decay; + end = st->end; + effEnd = IMAX(start, IMIN(end, mode->effEBands)); + +#ifdef NORM_ALIASING_HACK + /* This is an ugly hack that breaks aliasing rules and would be easily broken, + but it saves almost 4kB of stack. */ + X = (celt_norm*)(out_syn[C-1]+overlap/2); +#else + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ +#endif + + /* Energy decay */ + decay = loss_count==0 ? QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT); + c=0; do + { + for (i=start;irng; + for (c=0;c>20); + } + renormalise_vector(X+boffs, blen, Q15ONE, st->arch); + } + } + st->rng = seed; + + c=0; do { + OPUS_MOVE(decode_mem[c], decode_mem[c]+N, + DECODE_BUFFER_SIZE-N+(overlap>>1)); + } while (++cdownsample, 0, st->arch); + } else { + int exc_length; + /* Pitch-based PLC */ + const opus_val16 *window; + opus_val16 *exc; + opus_val16 fade = Q15ONE; + int pitch_index; + VARDECL(opus_val32, etmp); + VARDECL(opus_val16, _exc); + VARDECL(opus_val16, fir_tmp); + + if (loss_count == 0) + { + st->last_pitch_index = pitch_index = celt_plc_pitch_search(decode_mem, C, st->arch); + } else { + pitch_index = st->last_pitch_index; + fade = QCONST16(.8f,15); + } + + /* We want the excitation for 2 pitch periods in order to look for a + decaying signal, but we can't get more than MAX_PERIOD. */ + exc_length = IMIN(2*pitch_index, MAX_PERIOD); + + ALLOC(etmp, overlap, opus_val32); + ALLOC(_exc, MAX_PERIOD+LPC_ORDER, opus_val16); + ALLOC(fir_tmp, exc_length, opus_val16); + exc = _exc+LPC_ORDER; + window = mode->window; + c=0; do { + opus_val16 decay; + opus_val16 attenuation; + opus_val32 S1=0; + celt_sig *buf; + int extrapolation_offset; + int extrapolation_len; + int j; + + buf = decode_mem[c]; + for (i=0;iarch); + /* Add a noise floor of -40 dB. */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Use lag windowing to stabilize the Levinson-Durbin recursion. */ + for (i=1;i<=LPC_ORDER;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(0.008f*0.008f)*i*i; +#endif + } + _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER); +#ifdef FIXED_POINT + /* For fixed-point, apply bandwidth expansion until we can guarantee that + no overflow can happen in the IIR filter. This means: + 32768*sum(abs(filter)) < 2^31 */ + while (1) { + opus_val16 tmp=Q15ONE; + opus_val32 sum=QCONST16(1., SIG_SHIFT); + for (i=0;iarch); + OPUS_COPY(exc+MAX_PERIOD-exc_length, fir_tmp, exc_length); + } + + /* Check if the waveform is decaying, and if so how fast. + We do this to avoid adding energy when concealing in a segment + with decaying energy. */ + { + opus_val32 E1=1, E2=1; + int decay_length; +#ifdef FIXED_POINT + int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20); +#endif + decay_length = exc_length>>1; + for (i=0;i= pitch_index) { + j -= pitch_index; + attenuation = MULT16_16_Q15(attenuation, decay); + } + buf[DECODE_BUFFER_SIZE-N+i] = + SHL32(EXTEND32(MULT16_16_Q15(attenuation, + exc[extrapolation_offset+j])), SIG_SHIFT); + /* Compute the energy of the previously decoded signal whose + excitation we're copying. */ + tmp = ROUND16( + buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j], + SIG_SHIFT); + S1 += SHR32(MULT16_16(tmp, tmp), 10); + } + { + opus_val16 lpc_mem[LPC_ORDER]; + /* Copy the last decoded samples (prior to the overlap region) to + synthesis filter memory so we can have a continuous signal. */ + for (i=0;iarch); +#ifdef FIXED_POINT + for (i=0; i < extrapolation_len; i++) + buf[DECODE_BUFFER_SIZE-N+i] = SATURATE(buf[DECODE_BUFFER_SIZE-N+i], SIG_SAT); +#endif + } + + /* Check if the synthesis energy is higher than expected, which can + happen with the signal changes during our window. If so, + attenuate. */ + { + opus_val32 S2=0; + for (i=0;i SHR32(S2,2))) +#else + /* The float test is written this way to catch NaNs in the output + of the IIR filter at the same time. */ + if (!(S1 > 0.2f*S2)) +#endif + { + for (i=0;ipostfilter_period, st->postfilter_period, overlap, + -st->postfilter_gain, -st->postfilter_gain, + st->postfilter_tapset, st->postfilter_tapset, NULL, 0, st->arch); + + /* Simulate TDAC on the concealed audio so that it blends with the + MDCT of the next frame. */ + for (i=0;iloss_count = loss_count+1; + + RESTORE_STACK; +} + +int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, + int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec, int accum) +{ + int c, i, N; + int spread_decision; + opus_int32 bits; + ec_dec _dec; +#ifdef NORM_ALIASING_HACK + celt_norm *X; +#else + VARDECL(celt_norm, X); +#endif + VARDECL(int, fine_quant); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *decode_mem[2]; + celt_sig *out_syn[2]; + opus_val16 *lpc; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE; + + int shortBlocks; + int isTransient; + int intra_ener; + const int CC = st->channels; + int LM, M; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int postfilter_pitch; + opus_val16 postfilter_gain; + int intensity=0; + int dual_stereo=0; + opus_int32 total_bits; + opus_int32 balance; + opus_int32 tell; + int dynalloc_logp; + int postfilter_tapset; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence; + int C = st->stream_channels; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + ALLOC_STACK; + + VALIDATE_CELT_DECODER(st); + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + frame_size *= st->downsample; + + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC); + oldBandE = lpc+CC*LPC_ORDER; + oldLogE = oldBandE + 2*nbEBands; + oldLogE2 = oldLogE + 2*nbEBands; + backgroundLogE = oldLogE2 + 2*nbEBands; + +#ifdef CUSTOM_MODES + if (st->signalling && data!=NULL) + { + int data0=data[0]; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + data0 = fromOpus(data0); + if (data0<0) + return OPUS_INVALID_PACKET; + } + st->end = end = IMAX(1, mode->effEBands-2*(data0>>5)); + LM = (data0>>3)&0x3; + C = 1 + ((data0>>2)&0x1); + data++; + len--; + if (LM>mode->maxLM) + return OPUS_INVALID_PACKET; + if (frame_size < mode->shortMdctSize<shortMdctSize<maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + return OPUS_BAD_ARG; + } + M=1<1275 || pcm==NULL) + return OPUS_BAD_ARG; + + N = M*mode->shortMdctSize; + c=0; do { + decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap); + out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N; + } while (++c mode->effEBands) + effEnd = mode->effEBands; + + if (data == NULL || len<=1) + { + celt_decode_lost(st, N, LM); + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + RESTORE_STACK; + return frame_size/st->downsample; + } + + /* Check if there are at least two packets received consecutively before + * turning on the pitch-based PLC */ + st->skip_plc = st->loss_count != 0; + + if (dec == NULL) + { + ec_dec_init(&_dec,(unsigned char*)data,len); + dec = &_dec; + } + + if (C==1) + { + for (i=0;i= total_bits) + silence = 1; + else if (tell==1) + silence = ec_dec_bit_logp(dec, 15); + else + silence = 0; + if (silence) + { + /* Pretend we've read all the remaining bits */ + tell = len*8; + dec->nbits_total+=tell-ec_tell(dec); + } + + postfilter_gain = 0; + postfilter_pitch = 0; + postfilter_tapset = 0; + if (start==0 && tell+16 <= total_bits) + { + if(ec_dec_bit_logp(dec, 1)) + { + int qg, octave; + octave = ec_dec_uint(dec, 6); + postfilter_pitch = (16< 0 && tell+3 <= total_bits) + { + isTransient = ec_dec_bit_logp(dec, 3); + tell = ec_tell(dec); + } + else + isTransient = 0; + + if (isTransient) + shortBlocks = M; + else + shortBlocks = 0; + + /* Decode the global flags (first symbols in the stream) */ + intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0; + /* Get band energies */ + unquant_coarse_energy(mode, start, end, oldBandE, + intra_ener, dec, C, LM); + + ALLOC(tf_res, nbEBands, int); + tf_decode(start, end, isTransient, tf_res, LM, dec); + + tell = ec_tell(dec); + spread_decision = SPREAD_NORMAL; + if (tell+4 <= total_bits) + spread_decision = ec_dec_icdf(dec, spread_icdf, 5); + + ALLOC(cap, nbEBands, int); + + init_caps(mode,cap,LM,C); + + ALLOC(offsets, nbEBands, int); + + dynalloc_logp = 6; + total_bits<<=BITRES; + tell = ec_tell_frac(dec); + for (i=start;i0) + dynalloc_logp = IMAX(2, dynalloc_logp-1); + } + + ALLOC(fine_quant, nbEBands, int); + alloc_trim = tell+(6<=2&&bits>=((LM+2)<rng, 0, + st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = ec_dec_bits(dec, 1); + } + + unquant_energy_finalise(mode, start, end, oldBandE, + fine_quant, fine_priority, len*8-ec_tell(dec), dec, C); + + if (anti_collapse_on) + anti_collapse(mode, X, collapse_masks, LM, C, N, + start, end, oldBandE, oldLogE, oldLogE2, pulses, st->rng, st->arch); + + if (silence) + { + for (i=0;idownsample, silence, st->arch); + + c=0; do { + st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD); + st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize, + st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset, + mode->window, overlap, st->arch); + if (LM!=0) + comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize, + st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset, + mode->window, overlap, st->arch); + + } while (++cpostfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + st->postfilter_period = postfilter_pitch; + st->postfilter_gain = postfilter_gain; + st->postfilter_tapset = postfilter_tapset; + if (LM!=0) + { + st->postfilter_period_old = st->postfilter_period; + st->postfilter_gain_old = st->postfilter_gain; + st->postfilter_tapset_old = st->postfilter_tapset; + } + + if (C==1) + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + + /* In case start or end were to change */ + if (!isTransient) + { + opus_val16 max_background_increase; + OPUS_COPY(oldLogE2, oldLogE, 2*nbEBands); + OPUS_COPY(oldLogE, oldBandE, 2*nbEBands); + /* In normal circumstances, we only allow the noise floor to increase by + up to 2.4 dB/second, but when we're in DTX, we allow up to 6 dB + increase for each update.*/ + if (st->loss_count < 10) + max_background_increase = M*QCONST16(0.001f,DB_SHIFT); + else + max_background_increase = QCONST16(1.f,DB_SHIFT); + for (i=0;i<2*nbEBands;i++) + backgroundLogE[i] = MIN16(backgroundLogE[i] + max_background_increase, oldBandE[i]); + } else { + for (i=0;i<2*nbEBands;i++) + oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]); + } + c=0; do + { + for (i=0;irng = dec->rng; + + deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, accum); + st->loss_count = 0; + RESTORE_STACK; + if (ec_tell(dec) > 8*len) + return OPUS_INTERNAL_ERROR; + if(ec_get_error(dec)) + st->error = 1; + return frame_size/st->downsample; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size) +{ + return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size) +{ + int j, ret, C, N; + VARDECL(opus_int16, out); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + + ALLOC(out, C*N, opus_int16); + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + if (ret>0) + for (j=0;jchannels; + N = frame_size; + ALLOC(out, C*N, celt_sig); + + ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL, 0); + + if (ret>0) + for (j=0;j=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case CELT_GET_AND_CLEAR_ERROR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value=st->error; + st->error = 0; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->overlap/st->downsample; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2; + lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels); + oldBandE = lpc+st->channels*LPC_ORDER; + oldLogE = oldBandE + 2*st->mode->nbEBands; + oldLogE2 = oldLogE + 2*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->DECODER_RESET_START, + opus_custom_decoder_get_size(st->mode, st->channels)- + ((char*)&st->DECODER_RESET_START - (char*)st)); + for (i=0;i<2*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->skip_plc = 1; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (value==NULL) + goto bad_arg; + *value = st->postfilter_period; + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/src/libopus/celt/celt_encoder.c b/src/libopus/celt/celt_encoder.c new file mode 100644 index 00000000..1fcb6a81 --- /dev/null +++ b/src/libopus/celt/celt_encoder.c @@ -0,0 +1,2607 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2010 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#define CELT_ENCODER_C + +#include "cpu_support.h" +#include "os_support.h" +#include "mdct.h" +#include +#include "celt.h" +#include "pitch.h" +#include "bands.h" +#include "modes.h" +#include "entcode.h" +#include "quant_bands.h" +#include "rate.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "float_cast.h" +#include +#include "celt_lpc.h" +#include "vq.h" + + +/** Encoder state + @brief Encoder state + */ +struct OpusCustomEncoder { + const OpusCustomMode *mode; /**< Mode used by the encoder */ + int channels; + int stream_channels; + + int force_intra; + int clip; + int disable_pf; + int complexity; + int upsample; + int start, end; + + opus_int32 bitrate; + int vbr; + int signalling; + int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */ + int loss_rate; + int lsb_depth; + int lfe; + int disable_inv; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define ENCODER_RESET_START rng + + opus_uint32 rng; + int spread_decision; + opus_val32 delayedIntra; + int tonal_average; + int lastCodedBands; + int hf_average; + int tapset_decision; + + int prefilter_period; + opus_val16 prefilter_gain; + int prefilter_tapset; +#ifdef RESYNTH + int prefilter_period_old; + opus_val16 prefilter_gain_old; + int prefilter_tapset_old; +#endif + int consec_transient; + AnalysisInfo analysis; + SILKInfo silk_info; + + opus_val32 preemph_memE[2]; + opus_val32 preemph_memD[2]; + + /* VBR-related parameters */ + opus_int32 vbr_reservoir; + opus_int32 vbr_drift; + opus_int32 vbr_offset; + opus_int32 vbr_count; + opus_val32 overlap_max; + opus_val16 stereo_saving; + int intensity; + opus_val16 *energy_mask; + opus_val16 spec_avg; + +#ifdef RESYNTH + /* +MAX_PERIOD/2 to make space for overlap */ + celt_sig syn_mem[2][2*MAX_PERIOD+MAX_PERIOD/2]; +#endif + + celt_sig in_mem[1]; /* Size = channels*mode->overlap */ + /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */ + /* opus_val16 oldBandE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE[], Size = channels*mode->nbEBands */ + /* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */ + /* opus_val16 energyError[], Size = channels*mode->nbEBands */ +}; + +int celt_encoder_get_size(int channels) +{ + CELTMode *mode = opus_custom_mode_create(48000, 960, NULL); + return opus_custom_encoder_get_size(mode, channels); +} + +OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels) +{ + int size = sizeof(struct CELTEncoder) + + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */ + + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */ + + 4*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE[channels*mode->nbEBands]; */ + /* opus_val16 oldLogE2[channels*mode->nbEBands]; */ + /* opus_val16 energyError[channels*mode->nbEBands]; */ + return size; +} + +#ifdef CUSTOM_MODES +CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error) +{ + int ret; + CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels)); + /* init will handle the NULL case */ + ret = opus_custom_encoder_init(st, mode, channels); + if (ret != OPUS_OK) + { + opus_custom_encoder_destroy(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} +#endif /* CUSTOM_MODES */ + +static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode, + int channels, int arch) +{ + if (channels < 0 || channels > 2) + return OPUS_BAD_ARG; + + if (st==NULL || mode==NULL) + return OPUS_ALLOC_FAIL; + + OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels)); + + st->mode = mode; + st->stream_channels = st->channels = channels; + + st->upsample = 1; + st->start = 0; + st->end = st->mode->effEBands; + st->signalling = 1; + st->arch = arch; + + st->constrained_vbr = 1; + st->clip = 1; + + st->bitrate = OPUS_BITRATE_MAX; + st->vbr = 0; + st->force_intra = 0; + st->complexity = 5; + st->lsb_depth=24; + + opus_custom_encoder_ctl(st, OPUS_RESET_STATE); + + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels) +{ + return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch()); +} +#endif + +int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels, + int arch) +{ + int ret; + ret = opus_custom_encoder_init_arch(st, + opus_custom_mode_create(48000, 960, NULL), channels, arch); + if (ret != OPUS_OK) + return ret; + st->upsample = resampling_factor(sampling_rate); + return OPUS_OK; +} + +#ifdef CUSTOM_MODES +void opus_custom_encoder_destroy(CELTEncoder *st) +{ + opus_free(st); +} +#endif /* CUSTOM_MODES */ + + +static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C, + opus_val16 *tf_estimate, int *tf_chan, int allow_weak_transients, + int *weak_transient) +{ + int i; + VARDECL(opus_val16, tmp); + opus_val32 mem0,mem1; + int is_transient = 0; + opus_int32 mask_metric = 0; + int c; + opus_val16 tf_max; + int len2; + /* Forward masking: 6.7 dB/ms. */ +#ifdef FIXED_POINT + int forward_shift = 4; +#else + opus_val16 forward_decay = QCONST16(.0625f,15); +#endif + /* Table of 6*64/x, trained on real data to minimize the average error */ + static const unsigned char inv_table[128] = { + 255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25, + 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12, + 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + }; + SAVE_STACK; + ALLOC(tmp, len, opus_val16); + + *weak_transient = 0; + /* For lower bitrates, let's be more conservative and have a forward masking + decay of 3.3 dB/ms. This avoids having to code transients at very low + bitrate (mostly for hybrid), which can result in unstable energy and/or + partial collapse. */ + if (allow_weak_transients) + { +#ifdef FIXED_POINT + forward_shift = 5; +#else + forward_decay = QCONST16(.03125f,15); +#endif + } + len2=len/2; + for (c=0;c=0;i--) + { + /* Backward masking: 13.9 dB/ms. */ +#ifdef FIXED_POINT + /* FIXME: Use PSHR16() instead */ + tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3); +#else + tmp[i] = mem0 + MULT16_16_P15(QCONST16(0.125f,15),tmp[i]-mem0); +#endif + mem0 = tmp[i]; + maxE = MAX16(maxE, mem0); + } + /*for (i=0;i>1))); +#else + mean = celt_sqrt(mean * maxE*.5*len2); +#endif + /* Inverse of the mean energy in Q15+6 */ + norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1)); + /* Compute harmonic mean discarding the unreliable boundaries + The data is smooth, so we only take 1/4th of the samples */ + unmask=0; + /* We should never see NaNs here. If we find any, then something really bad happened and we better abort + before it does any damage later on. If these asserts are disabled (no hardening), then the table + lookup a few lines below (id = ...) is likely to crash dur to an out-of-bounds read. DO NOT FIX + that crash on NaN since it could result in a worse issue later on. */ + celt_assert(!celt_isnan(tmp[0])); + celt_assert(!celt_isnan(norm)); + for (i=12;imask_metric) + { + *tf_chan = c; + mask_metric = unmask; + } + } + is_transient = mask_metric>200; + /* For low bitrates, define "weak transients" that need to be + handled differently to avoid partial collapse. */ + if (allow_weak_transients && is_transient && mask_metric<600) { + is_transient = 0; + *weak_transient = 1; + } + /* Arbitrary metric for VBR boost */ + tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42); + /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */ + *tf_estimate = celt_sqrt(MAX32(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28))); + /*printf("%d %f\n", tf_max, mask_metric);*/ + RESTORE_STACK; +#ifdef FUZZING + is_transient = rand()&0x1; +#endif + /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/ + return is_transient; +} + +/* Looks for sudden increases of energy to decide whether we need to patch + the transient decision */ +static int patch_transient_decision(opus_val16 *newE, opus_val16 *oldE, int nbEBands, + int start, int end, int C) +{ + int i, c; + opus_val32 mean_diff=0; + opus_val16 spread_old[26]; + /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to + avoid false detection caused by irrelevant bands */ + if (C==1) + { + spread_old[start] = oldE[start]; + for (i=start+1;i=start;i--) + spread_old[i] = MAX16(spread_old[i], spread_old[i+1]-QCONST16(1.0f, DB_SHIFT)); + /* Compute mean increase */ + c=0; do { + for (i=IMAX(2,start);i QCONST16(1.f, DB_SHIFT); +} + +/** Apply window and compute the MDCT for all sub-frames and + all channels in a frame */ +static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in, + celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample, + int arch) +{ + const int overlap = mode->overlap; + int N; + int B; + int shift; + int i, b, c; + if (shortBlocks) + { + B = shortBlocks; + N = mode->shortMdctSize; + shift = mode->maxLM; + } else { + B = 1; + N = mode->shortMdctSize<maxLM-LM; + } + c=0; do { + for (b=0;bmdct, in+c*(B*N+overlap)+b*N, + &out[b+c*N*B], mode->window, overlap, shift, B, + arch); + } + } while (++ceBands[len]-m->eBands[len-1])<eBands[len]-m->eBands[len-1])<eBands[i+1]-m->eBands[i])<eBands[i+1]-m->eBands[i])==1; + OPUS_COPY(tmp, &X[tf_chan*N0 + (m->eBands[i]<eBands[i]<>LM, 1<>k, 1<=0;i--) + { + if (tf_res[i+1] == 1) + tf_res[i] = path1[i+1]; + else + tf_res[i] = path0[i+1]; + } + /*printf("%d %f\n", *tf_sum, tf_estimate);*/ + RESTORE_STACK; +#ifdef FUZZING + tf_select = rand()&0x1; + tf_res[0] = rand()&0x1; + for (i=1;istorage*8; + tell = ec_tell(enc); + logp = isTransient ? 2 : 4; + /* Reserve space to code the tf_select decision. */ + tf_select_rsv = LM>0 && tell+logp+1 <= budget; + budget -= tf_select_rsv; + curr = tf_changed = 0; + for (i=start;i> 10; + trim = QCONST16(4.f, 8) + QCONST16(1.f/16.f, 8)*frac; + } + if (C==2) + { + opus_val16 sum = 0; /* Q10 */ + opus_val16 minXC; /* Q10 */ + /* Compute inter-channel correlation for low frequencies */ + for (i=0;i<8;i++) + { + opus_val32 partial; + partial = celt_inner_prod(&X[m->eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<eBands[i]<eBands[i]<eBands[i+1]-m->eBands[i])<nbEBands]*(opus_int32)(2+2*i-end); + } + } while (++cvalid) + { + trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), + (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f)))); + } +#else + (void)analysis; +#endif + +#ifdef FIXED_POINT + trim_index = PSHR32(trim, 8); +#else + trim_index = (int)floor(.5f+trim); +#endif + trim_index = IMAX(0, IMIN(10, trim_index)); + /*printf("%d\n", trim_index);*/ +#ifdef FUZZING + trim_index = rand()%11; +#endif + return trim_index; +} + +static int stereo_analysis(const CELTMode *m, const celt_norm *X, + int LM, int N0) +{ + int i; + int thetas; + opus_val32 sumLR = EPSILON, sumMS = EPSILON; + + /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */ + for (i=0;i<13;i++) + { + int j; + for (j=m->eBands[i]<eBands[i+1]<eBands[13]<<(LM+1))+thetas, sumMS) + > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); +} + +#define MSWAP(a,b) do {opus_val16 tmp = a;a=b;b=tmp;} while(0) +static opus_val16 median_of_5(const opus_val16 *x) +{ + opus_val16 t0, t1, t2, t3, t4; + t2 = x[2]; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + if (x[3] > x[4]) + { + t3 = x[4]; + t4 = x[3]; + } else { + t3 = x[3]; + t4 = x[4]; + } + if (t0 > t3) + { + MSWAP(t0, t3); + MSWAP(t1, t4); + } + if (t2 > t1) + { + if (t1 < t3) + return MIN16(t2, t3); + else + return MIN16(t4, t1); + } else { + if (t2 < t3) + return MIN16(t1, t3); + else + return MIN16(t2, t4); + } +} + +static opus_val16 median_of_3(const opus_val16 *x) +{ + opus_val16 t0, t1, t2; + if (x[0] > x[1]) + { + t0 = x[1]; + t1 = x[0]; + } else { + t0 = x[0]; + t1 = x[1]; + } + t2 = x[2]; + if (t1 < t2) + return t1; + else if (t0 < t2) + return t2; + else + return t0; +} + +static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2, + int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN, + int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM, + int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc, + AnalysisInfo *analysis, int *importance, int *spread_weight) +{ + int i, c; + opus_int32 tot_boost=0; + opus_val16 maxDepth; + VARDECL(opus_val16, follower); + VARDECL(opus_val16, noise_floor); + SAVE_STACK; + ALLOC(follower, C*nbEBands, opus_val16); + ALLOC(noise_floor, C*nbEBands, opus_val16); + OPUS_CLEAR(offsets, nbEBands); + /* Dynamic allocation code */ + maxDepth=-QCONST16(31.9f, DB_SHIFT); + for (i=0;i=0;i--) + mask[i] = MAX16(mask[i], mask[i+1] - QCONST16(3.f, DB_SHIFT)); + for (i=0;i> shift; + } + /*for (i=0;i 50 && LM>=1 && !lfe) + { + int last=0; + c=0;do + { + opus_val16 offset; + opus_val16 tmp; + opus_val16 *f; + f = &follower[c*nbEBands]; + f[0] = bandLogE2[c*nbEBands]; + for (i=1;i bandLogE2[c*nbEBands+i-1]+QCONST16(.5f,DB_SHIFT)) + last=i; + f[i] = MIN16(f[i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*nbEBands+i]); + } + for (i=last-1;i>=0;i--) + f[i] = MIN16(f[i], MIN16(f[i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i])); + + /* Combine with a median filter to avoid dynalloc triggering unnecessarily. + The "offset" value controls how conservative we are -- a higher offset + reduces the impact of the median filter and makes dynalloc use more bits. */ + offset = QCONST16(1.f, DB_SHIFT); + for (i=2;i=12) + follower[i] = HALF16(follower[i]); + } +#ifdef DISABLE_FLOAT_API + (void)analysis; +#else + if (analysis->valid) + { + for (i=start;ileak_boost[i]; + } +#endif + for (i=start;i 48) { + boost = (int)SHR32(EXTEND32(follower[i])*8,DB_SHIFT); + boost_bits = (boost*width<>BITRES>>3 > 2*effectiveBytes/3) + { + opus_int32 cap = ((2*effectiveBytes/3)<mode; + overlap = mode->overlap; + ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig); + + pre[0] = _pre; + pre[1] = _pre + (N+COMBFILTER_MAXPERIOD); + + + c=0; do { + OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD); + OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+overlap)+overlap, N); + } while (++c>1, opus_val16); + + pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC, st->arch); + /* Don't search for the fir last 1.5 octave of the range because + there's too many false-positives due to short-term correlation */ + pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N, + COMBFILTER_MAXPERIOD-3*COMBFILTER_MINPERIOD, &pitch_index, + st->arch); + pitch_index = COMBFILTER_MAXPERIOD-pitch_index; + + gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD, + N, &pitch_index, st->prefilter_period, st->prefilter_gain, st->arch); + if (pitch_index > COMBFILTER_MAXPERIOD-2) + pitch_index = COMBFILTER_MAXPERIOD-2; + gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1); + /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/ + if (st->loss_rate>2) + gain1 = HALF32(gain1); + if (st->loss_rate>4) + gain1 = HALF32(gain1); + if (st->loss_rate>8) + gain1 = 0; + } else { + gain1 = 0; + pitch_index = COMBFILTER_MINPERIOD; + } +#ifndef DISABLE_FLOAT_API + if (analysis->valid) + gain1 = (opus_val16)(gain1 * analysis->max_pitch_ratio); +#else + (void)analysis; +#endif + /* Gain threshold for enabling the prefilter/postfilter */ + pf_threshold = QCONST16(.2f,15); + + /* Adjusting the threshold based on rate and continuity */ + if (abs(pitch_index-st->prefilter_period)*10>pitch_index) + pf_threshold += QCONST16(.2f,15); + if (nbAvailableBytes<25) + pf_threshold += QCONST16(.1f,15); + if (nbAvailableBytes<35) + pf_threshold += QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.4f,15)) + pf_threshold -= QCONST16(.1f,15); + if (st->prefilter_gain > QCONST16(.55f,15)) + pf_threshold -= QCONST16(.1f,15); + + /* Hard threshold at 0.2 */ + pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15)); + if (gain1prefilter_gain)prefilter_gain; + +#ifdef FIXED_POINT + qg = ((gain1+1536)>>10)/3-1; +#else + qg = (int)floor(.5f+gain1*32/3)-1; +#endif + qg = IMAX(0, IMIN(7, qg)); + gain1 = QCONST16(0.09375f,15)*(qg+1); + pf_on = 1; + } + /*printf("%d %f\n", pitch_index, gain1);*/ + + c=0; do { + int offset = mode->shortMdctSize-overlap; + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + OPUS_COPY(in+c*(N+overlap), st->in_mem+c*(overlap), overlap); + if (offset) + comb_filter(in+c*(N+overlap)+overlap, pre[c]+COMBFILTER_MAXPERIOD, + st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain, + st->prefilter_tapset, st->prefilter_tapset, NULL, 0, st->arch); + + comb_filter(in+c*(N+overlap)+overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset, + st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1, + st->prefilter_tapset, prefilter_tapset, mode->window, overlap, st->arch); + OPUS_COPY(st->in_mem+c*(overlap), in+c*(N+overlap)+N, overlap); + + if (N>COMBFILTER_MAXPERIOD) + { + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD); + } else { + OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N); + OPUS_COPY(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N); + } + } while (++cnbEBands; + eBands = mode->eBands; + + coded_bands = lastCodedBands ? lastCodedBands : nbEBands; + coded_bins = eBands[coded_bands]<analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/ +#ifndef DISABLE_FLOAT_API + if (analysis->valid && analysis->activity<.4) + target -= (opus_int32)((coded_bins<activity)); +#endif + /* Stereo savings */ + if (C==2) + { + int coded_stereo_bands; + int coded_stereo_dof; + opus_val16 max_frac; + coded_stereo_bands = IMIN(intensity, coded_bands); + coded_stereo_dof = (eBands[coded_stereo_bands]<valid && !lfe) + { + opus_int32 tonal_target; + float tonal; + + /* Tonality boost (compensating for the average). */ + tonal = MAX16(0.f,analysis->tonality-.15f)-0.12f; + tonal_target = target + (opus_int32)((coded_bins<tonality, tonal);*/ + target = tonal_target; + } +#else + (void)analysis; + (void)pitch_change; +#endif + + if (has_surround_mask&&!lfe) + { + opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(surround_masking,coded_bins<end, st->intensity, surround_target, target, st->bitrate);*/ + target = IMAX(target/4, surround_target); + } + + { + opus_int32 floor_depth; + int bins; + bins = eBands[nbEBands-2]<>2); + target = IMIN(target, floor_depth); + /*printf("%f %d\n", maxDepth, floor_depth);*/ + } + + /* Make VBR less aggressive for constrained VBR because we can't keep a higher bitrate + for long. Needs tuning. */ + if ((!has_surround_mask||lfe) && constrained_vbr) + { + target = base_target + (opus_int32)MULT16_32_Q15(QCONST16(0.67f, 15), target-base_target); + } + + if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14)) + { + opus_val16 amount; + opus_val16 tvbr_factor; + amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate))); + tvbr_factor = SHR32(MULT16_16(temporal_vbr, amount), DB_SHIFT); + target += (opus_int32)MULT16_32_Q15(tvbr_factor, target); + } + + /* Don't allow more than doubling the rate */ + target = IMIN(2*base_target, target); + + return target; +} + +int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) +{ + int i, c, N; + opus_int32 bits; + ec_enc _enc; + VARDECL(celt_sig, in); + VARDECL(celt_sig, freq); + VARDECL(celt_norm, X); + VARDECL(celt_ener, bandE); + VARDECL(opus_val16, bandLogE); + VARDECL(opus_val16, bandLogE2); + VARDECL(int, fine_quant); + VARDECL(opus_val16, error); + VARDECL(int, pulses); + VARDECL(int, cap); + VARDECL(int, offsets); + VARDECL(int, importance); + VARDECL(int, spread_weight); + VARDECL(int, fine_priority); + VARDECL(int, tf_res); + VARDECL(unsigned char, collapse_masks); + celt_sig *prefilter_mem; + opus_val16 *oldBandE, *oldLogE, *oldLogE2, *energyError; + int shortBlocks=0; + int isTransient=0; + const int CC = st->channels; + const int C = st->stream_channels; + int LM, M; + int tf_select; + int nbFilledBytes, nbAvailableBytes; + int start; + int end; + int effEnd; + int codedBands; + int alloc_trim; + int pitch_index=COMBFILTER_MINPERIOD; + opus_val16 gain1 = 0; + int dual_stereo=0; + int effectiveBytes; + int dynalloc_logp; + opus_int32 vbr_rate; + opus_int32 total_bits; + opus_int32 total_boost; + opus_int32 balance; + opus_int32 tell; + opus_int32 tell0_frac; + int prefilter_tapset=0; + int pf_on; + int anti_collapse_rsv; + int anti_collapse_on=0; + int silence=0; + int tf_chan = 0; + opus_val16 tf_estimate; + int pitch_change=0; + opus_int32 tot_boost; + opus_val32 sample_max; + opus_val16 maxDepth; + const OpusCustomMode *mode; + int nbEBands; + int overlap; + const opus_int16 *eBands; + int secondMdct; + int signalBandwidth; + int transient_got_disabled=0; + opus_val16 surround_masking=0; + opus_val16 temporal_vbr=0; + opus_val16 surround_trim = 0; + opus_int32 equiv_rate; + int hybrid; + int weak_transient = 0; + int enable_tf_analysis; + VARDECL(opus_val16, surround_dynalloc); + ALLOC_STACK; + + mode = st->mode; + nbEBands = mode->nbEBands; + overlap = mode->overlap; + eBands = mode->eBands; + start = st->start; + end = st->end; + hybrid = start != 0; + tf_estimate = 0; + if (nbCompressedBytes<2 || pcm==NULL) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + frame_size *= st->upsample; + for (LM=0;LM<=mode->maxLM;LM++) + if (mode->shortMdctSize<mode->maxLM) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + M=1<shortMdctSize; + + prefilter_mem = st->in_mem+CC*(overlap); + oldBandE = (opus_val16*)(st->in_mem+CC*(overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + CC*nbEBands; + oldLogE2 = oldLogE + CC*nbEBands; + energyError = oldLogE2 + CC*nbEBands; + + if (enc==NULL) + { + tell0_frac=tell=1; + nbFilledBytes=0; + } else { + tell0_frac=ec_tell_frac(enc); + tell=ec_tell(enc); + nbFilledBytes=(tell+4)>>3; + } + +#ifdef CUSTOM_MODES + if (st->signalling && enc==NULL) + { + int tmp = (mode->effEBands-end)>>1; + end = st->end = IMAX(1, mode->effEBands-tmp); + compressed[0] = tmp<<5; + compressed[0] |= LM<<3; + compressed[0] |= (C==2)<<2; + /* Convert "standard mode" to Opus header */ + if (mode->Fs==48000 && mode->shortMdctSize==120) + { + int c0 = toOpus(compressed[0]); + if (c0<0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + compressed[0] = c0; + } + compressed++; + nbCompressedBytes--; + } +#else + celt_assert(st->signalling==0); +#endif + + /* Can't produce more than 1275 output bytes */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275); + nbAvailableBytes = nbCompressedBytes - nbFilledBytes; + + if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX) + { + opus_int32 den=mode->Fs>>BITRES; + vbr_rate=(st->bitrate*frame_size+(den>>1))/den; +#ifdef CUSTOM_MODES + if (st->signalling) + vbr_rate -= 8<>(3+BITRES); + } else { + opus_int32 tmp; + vbr_rate = 0; + tmp = st->bitrate*frame_size; + if (tell>1) + tmp += tell; + if (st->bitrate!=OPUS_BITRATE_MAX) + nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes, + (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling)); + effectiveBytes = nbCompressedBytes - nbFilledBytes; + } + equiv_rate = ((opus_int32)nbCompressedBytes*8*50 >> (3-LM)) - (40*C+20)*((400>>LM) - 50); + if (st->bitrate != OPUS_BITRATE_MAX) + equiv_rate = IMIN(equiv_rate, st->bitrate - (40*C+20)*((400>>LM) - 50)); + + if (enc==NULL) + { + ec_enc_init(&_enc, compressed, nbCompressedBytes); + enc = &_enc; + } + + if (vbr_rate>0) + { + /* Computes the max bit-rate allowed in VBR mode to avoid violating the + target rate and buffering. + We must do this up front so that bust-prevention logic triggers + correctly if we don't have enough bits. */ + if (st->constrained_vbr) + { + opus_int32 vbr_bound; + opus_int32 max_allowed; + /* We could use any multiple of vbr_rate as bound (depending on the + delay). + This is clamped to ensure we use at least two bytes if the encoder + was entirely empty, but to allow 0 in hybrid mode. */ + vbr_bound = vbr_rate; + max_allowed = IMIN(IMAX(tell==1?2:0, + (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)), + nbAvailableBytes); + if(max_allowed < nbAvailableBytes) + { + nbCompressedBytes = nbFilledBytes+max_allowed; + nbAvailableBytes = max_allowed; + ec_enc_shrink(enc, nbCompressedBytes); + } + } + } + total_bits = nbCompressedBytes*8; + + effEnd = end; + if (effEnd > mode->effEBands) + effEnd = mode->effEBands; + + ALLOC(in, CC*(N+overlap), celt_sig); + + sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample)); + st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample); + sample_max=MAX32(sample_max, st->overlap_max); +#ifdef FIXED_POINT + silence = (sample_max==0); +#else + silence = (sample_max <= (opus_val16)1/(1<lsb_depth)); +#endif +#ifdef FUZZING + if ((rand()&0x3F)==0) + silence = 1; +#endif + if (tell==1) + ec_enc_bit_logp(enc, silence, 15); + else + silence=0; + if (silence) + { + /*In VBR mode there is no need to send more than the minimum. */ + if (vbr_rate>0) + { + effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2); + total_bits=nbCompressedBytes*8; + nbAvailableBytes=2; + ec_enc_shrink(enc, nbCompressedBytes); + } + /* Pretend we've filled all the remaining bits with zeros + (that's what the initialiser did anyway) */ + tell = nbCompressedBytes*8; + enc->nbits_total+=tell-ec_tell(enc); + } + c=0; do { + int need_clip=0; +#ifndef FIXED_POINT + need_clip = st->clip && sample_max>65536.f; +#endif + celt_preemphasis(pcm+c, in+c*(N+overlap)+overlap, N, CC, st->upsample, + mode->preemph, st->preemph_memE+c, need_clip); + } while (++clfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && !hybrid && !silence && !st->disable_pf + && st->complexity >= 5; + + prefilter_tapset = st->tapset_decision; + pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes, &st->analysis); + if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3) + && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period)) + pitch_change = 1; + if (pf_on==0) + { + if(!hybrid && tell+16<=total_bits) + ec_enc_bit_logp(enc, 0, 1); + } else { + /*This block is not gated by a total bits check only because + of the nbAvailableBytes check above.*/ + int octave; + ec_enc_bit_logp(enc, 1, 1); + pitch_index += 1; + octave = EC_ILOG(pitch_index)-5; + ec_enc_uint(enc, octave, 6); + ec_enc_bits(enc, pitch_index-(16<complexity >= 1 && !st->lfe) + { + /* Reduces the likelihood of energy instability on fricatives at low bitrate + in hybrid mode. It seems like we still want to have real transients on vowels + though (small SILK quantization offset value). */ + int allow_weak_transients = hybrid && effectiveBytes<15 && st->silk_info.signalType != 2; + isTransient = transient_analysis(in, N+overlap, CC, + &tf_estimate, &tf_chan, allow_weak_transients, &weak_transient); + } + if (LM>0 && ec_tell(enc)+3<=total_bits) + { + if (isTransient) + shortBlocks = M; + } else { + isTransient = 0; + transient_got_disabled=1; + } + + ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */ + ALLOC(bandE,nbEBands*CC, celt_ener); + ALLOC(bandLogE,nbEBands*CC, opus_val16); + + secondMdct = shortBlocks && st->complexity>=8; + ALLOC(bandLogE2, C*nbEBands, opus_val16); + if (secondMdct) + { + compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE2, C); + for (i=0;iupsample, st->arch); + /* This should catch any NaN in the CELT input. Since we're not supposed to see any (they're filtered + at the Opus layer), just abort. */ + celt_assert(!celt_isnan(freq[0]) && (C==1 || !celt_isnan(freq[N]))); + if (CC==2&&C==1) + tf_chan = 0; + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + + if (st->lfe) + { + for (i=2;ienergy_mask&&!st->lfe) + { + int mask_end; + int midband; + int count_dynalloc; + opus_val32 mask_avg=0; + opus_val32 diff=0; + int count=0; + mask_end = IMAX(2,st->lastCodedBands); + for (c=0;cenergy_mask[nbEBands*c+i], + QCONST16(.25f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_avg += MULT16_16(mask, eBands[i+1]-eBands[i]); + count += eBands[i+1]-eBands[i]; + diff += MULT16_16(mask, 1+2*i-mask_end); + } + } + celt_assert(count>0); + mask_avg = DIV32_16(mask_avg,count); + mask_avg += QCONST16(.2f, DB_SHIFT); + diff = diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end); + /* Again, being conservative */ + diff = HALF32(diff); + diff = MAX32(MIN32(diff, QCONST32(.031f, DB_SHIFT)), -QCONST32(.031f, DB_SHIFT)); + /* Find the band that's in the middle of the coded spectrum */ + for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++); + count_dynalloc=0; + for(i=0;ienergy_mask[i], st->energy_mask[nbEBands+i]); + else + unmask = st->energy_mask[i]; + unmask = MIN16(unmask, QCONST16(.0f, DB_SHIFT)); + unmask -= lin; + if (unmask > QCONST16(.25f, DB_SHIFT)) + { + surround_dynalloc[i] = unmask - QCONST16(.25f, DB_SHIFT); + count_dynalloc++; + } + } + if (count_dynalloc>=3) + { + /* If we need dynalloc in many bands, it's probably because our + initial masking rate was too low. */ + mask_avg += QCONST16(.25f, DB_SHIFT); + if (mask_avg>0) + { + /* Something went really wrong in the original calculations, + disabling masking. */ + mask_avg = 0; + diff = 0; + OPUS_CLEAR(surround_dynalloc, mask_end); + } else { + for(i=0;ilfe) + { + opus_val16 follow=-QCONST16(10.0f,DB_SHIFT); + opus_val32 frame_avg=0; + opus_val16 offset = shortBlocks?HALF16(SHL16(LM, DB_SHIFT)):0; + for(i=start;ispec_avg); + temporal_vbr = MIN16(QCONST16(3.f, DB_SHIFT), MAX16(-QCONST16(1.5f, DB_SHIFT), temporal_vbr)); + st->spec_avg += MULT16_16_Q15(QCONST16(.02f, 15), temporal_vbr); + } + /*for (i=0;i<21;i++) + printf("%f ", bandLogE[i]); + printf("\n");*/ + + if (!secondMdct) + { + OPUS_COPY(bandLogE2, bandLogE, C*nbEBands); + } + + /* Last chance to catch any transient we might have missed in the + time-domain analysis */ + if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe && !hybrid) + { + if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C)) + { + isTransient = 1; + shortBlocks = M; + compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch); + compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch); + amp2Log2(mode, effEnd, end, bandE, bandLogE, C); + /* Compensate for the scaling of short vs long mdcts */ + for (i=0;i0 && ec_tell(enc)+3<=total_bits) + ec_enc_bit_logp(enc, isTransient, 3); + + ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */ + + /* Band normalisation */ + normalise_bands(mode, freq, X, bandE, effEnd, C, M); + + enable_tf_analysis = effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe; + + ALLOC(offsets, nbEBands, int); + ALLOC(importance, nbEBands, int); + ALLOC(spread_weight, nbEBands, int); + + maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets, + st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr, + eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis, importance, spread_weight); + + ALLOC(tf_res, nbEBands, int); + /* Disable variable tf resolution for hybrid and at very low bitrate */ + if (enable_tf_analysis) + { + int lambda; + lambda = IMAX(80, 20480/effectiveBytes + 2); + tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan, importance); + for (i=effEnd;isilk_info.signalType != 2) + { + /* For low bitrate hybrid, we force temporal resolution to 5 ms rather than 2.5 ms. */ + for (i=0;iforce_intra, + &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe); + + tf_encode(start, end, isTransient, tf_res, LM, tf_select, enc); + + if (ec_tell(enc)+4<=total_bits) + { + if (st->lfe) + { + st->tapset_decision = 0; + st->spread_decision = SPREAD_NORMAL; + } else if (hybrid) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else if (isTransient) + st->spread_decision = SPREAD_NORMAL; + else + st->spread_decision = SPREAD_AGGRESSIVE; + } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C) + { + if (st->complexity == 0) + st->spread_decision = SPREAD_NONE; + else + st->spread_decision = SPREAD_NORMAL; + } else { + /* Disable new spreading+tapset estimator until we can show it works + better than the old one. So far it seems like spreading_decision() + works best. */ +#if 0 + if (st->analysis.valid) + { + static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)}; + static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)}; + static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)}; + static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)}; + st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision); + st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision); + } else +#endif + { + st->spread_decision = spreading_decision(mode, X, + &st->tonal_average, st->spread_decision, &st->hf_average, + &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M, spread_weight); + } + /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/ + /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/ + } + ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5); + } + + /* For LFE, everything interesting is in the first band */ + if (st->lfe) + offsets[0] = IMIN(8, effectiveBytes/3); + ALLOC(cap, nbEBands, int); + init_caps(mode,cap,LM,C); + + dynalloc_logp = 6; + total_bits<<=BITRES; + total_boost = 0; + tell = ec_tell_frac(enc); + for (i=start;iintensity = hysteresis_decision((opus_val16)(equiv_rate/1000), + intensity_thresholds, intensity_histeresis, 21, st->intensity); + st->intensity = IMIN(end,IMAX(start, st->intensity)); + } + + alloc_trim = 5; + if (tell+(6< 0 || st->lfe) + { + st->stereo_saving = 0; + alloc_trim = 5; + } else { + alloc_trim = alloc_trim_analysis(mode, X, bandLogE, + end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate, + st->intensity, surround_trim, equiv_rate, st->arch); + } + ec_enc_icdf(enc, alloc_trim, trim_icdf, 7); + tell = ec_tell_frac(enc); + } + + /* Variable bitrate */ + if (vbr_rate>0) + { + opus_val16 alpha; + opus_int32 delta; + /* The target rate in 8th bits per frame */ + opus_int32 target, base_target; + opus_int32 min_allowed; + int lm_diff = mode->maxLM - LM; + + /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms. + The CELT allocator will just not be able to use more than that anyway. */ + nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM)); + if (!hybrid) + { + base_target = vbr_rate - ((40*C+20)<constrained_vbr) + base_target += (st->vbr_offset>>lm_diff); + + if (!hybrid) + { + target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate, + st->lastCodedBands, C, st->intensity, st->constrained_vbr, + st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth, + st->lfe, st->energy_mask!=NULL, surround_masking, + temporal_vbr); + } else { + target = base_target; + /* Tonal frames (offset<100) need more bits than noisy (offset>100) ones. */ + if (st->silk_info.offset < 100) target += 12 << BITRES >> (3-LM); + if (st->silk_info.offset > 100) target -= 18 << BITRES >> (3-LM); + /* Boosting bitrate on transients and vowels with significant temporal + spikes. */ + target += (opus_int32)MULT16_16_Q14(tf_estimate-QCONST16(.25f,14), (50< QCONST16(.7f,14)) + target = IMAX(target, 50<>(BITRES+3)) + 2; + /* Take into account the 37 bits we need to have left in the packet to + signal a redundant frame in hybrid mode. Creating a shorter packet would + create an entropy coder desync. */ + if (hybrid) + min_allowed = IMAX(min_allowed, (tell0_frac+(37<>(BITRES+3)); + + nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3); + nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes); + nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + + /* By how much did we "miss" the target on that frame */ + delta = target - vbr_rate; + + target=nbAvailableBytes<<(BITRES+3); + + /*If the frame is silent we don't adjust our drift, otherwise + the encoder will shoot to very high rates after hitting a + span of silence, but we do allow the bitres to refill. + This means that we'll undershoot our target in CVBR/VBR modes + on files with lots of silence. */ + if(silence) + { + nbAvailableBytes = 2; + target = 2*8<vbr_count < 970) + { + st->vbr_count++; + alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16)); + } else + alpha = QCONST16(.001f,15); + /* How many bits have we used in excess of what we're allowed */ + if (st->constrained_vbr) + st->vbr_reservoir += target - vbr_rate; + /*printf ("%d\n", st->vbr_reservoir);*/ + + /* Compute the offset we need to apply in order to reach the target */ + if (st->constrained_vbr) + { + st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<vbr_offset-st->vbr_drift); + st->vbr_offset = -st->vbr_drift; + } + /*printf ("%d\n", st->vbr_drift);*/ + + if (st->constrained_vbr && st->vbr_reservoir < 0) + { + /* We're under the min value -- increase rate */ + int adjust = (-st->vbr_reservoir)/(8<vbr_reservoir = 0; + /*printf ("+%d\n", adjust);*/ + } + nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes); + /*printf("%d\n", nbCompressedBytes*50*8);*/ + /* This moves the raw bits to take into account the new compressed size */ + ec_enc_shrink(enc, nbCompressedBytes); + } + + /* Bit allocation */ + ALLOC(fine_quant, nbEBands, int); + ALLOC(pulses, nbEBands, int); + ALLOC(fine_priority, nbEBands, int); + + /* bits = packet size - where we are - safety*/ + bits = (((opus_int32)nbCompressedBytes*8)<=2&&bits>=((LM+2)<analysis.valid) + { + int min_bandwidth; + if (equiv_rate < (opus_int32)32000*C) + min_bandwidth = 13; + else if (equiv_rate < (opus_int32)48000*C) + min_bandwidth = 16; + else if (equiv_rate < (opus_int32)60000*C) + min_bandwidth = 18; + else if (equiv_rate < (opus_int32)80000*C) + min_bandwidth = 19; + else + min_bandwidth = 20; + signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth); + } +#endif + if (st->lfe) + signalBandwidth = 1; + codedBands = clt_compute_allocation(mode, start, end, offsets, cap, + alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses, + fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth); + if (st->lastCodedBands) + st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands)); + else + st->lastCodedBands = codedBands; + + quant_fine_energy(mode, start, end, oldBandE, error, fine_quant, enc, C); + + /* Residual quantisation */ + ALLOC(collapse_masks, C*nbEBands, unsigned char); + quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks, + bandE, pulses, shortBlocks, st->spread_decision, + dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<rng, st->complexity, st->arch, st->disable_inv); + + if (anti_collapse_rsv > 0) + { + anti_collapse_on = st->consec_transient<2; +#ifdef FUZZING + anti_collapse_on = rand()&0x1; +#endif + ec_enc_bits(enc, anti_collapse_on, 1); + } + quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C); + OPUS_CLEAR(energyError, nbEBands*CC); + c=0; + do { + for (i=start;irng); + } + + c=0; do { + OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, 2*MAX_PERIOD-N+overlap/2); + } while (++csyn_mem[c]+2*MAX_PERIOD-N; + } while (++cupsample, silence, st->arch); + + c=0; do { + st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD); + st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD); + comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize, + st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset, + mode->window, overlap); + if (LM!=0) + comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize, + st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset, + mode->window, overlap); + } while (++cupsample, mode->preemph, st->preemph_memD); + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + st->prefilter_period = pitch_index; + st->prefilter_gain = gain1; + st->prefilter_tapset = prefilter_tapset; +#ifdef RESYNTH + if (LM!=0) + { + st->prefilter_period_old = st->prefilter_period; + st->prefilter_gain_old = st->prefilter_gain; + st->prefilter_tapset_old = st->prefilter_tapset; + } +#endif + + if (CC==2&&C==1) { + OPUS_COPY(&oldBandE[nbEBands], oldBandE, nbEBands); + } + + if (!isTransient) + { + OPUS_COPY(oldLogE2, oldLogE, CC*nbEBands); + OPUS_COPY(oldLogE, oldBandE, CC*nbEBands); + } else { + for (i=0;iconsec_transient++; + else + st->consec_transient=0; + st->rng = enc->rng; + + /* If there's any room left (can only happen for very high rates), + it's already filled with zeros */ + ec_enc_done(enc); + +#ifdef CUSTOM_MODES + if (st->signalling) + nbCompressedBytes++; +#endif + + RESTORE_STACK; + if (ec_get_error(enc)) + return OPUS_INTERNAL_ERROR; + else + return nbCompressedBytes; +} + + +#ifdef CUSTOM_MODES + +#ifdef FIXED_POINT +int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL); +} + +#ifndef DISABLE_FLOAT_API +int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) +{ + int j, ret, C, N; + VARDECL(opus_int16, in); + ALLOC_STACK; + + if (pcm==NULL) + return OPUS_BAD_ARG; + + C = st->channels; + N = frame_size; + ALLOC(in, C*N, opus_int16); + + for (j=0;jchannels; + N=frame_size; + ALLOC(in, C*N, celt_sig); + for (j=0;j10) + goto bad_arg; + st->complexity = value; + } + break; + case CELT_SET_START_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<0 || value>=st->mode->nbEBands) + goto bad_arg; + st->start = value; + } + break; + case CELT_SET_END_BAND_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>st->mode->nbEBands) + goto bad_arg; + st->end = value; + } + break; + case CELT_SET_PREDICTION_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>2) + goto bad_arg; + st->disable_pf = value<=1; + st->force_intra = value==0; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + int value = va_arg(ap, opus_int32); + if (value<0 || value>100) + goto bad_arg; + st->loss_rate = value; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->constrained_vbr = value; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->vbr = value; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<=500 && value!=OPUS_BITRATE_MAX) + goto bad_arg; + value = IMIN(value, 260000*st->channels); + st->bitrate = value; + } + break; + case CELT_SET_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<1 || value>2) + goto bad_arg; + st->stream_channels = value; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + goto bad_arg; + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + *value=st->lsb_depth; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->disable_inv = value; + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->disable_inv; + } + break; + case OPUS_RESET_STATE: + { + int i; + opus_val16 *oldBandE, *oldLogE, *oldLogE2; + oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->mode->overlap+COMBFILTER_MAXPERIOD)); + oldLogE = oldBandE + st->channels*st->mode->nbEBands; + oldLogE2 = oldLogE + st->channels*st->mode->nbEBands; + OPUS_CLEAR((char*)&st->ENCODER_RESET_START, + opus_custom_encoder_get_size(st->mode, st->channels)- + ((char*)&st->ENCODER_RESET_START - (char*)st)); + for (i=0;ichannels*st->mode->nbEBands;i++) + oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT); + st->vbr_offset = 0; + st->delayedIntra = 1; + st->spread_decision = SPREAD_NORMAL; + st->tonal_average = 256; + st->hf_average = 0; + st->tapset_decision = 0; + } + break; +#ifdef CUSTOM_MODES + case CELT_SET_INPUT_CLIPPING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->clip = value; + } + break; +#endif + case CELT_SET_SIGNALLING_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->signalling = value; + } + break; + case CELT_SET_ANALYSIS_REQUEST: + { + AnalysisInfo *info = va_arg(ap, AnalysisInfo *); + if (info) + OPUS_COPY(&st->analysis, info, 1); + } + break; + case CELT_SET_SILK_INFO_REQUEST: + { + SILKInfo *info = va_arg(ap, SILKInfo *); + if (info) + OPUS_COPY(&st->silk_info, info, 1); + } + break; + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (value==0) + goto bad_arg; + *value=st->mode; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 * value = va_arg(ap, opus_uint32 *); + if (value==0) + goto bad_arg; + *value=st->rng; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_mask = value; + } + break; + default: + goto bad_request; + } + va_end(ap); + return OPUS_OK; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +bad_request: + va_end(ap); + return OPUS_UNIMPLEMENTED; +} diff --git a/src/libopus/celt/celt_lpc.c b/src/libopus/celt/celt_lpc.c new file mode 100644 index 00000000..2b3c7844 --- /dev/null +++ b/src/libopus/celt/celt_lpc.c @@ -0,0 +1,296 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "celt_lpc.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "pitch.h" + +void _celt_lpc( + opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */ +const opus_val32 *ac, /* in: [0...p] autocorrelation values */ +int p +) +{ + int i, j; + opus_val32 r; + opus_val32 error = ac[0]; +#ifdef FIXED_POINT + opus_val32 lpc[LPC_ORDER]; +#else + float *lpc = _lpc; +#endif + + OPUS_CLEAR(lpc, p); + if (ac[0] != 0) + { + for (i = 0; i < p; i++) { + /* Sum up this iteration's reflection coefficient */ + opus_val32 rr = 0; + for (j = 0; j < i; j++) + rr += MULT32_32_Q31(lpc[j],ac[i - j]); + rr += SHR32(ac[i + 1],3); + r = -frac_div32(SHL32(rr,3), error); + /* Update LPC coefficients and total error */ + lpc[i] = SHR32(r,3); + for (j = 0; j < (i+1)>>1; j++) + { + opus_val32 tmp1, tmp2; + tmp1 = lpc[j]; + tmp2 = lpc[i-1-j]; + lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2); + lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1); + } + + error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error); + /* Bail out once we get 30 dB gain */ +#ifdef FIXED_POINT + if (error=1;j--) + { + mem[j]=mem[j-1]; + } + mem[0] = SROUND16(sum, SIG_SHIFT); + _y[i] = sum; + } +#else + int i,j; + VARDECL(opus_val16, rden); + VARDECL(opus_val16, y); + SAVE_STACK; + + celt_assert((ord&3)==0); + ALLOC(rden, ord, opus_val16); + ALLOC(y, N+ord, opus_val16); + for(i=0;i0); + celt_assert(overlap>=0); + if (overlap == 0) + { + xptr = x; + } else { + for (i=0;i0) + { + for(i=0;i= 536870912) + { + int shift2=1; + if (ac[0] >= 1073741824) + shift2++; + for (i=0;i<=lag;i++) + ac[i] = SHR32(ac[i], shift2); + shift += shift2; + } +#endif + + RESTORE_STACK; + return shift; +} diff --git a/src/libopus/celt/celt_lpc.h b/src/libopus/celt/celt_lpc.h new file mode 100644 index 00000000..a4c5fd6e --- /dev/null +++ b/src/libopus/celt/celt_lpc.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2009-2010 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PLC_H +#define PLC_H + +#include "arch.h" +#include "cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/celt_lpc_sse.h" +#endif + +#define LPC_ORDER 24 + +void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p); + +void celt_fir_c( + const opus_val16 *x, + const opus_val16 *num, + opus_val16 *y, + int N, + int ord, + int arch); + +#if !defined(OVERRIDE_CELT_FIR) +#define celt_fir(x, num, y, N, ord, arch) \ + (celt_fir_c(x, num, y, N, ord, arch)) +#endif + +void celt_iir(const opus_val32 *x, + const opus_val16 *den, + opus_val32 *y, + int N, + int ord, + opus_val16 *mem, + int arch); + +int _celt_autocorr(const opus_val16 *x, opus_val32 *ac, + const opus_val16 *window, int overlap, int lag, int n, int arch); + +#endif /* PLC_H */ diff --git a/src/libopus/celt/cpu_support.h b/src/libopus/celt/cpu_support.h new file mode 100644 index 00000000..944e50d5 --- /dev/null +++ b/src/libopus/celt/cpu_support.h @@ -0,0 +1,70 @@ +/* Copyright (c) 2010 Xiph.Org Foundation + * Copyright (c) 2013 Parrot */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CPU_SUPPORT_H +#define CPU_SUPPORT_H + +#include "../opus_types.h" +#include "../opus_defines.h" + +#if defined(OPUS_HAVE_RTCD) && \ + (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/armcpu.h" + +/* We currently support 4 ARM variants: + * arch[0] -> ARMv4 + * arch[1] -> ARMv5E + * arch[2] -> ARMv6 + * arch[3] -> NEON + */ +#define OPUS_ARCHMASK 3 + +#elif (defined(OPUS_X86_MAY_HAVE_SSE) && !defined(OPUS_X86_PRESUME_SSE)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)) || \ + (defined(OPUS_X86_MAY_HAVE_SSE4_1) && !defined(OPUS_X86_PRESUME_SSE4_1)) || \ + (defined(OPUS_X86_MAY_HAVE_AVX) && !defined(OPUS_X86_PRESUME_AVX)) + +#include "x86/x86cpu.h" +/* We currently support 5 x86 variants: + * arch[0] -> non-sse + * arch[1] -> sse + * arch[2] -> sse2 + * arch[3] -> sse4.1 + * arch[4] -> avx + */ +#define OPUS_ARCHMASK 7 +int opus_select_arch(void); + +#else +#define OPUS_ARCHMASK 0 + +static OPUS_INLINE int opus_select_arch(void) +{ + return 0; +} +#endif +#endif diff --git a/src/libopus/celt/cwrs.c b/src/libopus/celt/cwrs.c new file mode 100644 index 00000000..402553dd --- /dev/null +++ b/src/libopus/celt/cwrs.c @@ -0,0 +1,716 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "os_support.h" +#include "cwrs.h" +#include "mathops.h" +#include "arch.h" +#include + +#ifdef CUSTOM_MODES + +/*Guaranteed to return a conservatively large estimate of the binary logarithm + with frac bits of fractional precision. + Tested for all possible 32-bit inputs with frac=4, where the maximum + overestimation is 0.06254243 bits.*/ +int log2_frac(opus_uint32 val, int frac) +{ + int l; + l=EC_ILOG(val); + if(val&(val-1)){ + /*This is (val>>l-16), but guaranteed to round up, even if adding a bias + before the shift would cause overflow (e.g., for 0xFFFFxxxx). + Doesn't work for val=0, but that case fails the test above.*/ + if(l>16)val=((val-1)>>(l-16))+1; + else val<<=16-l; + l=(l-1)<>16); + l+=b<>b; + val=(val*val+0x7FFF)>>15; + } + while(frac-->0); + /*If val is not exactly 0x8000, then we have to round up the remainder.*/ + return l+(val>0x8000); + } + /*Exact powers of two require no rounding.*/ + else return (l-1)<0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1, + where choose() is the binomial function. + A table of values for N<10 and K<10 looks like: + V[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1, 2, 2, 2, 2, 2, 2, 2, 2, 2}, + {1, 4, 8, 12, 16, 20, 24, 28, 32, 36}, + {1, 6, 18, 38, 66, 102, 146, 198, 258, 326}, + {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992}, + {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290}, + {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436}, + {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598}, + {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688}, + {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146} + }; + + U(N,K) = the number of such combinations wherein N-1 objects are taken at + most K-1 at a time. + This is given by + U(N,K) = sum(k=0...K-1,V(N-1,k)) + = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0. + The latter expression also makes clear that U(N,K) is half the number of such + combinations wherein the first object is taken at least once. + Although it may not be clear from either of these definitions, U(N,K) is the + natural function to work with when enumerating the pulse vector codebooks, + not V(N,K). + U(N,K) is not well-defined for N=0, but with the extension + U(0,K) = K>0 ? 0 : 1, + the function becomes symmetric: U(N,K) = U(K,N), with a similar table: + U[10][10] = { + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 1, 1, 1, 1, 1, 1, 1, 1, 1}, + {0, 1, 3, 5, 7, 9, 11, 13, 15, 17}, + {0, 1, 5, 13, 25, 41, 61, 85, 113, 145}, + {0, 1, 7, 25, 63, 129, 231, 377, 575, 833}, + {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649}, + {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073}, + {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081}, + {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545}, + {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729} + }; + + With this extension, V(N,K) may be written in terms of U(N,K): + V(N,K) = U(N,K) + U(N,K+1) + for all N>=0, K>=0. + Thus U(N,K+1) represents the number of combinations where the first element + is positive or zero, and U(N,K) represents the number of combinations where + it is negative. + With a large enough table of U(N,K) values, we could write O(N) encoding + and O(min(N*log(K),N+K)) decoding routines, but such a table would be + prohibitively large for small embedded devices (K may be as large as 32767 + for small N, and N may be as large as 200). + + Both functions obey the same recurrence relation: + V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1), + U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1), + for all N>0, K>0, with different initial conditions at N=0 or K=0. + This allows us to construct a row of one of the tables above given the + previous row or the next row. + Thus we can derive O(NK) encoding and decoding routines with O(K) memory + using only addition and subtraction. + + When encoding, we build up from the U(2,K) row and work our way forwards. + When decoding, we need to start at the U(N,K) row and work our way backwards, + which requires a means of computing U(N,K). + U(N,K) may be computed from two previous values with the same N: + U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2) + for all N>1, and since U(N,K) is symmetric, a similar relation holds for two + previous values with the same K: + U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K) + for all K>1. + This allows us to construct an arbitrary row of the U(N,K) table by starting + with the first two values, which are constants. + This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K) + multiplications. + Similar relations can be derived for V(N,K), but are not used here. + + For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree + polynomial for fixed N. + The first few are + U(1,K) = 1, + U(2,K) = 2*K-1, + U(3,K) = (2*K-2)*K+1, + U(4,K) = (((4*K-6)*K+8)*K-3)/3, + U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3, + and + V(1,K) = 2, + V(2,K) = 4*K, + V(3,K) = 4*K*K+2, + V(4,K) = 8*(K*K+2)*K/3, + V(5,K) = ((4*K*K+20)*K*K+6)/3, + for all K>0. + This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for + small N (and indeed decoding is also O(N) for N<3). + + @ARTICLE{Fis86, + author="Thomas R. Fischer", + title="A Pyramid Vector Quantizer", + journal="IEEE Transactions on Information Theory", + volume="IT-32", + number=4, + pages="568--583", + month=Jul, + year=1986 + }*/ + +#if !defined(SMALL_FOOTPRINT) + +/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/ +# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)]) +/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N + with K pulses allocated to it.*/ +# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1)) + +/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)). + Thus, the number of entries in row I is the larger of the maximum number of + pulses we will ever allocate for a given N=I (K=128, or however many fit in + 32 bits, whichever is smaller), plus one, and the maximum N for which + K=I-1 pulses fit in 32 bits. + The largest band size in an Opus Custom mode is 208. + Otherwise, we can limit things to the set of N which can be achieved by + splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48, + 44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/ +#if defined(CUSTOM_MODES) +static const opus_uint32 CELT_PVQ_U_DATA[1488] PROGMEM ={ +#else +static const opus_uint32 CELT_PVQ_U_DATA[1272] PROGMEM ={ +#endif + /*N=0, K=0...176:*/ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +#if defined(CUSTOM_MODES) + /*...208:*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, +#endif + /*N=1, K=1...176:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +#if defined(CUSTOM_MODES) + /*...208:*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, +#endif + /*N=2, K=2...176:*/ + 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, + 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, + 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, + 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, + 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, + 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, + 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, + 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, + 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293, + 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323, + 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351, +#if defined(CUSTOM_MODES) + /*...208:*/ + 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381, + 383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411, + 413, 415, +#endif + /*N=3, K=3...176:*/ + 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613, + 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861, + 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785, + 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385, + 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661, + 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961, + 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745, + 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013, + 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765, + 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001, + 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721, + 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925, + 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613, + 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785, + 57461, 58141, 58825, 59513, 60205, 60901, 61601, +#if defined(CUSTOM_MODES) + /*...208:*/ + 62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565, + 70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013, + 78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113, +#endif + /*N=4, K=4...176:*/ + 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017, + 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775, + 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153, + 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193, + 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575, + 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217, + 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951, + 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609, + 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023, + 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407, + 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759, + 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175, + 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751, + 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583, + 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767, + 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399, + 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575, + 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391, + 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943, + 7085049, 7207551, +#if defined(CUSTOM_MODES) + /*...208:*/ + 7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783, + 8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967, + 9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199, + 10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177, + 11912575, +#endif + /*N=5, K=5...176:*/ + 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041, + 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401, + 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241, + 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241, + 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801, + 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849, + 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849, + 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809, + 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881, + 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641, + 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081, + 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609, + 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049, + 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641, + 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041, + 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321, + 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969, + 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889, + 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401, + 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241, + 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561, + 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929, + 590359041, 604167209, 618216201, 632508801, +#if defined(CUSTOM_MODES) + /*...208:*/ + 647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241, + 755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161, + 878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329, + 1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041, + 1143412929, 1166053121, 1189027881, 1212340489, 1235994241, +#endif + /*N=6, K=6...96:*/ + 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047, + 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409, + 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793, + 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455, + 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189, + 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651, + 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185, + 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647, + 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229, + 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283, + 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135, + 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187, + 2011371957, 2120032959, +#if defined(CUSTOM_MODES) + /*...109:*/ + 2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U, + 3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U, + 4012305913U, +#endif + /*N=7, K=7...54*/ + 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777, + 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233, + 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013, + 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805, + 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433, + 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821, + 1667010073, 1870535785, 2094367717, +#if defined(CUSTOM_MODES) + /*...60:*/ + 2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U, +#endif + /*N=8, K=8...37*/ + 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767, + 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017, + 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351, + 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615, + 2229491905U, +#if defined(CUSTOM_MODES) + /*...40:*/ + 2691463695U, 3233240945U, 3866006015U, +#endif + /*N=9, K=9...28:*/ + 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777, + 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145, + 628496897, 872893441, 1196924561, 1621925137, 2173806145U, +#if defined(CUSTOM_MODES) + /*...29:*/ + 2883810113U, +#endif + /*N=10, K=10...24:*/ + 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073, + 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U, + 3375210671U, + /*N=11, K=11...19:*/ + 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585, + 948062325, 1616336765, +#if defined(CUSTOM_MODES) + /*...20:*/ + 2684641785U, +#endif + /*N=12, K=12...18:*/ + 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185, + 3248227095U, + /*N=13, K=13...16:*/ + 251595969, 579168825, 1267854873, 2653649025U, + /*N=14, K=14:*/ + 1409933619 +}; + +#if defined(CUSTOM_MODES) +static const opus_uint32 *const CELT_PVQ_U_ROW[15] PROGMEM={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415, + CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030, + CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389, + CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455, + CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473 +}; +#else +static const opus_uint32 *const CELT_PVQ_U_ROW[15] PROGMEM={ + CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351, + CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870, + CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178, + CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240, + CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257 +}; +#endif + +#if defined(CUSTOM_MODES) +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac); +} +#endif + +static opus_uint32 icwrs(int _n,const int *_y){ + opus_uint32 i; + int j; + int k; + celt_assert(_n>=2); + j=_n-1; + i=_y[j]<0; + k=abs(_y[j]); + do{ + j--; + i+=CELT_PVQ_U(_n-j,k); + k+=abs(_y[j]); + if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1); + } + while(j>0); + return i; +} + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + celt_assert(_k>0); + ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k)); +} + +static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){ + opus_uint32 p; + int s; + int k0; + opus_int16 val; + opus_val32 yy=0; + celt_assert(_k>0); + celt_assert(_n>1); + while(_n>2){ + opus_uint32 q; + /*Lots of pulses case:*/ + if(_k>=_n){ + const opus_uint32 *row; + row=CELT_PVQ_U_ROW[_n]; + /*Are the pulses in this dimension negative?*/ + p=row[_k+1]; + s=-(_i>=p); + _i-=p&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + q=row[_n]; + if(q>_i){ + celt_sig_assert(p>q); + _k=_n; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + } + else for(p=row[_k];p>_i;p=row[_k])_k--; + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + /*Lots of dimensions case:*/ + else{ + /*Are there any pulses in this dimension at all?*/ + p=CELT_PVQ_U_ROW[_k][_n]; + q=CELT_PVQ_U_ROW[_k+1][_n]; + if(p<=_i&&_i=q); + _i-=q&s; + /*Count how many pulses were placed in this dimension.*/ + k0=_k; + do p=CELT_PVQ_U_ROW[--_k][_n]; + while(p>_i); + _i-=p; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + } + } + _n--; + } + /*_n==2*/ + p=2*_k+1; + s=-(_i>=p); + _i-=p&s; + k0=_k; + _k=(_i+1)>>1; + if(_k)_i-=2*_k-1; + val=(k0-_k+s)^s; + *_y++=val; + yy=MAC16_16(yy,val,val); + /*_n==1*/ + s=-(int)_i; + val=(_k+s)^s; + *_y=val; + yy=MAC16_16(yy,val,val); + return yy; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + return cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y); +} + +#else /* SMALL_FOOTPRINT */ + +/*Computes the next row/column of any recurrence that obeys the relation + u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_len); + _ui[j-1]=_ui0; +} + +/*Computes the previous row/column of any recurrence that obeys the relation + u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1]. + _ui0 is the base case for the new row/column.*/ +static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){ + opus_uint32 ui1; + unsigned j; + /*This do-while will overrun the array if we don't have storage for at least + 2 values.*/ + j=1; do { + ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0); + _ui[j-1]=_ui0; + _ui0=ui1; + } while (++j<_n); + _ui[j-1]=_ui0; +} + +/*Compute V(_n,_k), as well as U(_n,0..._k+1). + _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/ +static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){ + opus_uint32 um2; + unsigned len; + unsigned k; + len=_k+2; + /*We require storage at least 3 values (e.g., _k>0).*/ + celt_assert(len>=3); + _u[0]=0; + _u[1]=um2=1; + /*If _n==0, _u[0] should be 1 and the rest should be 0.*/ + /*If _n==1, _u[i] should be 1 for i>1.*/ + celt_assert(_n>=2); + /*If _k==0, the following do-while loop will overflow the buffer.*/ + celt_assert(_k>0); + k=2; + do _u[k]=(k<<1)-1; + while(++k0); + j=0; + do{ + opus_uint32 p; + int s; + int yj; + p=_u[_k+1]; + s=-(_i>=p); + _i-=p&s; + yj=_k; + p=_u[_k]; + while(p>_i)p=_u[--_k]; + _i-=p; + yj-=_k; + val=(yj+s)^s; + _y[j]=val; + yy=MAC16_16(yy,val,val); + uprev(_u,_k+2,0); + } + while(++j<_n); + return yy; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size 1 with associated sign bits. + _y: The vector of pulses, whose sum of absolute values is K. + _k: Returns K.*/ +static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){ + *_k=abs(_y[0]); + return _y[0]<0; +} + +/*Returns the index of the given combination of K elements chosen from a set + of size _n with associated sign bits. + _y: The vector of pulses, whose sum of absolute values must be _k. + _nc: Returns V(_n,_k).*/ +static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y, + opus_uint32 *_u){ + opus_uint32 i; + int j; + int k; + /*We can't unroll the first two iterations of the loop unless _n>=2.*/ + celt_assert(_n>=2); + _u[0]=0; + for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1; + i=icwrs1(_y+_n-1,&k); + j=_n-2; + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + while(j-->0){ + unext(_u,_k+2,0); + i+=_u[k]; + k+=abs(_y[j]); + if(_y[j]<0)i+=_u[k+1]; + } + *_nc=_u[k]+_u[k+1]; + return i; +} + +#ifdef CUSTOM_MODES +void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){ + int k; + /*_maxk==0 => there's nothing to do.*/ + celt_assert(_maxk>0); + _bits[0]=0; + if (_n==1) + { + for (k=1;k<=_maxk;k++) + _bits[k] = 1<<_frac; + } + else { + VARDECL(opus_uint32,u); + SAVE_STACK; + ALLOC(u,_maxk+2U,opus_uint32); + ncwrs_urow(_n,_maxk,u); + for(k=1;k<=_maxk;k++) + _bits[k]=log2_frac(u[k]+u[k+1],_frac); + RESTORE_STACK; + } +} +#endif /* CUSTOM_MODES */ + +void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){ + opus_uint32 i; + VARDECL(opus_uint32,u); + opus_uint32 nc; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + i=icwrs(_n,_k,&nc,_y,u); + ec_enc_uint(_enc,i,nc); + RESTORE_STACK; +} + +opus_val32 decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){ + VARDECL(opus_uint32,u); + int ret; + SAVE_STACK; + celt_assert(_k>0); + ALLOC(u,_k+2U,opus_uint32); + ret = cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u); + RESTORE_STACK; + return ret; +} + +#endif /* SMALL_FOOTPRINT */ diff --git a/src/libopus/celt/cwrs.h b/src/libopus/celt/cwrs.h new file mode 100644 index 00000000..7cd47174 --- /dev/null +++ b/src/libopus/celt/cwrs.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2007-2009 Timothy B. Terriberry + Written by Timothy B. Terriberry and Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef CWRS_H +#define CWRS_H + +#include "arch.h" +#include "stack_alloc.h" +#include "entenc.h" +#include "entdec.h" + +#ifdef CUSTOM_MODES +int log2_frac(opus_uint32 val, int frac); +#endif + +void get_required_bits(opus_int16 *bits, int N, int K, int frac); + +void encode_pulses(const int *_y, int N, int K, ec_enc *enc); + +opus_val32 decode_pulses(int *_y, int N, int K, ec_dec *dec); + +#endif /* CWRS_H */ diff --git a/src/libopus/celt/ecintrin.h b/src/libopus/celt/ecintrin.h new file mode 100644 index 00000000..d5a09af9 --- /dev/null +++ b/src/libopus/celt/ecintrin.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2003-2008 Timothy B. Terriberry + Copyright (c) 2008 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*Some common macros for potential platform-specific optimization.*/ +#include "../opus_types.h" +#include +#include +#include "arch.h" +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a)))) + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +# include +/*In _DEBUG mode this is not an intrinsic by default.*/ +# pragma intrinsic(_BitScanReverse) + +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(_x)) +#elif __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +int ec_ilog(opus_uint32 _v); +# define EC_ILOG(_x) (ec_ilog(_x)) +#endif +#endif diff --git a/src/libopus/celt/entcode.c b/src/libopus/celt/entcode.c new file mode 100644 index 00000000..e689df68 --- /dev/null +++ b/src/libopus/celt/entcode.c @@ -0,0 +1,153 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "entcode.h" +#include "arch.h" + +#if !defined(EC_CLZ) +/*This is a fallback for systems where we don't know how to access + a BSR or CLZ instruction (see ecintrin.h). + If you are optimizing Opus on a new platform and it has a native CLZ or + BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be + an easy performance win.*/ +int ec_ilog(opus_uint32 _v){ + /*On a Pentium M, this branchless version tested as the fastest on + 1,000,000,000 random 32-bit integers, edging out a similar version with + branches, and a 256-entry LUT version.*/ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +#endif + +#if 1 +/* This is a faster version of ec_tell_frac() that takes advantage + of the low (1/8 bit) resolution to use just a linear function + followed by a lookup to determine the exact transition thresholds. */ +opus_uint32 ec_tell_frac(ec_ctx *_this){ + static const unsigned correction[8] = + {35733, 38967, 42495, 46340, + 50535, 55109, 60097, 65535}; + opus_uint32 nbits; + opus_uint32 r; + int l; + unsigned b; + nbits=_this->nbits_total<rng); + r=_this->rng>>(l-16); + b = (r>>12)-8; + b += r>correction[b]; + l = (l<<3)+b; + return nbits-l; +} +#else +opus_uint32 ec_tell_frac(ec_ctx *_this){ + opus_uint32 nbits; + opus_uint32 r; + int l; + int i; + /*To handle the non-integral number of bits still left in the encoder/decoder + state, we compute the worst-case number of bits of val that must be + encoded to ensure that the value is inside the range for any possible + subsequent bits. + The computation here is independent of val itself (the decoder does not + even track that value), even though the real number of bits used after + ec_enc_done() may be 1 smaller if rng is a power of two and the + corresponding trailing bits of val are all zeros. + If we did try to track that special case, then coding a value with a + probability of 1/(1<nbits_total<rng); + r=_this->rng>>(l-16); + for(i=BITRES;i-->0;){ + int b; + r=r*r>>15; + b=(int)(r>>16); + l=l<<1|b; + r>>=b; + } + return nbits-l; +} +#endif + +#ifdef USE_SMALL_DIV_TABLE +/* Result of 2^32/(2*i+1), except for i=0. */ +const opus_uint32 SMALL_DIV_TABLE[129] = { + 0xFFFFFFFF, 0x55555555, 0x33333333, 0x24924924, + 0x1C71C71C, 0x1745D174, 0x13B13B13, 0x11111111, + 0x0F0F0F0F, 0x0D79435E, 0x0C30C30C, 0x0B21642C, + 0x0A3D70A3, 0x097B425E, 0x08D3DCB0, 0x08421084, + 0x07C1F07C, 0x07507507, 0x06EB3E45, 0x06906906, + 0x063E7063, 0x05F417D0, 0x05B05B05, 0x0572620A, + 0x05397829, 0x05050505, 0x04D4873E, 0x04A7904A, + 0x047DC11F, 0x0456C797, 0x04325C53, 0x04104104, + 0x03F03F03, 0x03D22635, 0x03B5CC0E, 0x039B0AD1, + 0x0381C0E0, 0x0369D036, 0x03531DEC, 0x033D91D2, + 0x0329161F, 0x03159721, 0x03030303, 0x02F14990, + 0x02E05C0B, 0x02D02D02, 0x02C0B02C, 0x02B1DA46, + 0x02A3A0FD, 0x0295FAD4, 0x0288DF0C, 0x027C4597, + 0x02702702, 0x02647C69, 0x02593F69, 0x024E6A17, + 0x0243F6F0, 0x0239E0D5, 0x02302302, 0x0226B902, + 0x021D9EAD, 0x0214D021, 0x020C49BA, 0x02040810, + 0x01FC07F0, 0x01F44659, 0x01ECC07B, 0x01E573AC, + 0x01DE5D6E, 0x01D77B65, 0x01D0CB58, 0x01CA4B30, + 0x01C3F8F0, 0x01BDD2B8, 0x01B7D6C3, 0x01B20364, + 0x01AC5701, 0x01A6D01A, 0x01A16D3F, 0x019C2D14, + 0x01970E4F, 0x01920FB4, 0x018D3018, 0x01886E5F, + 0x0183C977, 0x017F405F, 0x017AD220, 0x01767DCE, + 0x01724287, 0x016E1F76, 0x016A13CD, 0x01661EC6, + 0x01623FA7, 0x015E75BB, 0x015AC056, 0x01571ED3, + 0x01539094, 0x01501501, 0x014CAB88, 0x0149539E, + 0x01460CBC, 0x0142D662, 0x013FB013, 0x013C995A, + 0x013991C2, 0x013698DF, 0x0133AE45, 0x0130D190, + 0x012E025C, 0x012B404A, 0x01288B01, 0x0125E227, + 0x01234567, 0x0120B470, 0x011E2EF3, 0x011BB4A4, + 0x01194538, 0x0116E068, 0x011485F0, 0x0112358E, + 0x010FEF01, 0x010DB20A, 0x010B7E6E, 0x010953F3, + 0x01073260, 0x0105197F, 0x0103091B, 0x01010101 +}; +#endif diff --git a/src/libopus/celt/entcode.h b/src/libopus/celt/entcode.h new file mode 100644 index 00000000..89ce2635 --- /dev/null +++ b/src/libopus/celt/entcode.h @@ -0,0 +1,152 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "../opus_types.h" +#include "../opus_defines.h" + +#if !defined(_entcode_H) +# define _entcode_H (1) +# include +# include +# include "ecintrin.h" + +extern const opus_uint32 SMALL_DIV_TABLE[129]; + +#ifdef OPUS_ARM_ASM +#define USE_SMALL_DIV_TABLE +#endif + +/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a + larger type, you can speed up the decoder by using it here.*/ +typedef opus_uint32 ec_window; +typedef struct ec_ctx ec_ctx; +typedef struct ec_ctx ec_enc; +typedef struct ec_ctx ec_dec; + +# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT) + +/*The number of bits to use for the range-coded part of unsigned integers.*/ +# define EC_UINT_BITS (8) + +/*The resolution of fractional-precision bit usage measurements, i.e., + 3 => 1/8th bits.*/ +# define BITRES 3 + +/*The entropy encoder/decoder context. + We use the same structure for both, so that common functions like ec_tell() + can be used on either one.*/ +struct ec_ctx{ + /*Buffered input/output.*/ + unsigned char *buf; + /*The size of the buffer.*/ + opus_uint32 storage; + /*The offset at which the last byte containing raw bits was read/written.*/ + opus_uint32 end_offs; + /*Bits that will be read from/written at the end.*/ + ec_window end_window; + /*Number of valid bits in end_window.*/ + int nend_bits; + /*The total number of whole bits read/written. + This does not include partial bits currently in the range coder.*/ + int nbits_total; + /*The offset at which the next range coder byte will be read/written.*/ + opus_uint32 offs; + /*The number of values in the current range.*/ + opus_uint32 rng; + /*In the decoder: the difference between the top of the current range and + the input value, minus one. + In the encoder: the low end of the current range.*/ + opus_uint32 val; + /*In the decoder: the saved normalization factor from ec_decode(). + In the encoder: the number of oustanding carry propagating symbols.*/ + opus_uint32 ext; + /*A buffered input/output symbol, awaiting carry propagation.*/ + int rem; + /*Nonzero if an error occurred.*/ + int error; +}; + +static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){ + return _this->offs; +} + +static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){ + return _this->buf; +} + +static OPUS_INLINE int ec_get_error(ec_ctx *_this){ + return _this->error; +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +static OPUS_INLINE int ec_tell(ec_ctx *_this){ + return _this->nbits_total-EC_ILOG(_this->rng); +} + +/*Returns the number of bits "used" by the encoded or decoded symbols so far. + This same number can be computed in either the encoder or the decoder, and is + suitable for making coding decisions. + Return: The number of bits scaled by 2**BITRES. + This will always be slightly larger than the exact value (e.g., all + rounding error is in the positive direction).*/ +opus_uint32 ec_tell_frac(ec_ctx *_this); + +/* Tested exhaustively for all n and for 1<=d<=256 */ +static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (d>256) + return n/d; + else { + opus_uint32 t, q; + t = EC_ILOG(d&-d); + q = (opus_uint64)SMALL_DIV_TABLE[d>>t]*(n>>(t-1))>>32; + return q+(n-q*d >= d); + } +#else + return n/d; +#endif +} + +static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) { + celt_sig_assert(d>0); +#ifdef USE_SMALL_DIV_TABLE + if (n<0) + return -(opus_int32)celt_udiv(-n, d); + else + return celt_udiv(n, d); +#else + return n/d; +#endif +} + +#endif diff --git a/src/libopus/celt/entdec.c b/src/libopus/celt/entdec.c new file mode 100644 index 00000000..a37d9587 --- /dev/null +++ b/src/libopus/celt/entdec.c @@ -0,0 +1,245 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include +#include "os_support.h" +#include "arch.h" +#include "entdec.h" +#include "mfrngcod.h" + +/*A range decoder. + This is an entropy decoder based upon \cite{Mar79}, which is itself a + rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}. + It is very similar to arithmetic encoding, except that encoding is done with + digits in any base, instead of with bits, and so it is faster when using + larger bases (i.e.: a byte). + The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$ + is the base, longer than the theoretical optimum, but to my knowledge there + is no published justification for this claim. + This only seems true when using near-infinite precision arithmetic so that + the process is carried out with no rounding errors. + + An excellent description of implementation details is available at + http://www.arturocampos.com/ac_range.html + A recent work \cite{MNW98} which proposes several changes to arithmetic + encoding for efficiency actually re-discovers many of the principles + behind range encoding, and presents a good theoretical analysis of them. + + End of stream is handled by writing out the smallest number of bits that + ensures that the stream will be correctly decoded regardless of the value of + any subsequent bits. + ec_tell() can be used to determine how many bits were needed to decode + all the symbols thus far; other data can be packed in the remaining bits of + the input buffer. + @PHDTHESIS{Pas76, + author="Richard Clark Pasco", + title="Source coding algorithms for fast data compression", + school="Dept. of Electrical Engineering, Stanford University", + address="Stanford, CA", + month=May, + year=1976 + } + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video & Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_read_byte(ec_dec *_this){ + return _this->offs<_this->storage?_this->buf[_this->offs++]:0; +} + +static int ec_read_byte_from_end(ec_dec *_this){ + return _this->end_offs<_this->storage? + _this->buf[_this->storage-++(_this->end_offs)]:0; +} + +/*Normalizes the contents of val and rng so that rng lies entirely in the + high-order symbol.*/ +static void ec_dec_normalize(ec_dec *_this){ + /*If the range is too small, rescale it and input some bits.*/ + while(_this->rng<=EC_CODE_BOT){ + int sym; + _this->nbits_total+=EC_SYM_BITS; + _this->rng<<=EC_SYM_BITS; + /*Use up the remaining bits from our last symbol.*/ + sym=_this->rem; + /*Read the next value from the input.*/ + _this->rem=ec_read_byte(_this); + /*Take the rest of the bits we need from this new symbol.*/ + sym=(sym<rem)>>(EC_SYM_BITS-EC_CODE_EXTRA); + /*And subtract them from val, capped to be less than EC_CODE_TOP.*/ + _this->val=((_this->val<buf=_buf; + _this->storage=_storage; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits. + The final value after the ec_dec_normalize() call will be the same as in + the encoder, but we have to compensate for the bits that are added there.*/ + _this->nbits_total=EC_CODE_BITS+1 + -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS; + _this->offs=0; + _this->rng=1U<rem=ec_read_byte(_this); + _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA)); + _this->error=0; + /*Normalize the interval.*/ + ec_dec_normalize(_this); +} + +unsigned ec_decode(ec_dec *_this,unsigned _ft){ + unsigned s; + _this->ext=celt_udiv(_this->rng,_ft); + s=(unsigned)(_this->val/_this->ext); + return _ft-EC_MINI(s+1,_ft); +} + +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){ + unsigned s; + _this->ext=_this->rng>>_bits; + s=(unsigned)(_this->val/_this->ext); + return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits); +} + +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 s; + s=IMUL32(_this->ext,_ft-_fh); + _this->val-=s; + _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s; + ec_dec_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + int ret; + r=_this->rng; + d=_this->val; + s=r>>_logp; + ret=dval=d-s; + _this->rng=ret?s:r-s; + ec_dec_normalize(_this); + return ret; +} + +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + opus_uint32 d; + opus_uint32 s; + opus_uint32 t; + int ret; + s=_this->rng; + d=_this->val; + r=s>>_ftb; + ret=-1; + do{ + t=s; + s=IMUL32(r,_icdf[++ret]); + } + while(dval=d-s; + _this->rng=t-s; + ec_dec_normalize(_this); + return ret; +} + +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){ + unsigned ft; + unsigned s; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + opus_uint32 t; + ftb-=EC_UINT_BITS; + ft=(unsigned)(_ft>>ftb)+1; + s=ec_decode(_this,ft); + ec_dec_update(_this,s,s+1,ft); + t=(opus_uint32)s<error=1; + return _ft; + } + else{ + _ft++; + s=ec_decode(_this,(unsigned)_ft); + ec_dec_update(_this,s,s+1,(unsigned)_ft); + return s; + } +} + +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){ + ec_window window; + int available; + opus_uint32 ret; + window=_this->end_window; + available=_this->nend_bits; + if((unsigned)available<_bits){ + do{ + window|=(ec_window)ec_read_byte_from_end(_this)<>=_bits; + available-=_bits; + _this->end_window=window; + _this->nend_bits=available; + _this->nbits_total+=_bits; + return ret; +} diff --git a/src/libopus/celt/entdec.h b/src/libopus/celt/entdec.h new file mode 100644 index 00000000..025fc187 --- /dev/null +++ b/src/libopus/celt/entdec.h @@ -0,0 +1,100 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entdec_H) +# define _entdec_H (1) +# include +# include "entcode.h" + +/*Initializes the decoder. + _buf: The input buffer to use. + Return: 0 on success, or a negative value on error.*/ +void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage); + +/*Calculates the cumulative frequency for the next symbol. + This can then be fed into the probability model to determine what that + symbol is, and the additional frequency information required to advance to + the next symbol. + This function cannot be called more than once without a corresponding call to + ec_dec_update(), or decoding will not proceed correctly. + _ft: The total frequency of the symbols in the alphabet the next symbol was + encoded with. + Return: A cumulative frequency representing the encoded symbol. + If the cumulative frequency of all the symbols before the one that + was encoded was fl, and the cumulative frequency of all the symbols + up to and including the one encoded is fh, then the returned value + will fall in the range [fl,fh).*/ +unsigned ec_decode(ec_dec *_this,unsigned _ft); + +/*Equivalent to ec_decode() with _ft==1<<_bits.*/ +unsigned ec_decode_bin(ec_dec *_this,unsigned _bits); + +/*Advance the decoder past the next symbol using the frequency information the + symbol was encoded with. + Exactly one call to ec_decode() must have been made so that all necessary + intermediate calculations are performed. + _fl: The cumulative frequency of all symbols that come before the symbol + decoded. + _fh: The cumulative frequency of all symbols up to and including the symbol + decoded. + Together with _fl, this defines the range [_fl,_fh) in which the value + returned above must fall. + _ft: The total frequency of the symbols in the alphabet the symbol decoded + was encoded in. + This must be the same as passed to the preceding call to ec_decode().*/ +void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/* Decode a bit that has a 1/(1<<_logp) probability of being a one */ +int ec_dec_bit_logp(ec_dec *_this,unsigned _logp); + +/*Decodes a symbol given an "inverse" CDF table. + No call to ec_dec_update() is necessary after this call. + _icdf: The "inverse" CDF, such that symbol s falls in the range + [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution. + Return: The decoded symbol s.*/ +int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb); + +/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream. + The bits must have been encoded with ec_enc_uint(). + No call to ec_dec_update() is necessary after this call. + _ft: The number of integers that can be decoded (one more than the max). + This must be at least 2, and no more than 2**32-1. + Return: The decoded bits.*/ +opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft); + +/*Extracts a sequence of raw bits from the stream. + The bits must have been encoded with ec_enc_bits(). + No call to ec_dec_update() is necessary after this call. + _ftb: The number of bits to extract. + This must be between 0 and 25, inclusive. + Return: The decoded bits.*/ +opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb); + +#endif diff --git a/src/libopus/celt/entenc.c b/src/libopus/celt/entenc.c new file mode 100644 index 00000000..164f238b --- /dev/null +++ b/src/libopus/celt/entenc.c @@ -0,0 +1,294 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#if defined(HAVE_CONFIG_H) +# include "../config.h" +//#endif +#include "os_support.h" +#include "arch.h" +#include "entenc.h" +#include "mfrngcod.h" + +/*A range encoder. + See entdec.c and the references for implementation details \cite{Mar79,MNW98}. + + @INPROCEEDINGS{Mar79, + author="Martin, G.N.N.", + title="Range encoding: an algorithm for removing redundancy from a digitised + message", + booktitle="Video \& Data Recording Conference", + year=1979, + address="Southampton", + month=Jul + } + @ARTICLE{MNW98, + author="Alistair Moffat and Radford Neal and Ian H. Witten", + title="Arithmetic Coding Revisited", + journal="{ACM} Transactions on Information Systems", + year=1998, + volume=16, + number=3, + pages="256--294", + month=Jul, + URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf" + }*/ + +static int ec_write_byte(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->offs++]=(unsigned char)_value; + return 0; +} + +static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){ + if(_this->offs+_this->end_offs>=_this->storage)return -1; + _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value; + return 0; +} + +/*Outputs a symbol, with a carry bit. + If there is a potential to propagate a carry over several symbols, they are + buffered until it can be determined whether or not an actual carry will + occur. + If the counter for the buffered symbols overflows, then the stream becomes + undecodable. + This gives a theoretical limit of a few billion symbols in a single packet on + 32-bit systems. + The alternative is to truncate the range in order to force a carry, but + requires similar carry tracking in the decoder, needlessly slowing it down.*/ +static void ec_enc_carry_out(ec_enc *_this,int _c){ + if(_c!=EC_SYM_MAX){ + /*No further carry propagation possible, flush buffer.*/ + int carry; + carry=_c>>EC_SYM_BITS; + /*Don't output a byte on the first write. + This compare should be taken care of by branch-prediction thereafter.*/ + if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry); + if(_this->ext>0){ + unsigned sym; + sym=(EC_SYM_MAX+carry)&EC_SYM_MAX; + do _this->error|=ec_write_byte(_this,sym); + while(--(_this->ext)>0); + } + _this->rem=_c&EC_SYM_MAX; + } + else _this->ext++; +} + +static OPUS_INLINE void ec_enc_normalize(ec_enc *_this){ + /*If the range is too small, output some bits and rescale it.*/ + while(_this->rng<=EC_CODE_BOT){ + ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT)); + /*Move the next-to-high-order symbol into the high-order position.*/ + _this->val=(_this->val<rng<<=EC_SYM_BITS; + _this->nbits_total+=EC_SYM_BITS; + } +} + +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){ + _this->buf=_buf; + _this->end_offs=0; + _this->end_window=0; + _this->nend_bits=0; + /*This is the offset from which ec_tell() will subtract partial bits.*/ + _this->nbits_total=EC_CODE_BITS+1; + _this->offs=0; + _this->rng=EC_CODE_TOP; + _this->rem=-1; + _this->val=0; + _this->ext=0; + _this->storage=_size; + _this->error=0; +} + +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){ + opus_uint32 r; + r=celt_udiv(_this->rng,_ft); + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,(_ft-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,(_ft-_fh)); + ec_enc_normalize(_this); +} + +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){ + opus_uint32 r; + r=_this->rng>>_bits; + if(_fl>0){ + _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl)); + _this->rng=IMUL32(r,(_fh-_fl)); + } + else _this->rng-=IMUL32(r,((1U<<_bits)-_fh)); + ec_enc_normalize(_this); +} + +/*The probability of having a "one" is 1/(1<<_logp).*/ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){ + opus_uint32 r; + opus_uint32 s; + opus_uint32 l; + r=_this->rng; + l=_this->val; + s=r>>_logp; + r-=s; + if(_val)_this->val=l+r; + _this->rng=_val?s:r; + ec_enc_normalize(_this); +} + +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){ + opus_uint32 r; + r=_this->rng>>_ftb; + if(_s>0){ + _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]); + _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]); + } + else _this->rng-=IMUL32(r,_icdf[_s]); + ec_enc_normalize(_this); +} + +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){ + unsigned ft; + unsigned fl; + int ftb; + /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/ + celt_assert(_ft>1); + _ft--; + ftb=EC_ILOG(_ft); + if(ftb>EC_UINT_BITS){ + ftb-=EC_UINT_BITS; + ft=(_ft>>ftb)+1; + fl=(unsigned)(_fl>>ftb); + ec_encode(_this,fl,fl+1,ft); + ec_enc_bits(_this,_fl&(((opus_uint32)1<end_window; + used=_this->nend_bits; + celt_assert(_bits>0); + if(used+_bits>EC_WINDOW_SIZE){ + do{ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + while(used>=EC_SYM_BITS); + } + window|=(ec_window)_fl<end_window=window; + _this->nend_bits=used; + _this->nbits_total+=_bits; +} + +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){ + int shift; + unsigned mask; + celt_assert(_nbits<=EC_SYM_BITS); + shift=EC_SYM_BITS-_nbits; + mask=((1<<_nbits)-1)<offs>0){ + /*The first byte has been finalized.*/ + _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<rem>=0){ + /*The first byte is still awaiting carry propagation.*/ + _this->rem=(_this->rem&~mask)|_val<rng<=(EC_CODE_TOP>>_nbits)){ + /*The renormalization loop has never been run.*/ + _this->val=(_this->val&~((opus_uint32)mask<error=-1; +} + +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){ + celt_assert(_this->offs+_this->end_offs<=_size); + OPUS_MOVE(_this->buf+_size-_this->end_offs, + _this->buf+_this->storage-_this->end_offs,_this->end_offs); + _this->storage=_size; +} + +void ec_enc_done(ec_enc *_this){ + ec_window window; + int used; + opus_uint32 msk; + opus_uint32 end; + int l; + /*We output the minimum number of bits that ensures that the symbols encoded + thus far will be decoded correctly regardless of the bits that follow.*/ + l=EC_CODE_BITS-EC_ILOG(_this->rng); + msk=(EC_CODE_TOP-1)>>l; + end=(_this->val+msk)&~msk; + if((end|msk)>=_this->val+_this->rng){ + l++; + msk>>=1; + end=(_this->val+msk)&~msk; + } + while(l>0){ + ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT)); + end=(end<rem>=0||_this->ext>0)ec_enc_carry_out(_this,0); + /*If we have buffered extra bits, flush them as well.*/ + window=_this->end_window; + used=_this->nend_bits; + while(used>=EC_SYM_BITS){ + _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX); + window>>=EC_SYM_BITS; + used-=EC_SYM_BITS; + } + /*Clear any excess space and add any remaining extra bits to the last byte.*/ + if(!_this->error){ + OPUS_CLEAR(_this->buf+_this->offs, + _this->storage-_this->offs-_this->end_offs); + if(used>0){ + /*If there's no range coder data at all, give up.*/ + if(_this->end_offs>=_this->storage)_this->error=-1; + else{ + l=-l; + /*If we've busted, don't add too many extra bits to the last byte; it + would corrupt the range coder data, and that's more important.*/ + if(_this->offs+_this->end_offs>=_this->storage&&lerror=-1; + } + _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window; + } + } + } +} diff --git a/src/libopus/celt/entenc.h b/src/libopus/celt/entenc.h new file mode 100644 index 00000000..f502eaf6 --- /dev/null +++ b/src/libopus/celt/entenc.h @@ -0,0 +1,110 @@ +/* Copyright (c) 2001-2011 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_entenc_H) +# define _entenc_H (1) +# include +# include "entcode.h" + +/*Initializes the encoder. + _buf: The buffer to store output bytes in. + _size: The size of the buffer, in chars.*/ +void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size); +/*Encodes a symbol given its frequency information. + The frequency information must be discernable by the decoder, assuming it + has read only the previous symbols from the stream. + It is allowable to change the frequency information, or even the entire + source alphabet, so long as the decoder can tell from the context of the + previously encoded information that it is supposed to do so as well. + _fl: The cumulative frequency of all symbols that come before the one to be + encoded. + _fh: The cumulative frequency of all symbols up to and including the one to + be encoded. + Together with _fl, this defines the range [_fl,_fh) in which the + decoded value will fall. + _ft: The sum of the frequencies of all the symbols*/ +void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft); + +/*Equivalent to ec_encode() with _ft==1<<_bits.*/ +void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits); + +/* Encode a bit that has a 1/(1<<_logp) probability of being a one */ +void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp); + +/*Encodes a symbol given an "inverse" CDF table. + _s: The index of the symbol to encode. + _icdf: The "inverse" CDF, such that symbol _s falls in the range + [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb. + The values must be monotonically non-increasing, and the last value + must be 0. + _ftb: The number of bits of precision in the cumulative distribution.*/ +void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb); + +/*Encodes a raw unsigned integer in the stream. + _fl: The integer to encode. + _ft: The number of integers that can be encoded (one more than the max). + This must be at least 2, and no more than 2**32-1.*/ +void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft); + +/*Encodes a sequence of raw bits in the stream. + _fl: The bits to encode. + _ftb: The number of bits to encode. + This must be between 1 and 25, inclusive.*/ +void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb); + +/*Overwrites a few bits at the very start of an existing stream, after they + have already been encoded. + This makes it possible to have a few flags up front, where it is easy for + decoders to access them without parsing the whole stream, even if their + values are not determined until late in the encoding process, without having + to buffer all the intermediate symbols in the encoder. + In order for this to work, at least _nbits bits must have already been + encoded using probabilities that are an exact power of two. + The encoder can verify the number of encoded bits is sufficient, but cannot + check this latter condition. + _val: The bits to encode (in the least _nbits significant bits). + They will be decoded in order from most-significant to least. + _nbits: The number of bits to overwrite. + This must be no more than 8.*/ +void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits); + +/*Compacts the data to fit in the target size. + This moves up the raw bits at the end of the current buffer so they are at + the end of the new buffer size. + The caller must ensure that the amount of data that's already been written + will fit in the new size. + _size: The number of bytes in the new buffer. + This must be large enough to contain the bits already written, and + must be no larger than the existing size.*/ +void ec_enc_shrink(ec_enc *_this,opus_uint32 _size); + +/*Indicates that there are no more symbols to encode. + All reamining output bytes are flushed to the output buffer. + ec_enc_init() must be called before the encoder can be used again.*/ +void ec_enc_done(ec_enc *_this); + +#endif diff --git a/src/libopus/celt/fixed_debug.h b/src/libopus/celt/fixed_debug.h new file mode 100644 index 00000000..388d4857 --- /dev/null +++ b/src/libopus/celt/fixed_debug.h @@ -0,0 +1,791 @@ +/* Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2012 Xiph.Org Foundation */ +/** + @file fixed_debug.h + @brief Fixed-point operations with debugging +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_DEBUG_H +#define FIXED_DEBUG_H + +#include +#include "../opus_defines.h" + +#ifdef CELT_C +OPUS_EXPORT opus_int64 celt_mips=0; +#else +extern opus_int64 celt_mips; +#endif + +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16)) + +#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16) + +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768) +#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL) +#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1)) + +#define SHR(a,b) SHR32(a,b) +#define PSHR(a,b) PSHR32(a,b) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) (celt_mips+=2,(opus_val32)(0-(opus_uint32)(a))) + +static OPUS_INLINE short NEG16(int x) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "NEG16: input is not short: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "NEG16: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +static OPUS_INLINE int NEG32(opus_int64 x) +{ + opus_int64 res; + if (!VERIFY_INT(x)) + { + fprintf (stderr, "NEG16: input is not int: %d\n", (int)x); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = -x; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "NEG16: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__) +static OPUS_INLINE short EXTRACT16_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__) +static OPUS_INLINE int EXTEND32_(int x, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(x)) + { + fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = x; + celt_mips++; + return res; +} + +#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a>>shift; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} +#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>shift; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SHR32: output is not int: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} +#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__) +static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_SHORT(shift)) + { + fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a<>1))),shift)) +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a)))) +#define SROUND16(x,a) (celt_mips--,EXTRACT16(SATURATE(PSHR32(x,a), 32767))); + +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short ADD16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short SUB16_(int a, int b, char *file, int line) +{ + int res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips++; + return res; +} + +#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a-b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef UADD32 +#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a+b; + if (!VERIFY_UINT(res)) + { + fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#undef USUB32 +#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line) +{ + opus_uint64 res; + if (!VERIFY_UINT(a) || !VERIFY_UINT(b)) + { + fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (a=((opus_val32)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = (((opus_int64)a)*(opus_int64)b) >> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=3; + else + celt_mips+=4; + return res; +} + +#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__) +static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (ABS32(b)>=((opus_int64)(1)<<(15+Q))) + { + fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<>1))>> Q; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + if (Q==15) + celt_mips+=4; + else + celt_mips+=5; + return res; +} + +#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15) +#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b)))) +#define MAC16_32_Q16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q16((a),(b)))) + +static OPUS_INLINE int SATURATE(int a, int b) +{ + if (a>b) + a=b; + if (a<-b) + a = -b; + celt_mips+=3; + return a; +} + +static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a) +{ + celt_mips+=3; + if (a>32767) + return 32767; + else if (a<-32768) + return -32768; + else return a; +} + +static OPUS_INLINE int MULT16_16_Q11_32(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 11; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} +static OPUS_INLINE short MULT16_16_Q14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=3; + return res; +} + +#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__) +static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=1; + return res; +} + +static OPUS_INLINE short MULT16_16_P13(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 4096; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 13; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P14(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 8192; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 14; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=4; + return res; +} +static OPUS_INLINE short MULT16_16_P15(int a, int b) +{ + opus_int64 res; + if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = ((opus_int64)a)*b; + res += 16384; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res >>= 15; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=2; + return res; +} + +#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__) + +static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + if (!VERIFY_INT(a) || !VERIFY_SHORT(b)) + { + fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_SHORT(res)) + { + fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line); + if (res>32767) + res = 32767; + if (res<-32768) + res = -32768; +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=35; + return res; +} + +#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__) +static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line) +{ + opus_int64 res; + if (b==0) + { + fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + return 0; + } + + if (!VERIFY_INT(a) || !VERIFY_INT(b)) + { + fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + res = a/b; + if (!VERIFY_INT(res)) + { + fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line); +#ifdef FIXED_DEBUG_ASSERT + celt_assert(0); +#endif + } + celt_mips+=70; + return res; +} + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + + +#undef PRINT_MIPS +#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0); + +#endif diff --git a/src/libopus/celt/fixed_generic.h b/src/libopus/celt/fixed_generic.h new file mode 100644 index 00000000..5f4abda7 --- /dev/null +++ b/src/libopus/celt/fixed_generic.h @@ -0,0 +1,178 @@ +/* Copyright (C) 2007-2009 Xiph.Org Foundation + Copyright (C) 2003-2008 Jean-Marc Valin + Copyright (C) 2007-2008 CSIRO */ +/** + @file fixed_generic.h + @brief Generic fixed-point operations +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FIXED_GENERIC_H +#define FIXED_GENERIC_H + +/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */ +#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b)) + +/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q16(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_P16(a,b) ((opus_val32)PSHR((opus_int64)((opus_val16)(a))*(b),16)) +#else +#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16)) +#endif + +/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT16_32_Q15(a,b) ((opus_val32)SHR((opus_int64)((opus_val16)(a))*(b),15)) +#else +#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15)) +#endif + +/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */ +#if OPUS_FAST_INT64 +#define MULT32_32_Q31(a,b) ((opus_val32)SHR((opus_int64)(a)*(opus_int64)(b),31)) +#else +#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15)) +#endif + +/** Compile-time conversion of float constant to 16-bit value */ +#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Compile-time conversion of float constant to 32-bit value */ +#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits)))) + +/** Negate a 16-bit value */ +#define NEG16(x) (-(x)) +/** Negate a 32-bit value */ +#define NEG32(x) (-(x)) + +/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */ +#define EXTRACT16(x) ((opus_val16)(x)) +/** Change a 16-bit value into a 32-bit value */ +#define EXTEND32(x) ((opus_val32)(x)) + +/** Arithmetic shift-right of a 16-bit value */ +#define SHR16(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 16-bit value */ +#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift))) +/** Arithmetic shift-right of a 32-bit value */ +#define SHR32(a,shift) ((a) >> (shift)) +/** Arithmetic shift-left of a 32-bit value */ +#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift))) + +/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */ +#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +/** 32-bit arithmetic shift right where the argument can be negative */ +#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift))) + +/** "RAW" macros, should not be used outside of this header file */ +#define SHR(a,shift) ((a) >> (shift)) +#define SHL(a,shift) SHL32(a,shift) +#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift)) +#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x))) + +#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x))) + +/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */ +#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a)))) +/** Shift by a and round-to-neareast 32-bit value. Result is a saturated 16-bit value */ +#define SROUND16(x,a) EXTRACT16(SATURATE(PSHR32(x,a), 32767)); + +/** Divide by two */ +#define HALF16(x) (SHR16(x,1)) +#define HALF32(x) (SHR32(x,1)) + +/** Add two 16-bit values */ +#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b))) +/** Subtract two 16-bit values */ +#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b)) +/** Add two 32-bit values */ +#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b)) +/** Subtract two 32-bit values */ +#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b)) + +/** Add two 32-bit values, ignore any overflows */ +#define ADD32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)+(opus_uint32)(b))) +/** Subtract two 32-bit values, ignore any overflows */ +#define SUB32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)-(opus_uint32)(b))) +/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */ +/** Negate 32-bit value, ignore any overflows */ +#define NEG32_ovflw(a) ((opus_val32)(0-(opus_uint32)(a))) + +/** 16x16 multiplication where the result fits in 16 bits */ +#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b)))) + +/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */ +/** 16x16 multiplication where the result fits in 32 bits */ +#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b))) + +/** 16x16 multiply-add where the result fits in 32 bits */ +#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b)))) +/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add. + b must fit in 31 bits. + Result fits in 32 bits. */ +#define MAC16_32_Q15(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15))) + +/** 16x32 multiplication, followed by a 16-bit shift right and 32-bit add. + Results fits in 32 bits */ +#define MAC16_32_Q16(c,a,b) ADD32((c),ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))) + +#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11)) +#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13)) +#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14)) +#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15)) + +#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13)) +#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14)) +#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15)) + +/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */ +#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b)))) + +/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */ +#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b))) + +#if defined(MIPSr1_ASM) +#include "mips/fixed_generic_mipsr1.h" +#endif + +static OPUS_INLINE opus_val16 SIG2WORD16_generic(celt_sig x) +{ + x = PSHR32(x, SIG_SHIFT); + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return EXTRACT16(x); +} +#define SIG2WORD16(x) (SIG2WORD16_generic(x)) + +#endif diff --git a/src/libopus/celt/float_cast.h b/src/libopus/celt/float_cast.h new file mode 100644 index 00000000..75d5fe82 --- /dev/null +++ b/src/libopus/celt/float_cast.h @@ -0,0 +1,146 @@ +/* Copyright (C) 2001 Erik de Castro Lopo */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Version 1.1 */ + +#ifndef FLOAT_CAST_H +#define FLOAT_CAST_H + + +#include "arch.h" + +/*============================================================================ +** On Intel Pentium processors (especially PIII and probably P4), converting +** from float to int is very slow. To meet the C specs, the code produced by +** most C compilers targeting Pentium needs to change the FPU rounding mode +** before the float to int conversion is performed. +** +** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It +** is this flushing of the pipeline which is so slow. +** +** Fortunately the ISO C99 specifications define the functions lrint, lrintf, +** llrint and llrintf which fix this problem as a side effect. +** +** On Unix-like systems, the configure process should have detected the +** presence of these functions. If they weren't found we have to replace them +** here with a standard C cast. +*/ + +/* +** The C99 prototypes for lrint and lrintf are as follows: +** +** long int lrintf (float x) ; +** long int lrint (double x) ; +*/ + +/* The presence of the required functions are detected during the configure +** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in +** the ../config.h file. +*/ + +/* With GCC, when SSE is available, the fastest conversion is cvtss2si. */ +#if defined(__GNUC__) && defined(__SSE__) + +#include +static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_ss(x));} + +#elif defined(HAVE_LRINTF) + +/* These defines enable functionality introduced with the 1999 ISO C +** standard. They must be defined before the inclusion of math.h to +** engage them. If optimisation is enabled, these functions will be +** inlined. With optimisation switched off, you have to link in the +** maths library using -lm. +*/ + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrintf(x) + +#elif (defined(HAVE_LRINT)) + +#define _ISOC9X_SOURCE 1 +#define _ISOC99_SOURCE 1 + +#define __USE_ISOC9X 1 +#define __USE_ISOC99 1 + +#include +#define float2int(x) lrint(x) + +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)) + #include + + static __inline long int float2int(float value) + { + return _mm_cvtss_si32(_mm_load_ss(&value)); + } +#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_IX86) + #include + + /* Win32 doesn't seem to have these functions. + ** Therefore implement OPUS_INLINE versions of these functions here. + */ + + static __inline long int + float2int (float flt) + { int intgr; + + _asm + { fld flt + fistp intgr + } ; + + return intgr ; + } + +#else + +#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) + /* supported by gcc in C99 mode, but not by all other compilers */ + #warning "Don't have the functions lrint() and lrintf ()." + #warning "Replacing these functions with a standard C cast." +#endif /* __STDC_VERSION__ >= 199901L */ + #include + #define float2int(flt) ((int)(floor(.5+flt))) +#endif + +#ifndef DISABLE_FLOAT_API +static OPUS_INLINE opus_int16 FLOAT2INT16(float x) +{ + x = x*CELT_SIG_SCALE; + x = MAX32(x, -32768); + x = MIN32(x, 32767); + return (opus_int16)float2int(x); +} +#endif /* DISABLE_FLOAT_API */ + +#endif /* FLOAT_CAST_H */ diff --git a/src/libopus/celt/kiss_fft.c b/src/libopus/celt/kiss_fft.c new file mode 100644 index 00000000..2b761846 --- /dev/null +++ b/src/libopus/celt/kiss_fft.c @@ -0,0 +1,604 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +/* This code is originally from Mark Borgerding's KISS-FFT but has been + heavily modified to better suit Opus */ + +#ifndef SKIP_CONFIG_H +//# ifdef HAVE_CONFIG_H +# include "../config.h" +//# endif +#endif + +#include "_kiss_fft_guts.h" +#include "arch.h" +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +/* The guts header contains all the multiplication and addition macros that are defined for + complex numbers. It also delares the kf_ internal functions. +*/ + +static void kf_bfly2( + kiss_fft_cpx * Fout, + int m, + int N + ) +{ + kiss_fft_cpx * Fout2; + int i; + (void)m; +#ifdef CUSTOM_MODES + if (m==1) + { + celt_assert(m==1); + for (i=0;itwiddles; + /* m is guaranteed to be a multiple of 4. */ + for (j=0;jtwiddles[fstride*m]; +#endif + for (i=0;itwiddles; + /* For non-custom modes, m is guaranteed to be a multiple of 4. */ + k=m; + do { + + C_MUL(scratch[1],Fout[m] , *tw1); + C_MUL(scratch[2],Fout[m2] , *tw2); + + C_ADD(scratch[3],scratch[1],scratch[2]); + C_SUB(scratch[0],scratch[1],scratch[2]); + tw1 += fstride; + tw2 += fstride*2; + + Fout[m].r = SUB32_ovflw(Fout->r, HALF_OF(scratch[3].r)); + Fout[m].i = SUB32_ovflw(Fout->i, HALF_OF(scratch[3].i)); + + C_MULBYSCALAR( scratch[0] , epi3.i ); + + C_ADDTO(*Fout,scratch[3]); + + Fout[m2].r = ADD32_ovflw(Fout[m].r, scratch[0].i); + Fout[m2].i = SUB32_ovflw(Fout[m].i, scratch[0].r); + + Fout[m].r = SUB32_ovflw(Fout[m].r, scratch[0].i); + Fout[m].i = ADD32_ovflw(Fout[m].i, scratch[0].r); + + ++Fout; + } while(--k); + } +} + + +#ifndef OVERRIDE_kf_bfly5 +static void kf_bfly5( + kiss_fft_cpx * Fout, + const size_t fstride, + const kiss_fft_state *st, + int m, + int N, + int mm + ) +{ + kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; + int i, u; + kiss_fft_cpx scratch[13]; + const kiss_twiddle_cpx *tw; + kiss_twiddle_cpx ya,yb; + kiss_fft_cpx * Fout_beg = Fout; + +#ifdef FIXED_POINT + ya.r = 10126; + ya.i = -31164; + yb.r = -26510; + yb.i = -19261; +#else + ya = st->twiddles[fstride*m]; + yb = st->twiddles[fstride*2*m]; +#endif + tw=st->twiddles; + + for (i=0;ir = ADD32_ovflw(Fout0->r, ADD32_ovflw(scratch[7].r, scratch[8].r)); + Fout0->i = ADD32_ovflw(Fout0->i, ADD32_ovflw(scratch[7].i, scratch[8].i)); + + scratch[5].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,ya.r), S_MUL(scratch[8].r,yb.r))); + scratch[5].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,ya.r), S_MUL(scratch[8].i,yb.r))); + + scratch[6].r = ADD32_ovflw(S_MUL(scratch[10].i,ya.i), S_MUL(scratch[9].i,yb.i)); + scratch[6].i = NEG32_ovflw(ADD32_ovflw(S_MUL(scratch[10].r,ya.i), S_MUL(scratch[9].r,yb.i))); + + C_SUB(*Fout1,scratch[5],scratch[6]); + C_ADD(*Fout4,scratch[5],scratch[6]); + + scratch[11].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,yb.r), S_MUL(scratch[8].r,ya.r))); + scratch[11].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,yb.r), S_MUL(scratch[8].i,ya.r))); + scratch[12].r = SUB32_ovflw(S_MUL(scratch[9].i,ya.i), S_MUL(scratch[10].i,yb.i)); + scratch[12].i = SUB32_ovflw(S_MUL(scratch[10].r,yb.i), S_MUL(scratch[9].r,ya.i)); + + C_ADD(*Fout2,scratch[11],scratch[12]); + C_SUB(*Fout3,scratch[11],scratch[12]); + + ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; + } + } +} +#endif /* OVERRIDE_kf_bfly5 */ + + +#endif + + +#ifdef CUSTOM_MODES + +static +void compute_bitrev_table( + int Fout, + opus_int16 *f, + const size_t fstride, + int in_stride, + opus_int16 * factors, + const kiss_fft_state *st + ) +{ + const int p=*factors++; /* the radix */ + const int m=*factors++; /* stage's fft length/p */ + + /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/ + if (m==1) + { + int j; + for (j=0;j32000 || (opus_int32)p*(opus_int32)p > n) + p = n; /* no more factors, skip to end */ + } + n /= p; +#ifdef RADIX_TWO_ONLY + if (p!=2 && p != 4) +#else + if (p>5) +#endif + { + return 0; + } + facbuf[2*stages] = p; + if (p==2 && stages > 1) + { + facbuf[2*stages] = 4; + facbuf[2] = 2; + } + stages++; + } while (n > 1); + n = nbak; + /* Reverse the order to get the radix 4 at the end, so we can use the + fast degenerate case. It turns out that reversing the order also + improves the noise behaviour. */ + for (i=0;i= memneeded) + st = (kiss_fft_state*)mem; + *lenmem = memneeded; + } + if (st) { + opus_int16 *bitrev; + kiss_twiddle_cpx *twiddles; + + st->nfft=nfft; +#ifdef FIXED_POINT + st->scale_shift = celt_ilog2(st->nfft); + if (st->nfft == 1<scale_shift) + st->scale = Q15ONE; + else + st->scale = (1073741824+st->nfft/2)/st->nfft>>(15-st->scale_shift); +#else + st->scale = 1.f/nfft; +#endif + if (base != NULL) + { + st->twiddles = base->twiddles; + st->shift = 0; + while (st->shift < 32 && nfft<shift != base->nfft) + st->shift++; + if (st->shift>=32) + goto fail; + } else { + st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft); + compute_twiddles(twiddles, nfft); + st->shift = -1; + } + if (!kf_factor(nfft,st->factors)) + { + goto fail; + } + + /* bitrev */ + st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft); + if (st->bitrev==NULL) + goto fail; + compute_bitrev_table(0, bitrev, 1,1, st->factors,st); + + /* Initialize architecture specific fft parameters */ + if (opus_fft_alloc_arch(st, arch)) + goto fail; + } + return st; +fail: + opus_fft_free(st, arch); + return NULL; +} + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch) +{ + return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL, arch); +} + +void opus_fft_free_arch_c(kiss_fft_state *st) { + (void)st; +} + +void opus_fft_free(const kiss_fft_state *cfg, int arch) +{ + if (cfg) + { + opus_fft_free_arch((kiss_fft_state *)cfg, arch); + opus_free((opus_int16*)cfg->bitrev); + if (cfg->shift < 0) + opus_free((kiss_twiddle_cpx*)cfg->twiddles); + opus_free((kiss_fft_state*)cfg); + } +} + +#endif /* CUSTOM_MODES */ + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout) +{ + int m2, m; + int p; + int L; + int fstride[MAXFACTORS]; + int i; + int shift; + + /* st->shift can be -1 */ + shift = st->shift>0 ? st->shift : 0; + + fstride[0] = 1; + L=0; + do { + p = st->factors[2*L]; + m = st->factors[2*L+1]; + fstride[L+1] = fstride[L]*p; + L++; + } while(m!=1); + m = st->factors[2*L-1]; + for (i=L-1;i>=0;i--) + { + if (i!=0) + m2 = st->factors[2*i-1]; + else + m2 = 1; + switch (st->factors[2*i]) + { + case 2: + kf_bfly2(fout, m, fstride[i]); + break; + case 4: + kf_bfly4(fout,fstride[i]<scale_shift-1; +#endif + scale = st->scale; + + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + { + kiss_fft_cpx x = fin[i]; + fout[st->bitrev[i]].r = SHR32(MULT16_32_Q16(scale, x.r), scale_shift); + fout[st->bitrev[i]].i = SHR32(MULT16_32_Q16(scale, x.i), scale_shift); + } + opus_fft_impl(st, fout); +} + + +void opus_ifft_c(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) +{ + int i; + celt_assert2 (fin != fout, "In-place FFT not supported"); + /* Bit-reverse the input */ + for (i=0;infft;i++) + fout[st->bitrev[i]] = fin[i]; + for (i=0;infft;i++) + fout[i].i = -fout[i].i; + opus_fft_impl(st, fout); + for (i=0;infft;i++) + fout[i].i = -fout[i].i; +} diff --git a/src/libopus/celt/kiss_fft.h b/src/libopus/celt/kiss_fft.h new file mode 100644 index 00000000..bffa2bfa --- /dev/null +++ b/src/libopus/celt/kiss_fft.h @@ -0,0 +1,200 @@ +/*Copyright (c) 2003-2004, Mark Borgerding + Lots of modifications by Jean-Marc Valin + Copyright (c) 2005-2007, Xiph.Org Foundation + Copyright (c) 2008, Xiph.Org Foundation, CSIRO + + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE.*/ + +#ifndef KISS_FFT_H +#define KISS_FFT_H + +#include +#include +#include "arch.h" +#include "cpu_support.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef USE_SIMD +# include +# define kiss_fft_scalar __m128 +#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes) +#else +#define KISS_FFT_MALLOC opus_alloc +#endif + +#ifdef FIXED_POINT +#include "arch.h" + +# define kiss_fft_scalar opus_int32 +# define kiss_twiddle_scalar opus_int16 + + +#else +# ifndef kiss_fft_scalar +/* default is float */ +# define kiss_fft_scalar float +# define kiss_twiddle_scalar float +# define KF_SUFFIX _celt_single +# endif +#endif + +typedef struct { + kiss_fft_scalar r; + kiss_fft_scalar i; +}kiss_fft_cpx; + +typedef struct { + kiss_twiddle_scalar r; + kiss_twiddle_scalar i; +}kiss_twiddle_cpx; + +#define MAXFACTORS 8 +/* e.g. an fft of length 128 has 4 factors + as far as kissfft is concerned + 4*4*4*2 + */ + +typedef struct arch_fft_state{ + int is_supported; + void *priv; +} arch_fft_state; + +typedef struct kiss_fft_state{ + int nfft; + opus_val16 scale; +#ifdef FIXED_POINT + int scale_shift; +#endif + int shift; + opus_int16 factors[2*MAXFACTORS]; + const opus_int16 *bitrev; + const kiss_twiddle_cpx *twiddles; + arch_fft_state *arch_fft; +} kiss_fft_state; + +#if defined(HAVE_ARM_NE10) +#include "arm/fft_arm.h" +#endif + +/*typedef struct kiss_fft_state* kiss_fft_cfg;*/ + +/** + * opus_fft_alloc + * + * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. + * + * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL); + * + * The return value from fft_alloc is a cfg buffer used internally + * by the fft routine or NULL. + * + * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc. + * The returned value should be free()d when done to avoid memory leaks. + * + * The state can be placed in a user supplied buffer 'mem': + * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, + * then the function places the cfg in mem and the size used in *lenmem + * and returns mem. + * + * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), + * then the function returns NULL and places the minimum cfg + * buffer size in *lenmem. + * */ + +kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base, int arch); + +kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem, int arch); + +/** + * opus_fft(cfg,in_out_buf) + * + * Perform an FFT on a complex input buffer. + * for a forward FFT, + * fin should be f[0] , f[1] , ... ,f[nfft-1] + * fout will be F[0] , F[1] , ... ,F[nfft-1] + * Note that each element is complex and can be accessed like + f[k].r and f[k].i + * */ +void opus_fft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); +void opus_ifft_c(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); + +void opus_fft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); +void opus_ifft_impl(const kiss_fft_state *st,kiss_fft_cpx *fout); + +void opus_fft_free(const kiss_fft_state *cfg, int arch); + + +void opus_fft_free_arch_c(kiss_fft_state *st); +int opus_fft_alloc_arch_c(kiss_fft_state *st); + +#if !defined(OVERRIDE_OPUS_FFT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) + +extern int (*const OPUS_FFT_ALLOC_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); + +#define opus_fft_alloc_arch(_st, arch) \ + ((*OPUS_FFT_ALLOC_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT_FREE_ARCH_IMPL[OPUS_ARCHMASK+1])( + kiss_fft_state *st); +#define opus_fft_free_arch(_st, arch) \ + ((*OPUS_FFT_FREE_ARCH_IMPL[(arch)&OPUS_ARCHMASK])(_st)) + +extern void (*const OPUS_FFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((*OPUS_FFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +extern void (*const OPUS_IFFT[OPUS_ARCHMASK+1])(const kiss_fft_state *cfg, + const kiss_fft_cpx *fin, kiss_fft_cpx *fout); +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((*OPUS_IFFT[(arch)&OPUS_ARCHMASK])(_cfg, _fin, _fout)) + +#else /* else for if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ + +#define opus_fft_alloc_arch(_st, arch) \ + ((void)(arch), opus_fft_alloc_arch_c(_st)) + +#define opus_fft_free_arch(_st, arch) \ + ((void)(arch), opus_fft_free_arch_c(_st)) + +#define opus_fft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_fft_c(_cfg, _fin, _fout)) + +#define opus_ifft(_cfg, _fin, _fout, arch) \ + ((void)(arch), opus_ifft_c(_cfg, _fin, _fout)) + +#endif /* end if defined(OPUS_HAVE_RTCD) && (defined(HAVE_ARM_NE10)) */ +#endif /* end if !defined(OVERRIDE_OPUS_FFT) */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/celt/laplace.c b/src/libopus/celt/laplace.c new file mode 100644 index 00000000..820433aa --- /dev/null +++ b/src/libopus/celt/laplace.c @@ -0,0 +1,134 @@ +/* Copyright (c) 2007 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "laplace.h" +#include "mathops.h" + +/* The minimum probability of an energy delta (out of 32768). */ +#define LAPLACE_LOG_MINP (0) +#define LAPLACE_MINP (1<>15; +} + +void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay) +{ + unsigned fl; + int val = *value; + fl = 0; + if (val) + { + int s; + int i; + s = -(val<0); + val = (val+s)^s; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay); + /* Search the decaying part of the PDF.*/ + for (i=1; fs > 0 && i < val; i++) + { + fs *= 2; + fl += fs+2*LAPLACE_MINP; + fs = (fs*(opus_int32)decay)>>15; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (!fs) + { + int di; + int ndi_max; + ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP; + ndi_max = (ndi_max-s)>>1; + di = IMIN(val - i, ndi_max - 1); + fl += (2*di+1+s)*LAPLACE_MINP; + fs = IMIN(LAPLACE_MINP, 32768-fl); + *value = (i+di+s)^s; + } + else + { + fs += LAPLACE_MINP; + fl += fs&~s; + } + celt_assert(fl+fs<=32768); + celt_assert(fs>0); + } + ec_encode_bin(enc, fl, fl+fs, 15); +} + +int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay) +{ + int val=0; + unsigned fl; + unsigned fm; + fm = ec_decode_bin(dec, 15); + fl = 0; + if (fm >= fs) + { + val++; + fl = fs; + fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP; + /* Search the decaying part of the PDF.*/ + while(fs > LAPLACE_MINP && fm >= fl+2*fs) + { + fs *= 2; + fl += fs; + fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15; + fs += LAPLACE_MINP; + val++; + } + /* Everything beyond that has probability LAPLACE_MINP. */ + if (fs <= LAPLACE_MINP) + { + int di; + di = (fm-fl)>>(LAPLACE_LOG_MINP+1); + val += di; + fl += 2*di*LAPLACE_MINP; + } + if (fm < fl+fs) + val = -val; + else + fl += fs; + } + celt_assert(fl<32768); + celt_assert(fs>0); + celt_assert(fl<=fm); + celt_assert(fm>1; + b=1U<>=1; + bshift--; + } + while(bshift>=0); + return g; +} + +#ifdef FIXED_POINT + +opus_val32 frac_div32(opus_val32 a, opus_val32 b) +{ + opus_val16 rcp; + opus_val32 result, rem; + int shift = celt_ilog2(b)-29; + a = VSHR32(a,shift); + b = VSHR32(b,shift); + /* 16-bit reciprocal */ + rcp = ROUND16(celt_rcp(ROUND16(b,16)),3); + result = MULT16_32_Q15(rcp, a); + rem = PSHR32(a,2)-MULT32_32_Q31(result, b); + result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2)); + if (result >= 536870912) /* 2^29 */ + return 2147483647; /* 2^31 - 1 */ + else if (result <= -536870912) /* -2^29 */ + return -2147483647; /* -2^31 */ + else + return SHL32(result, 2); +} + +/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */ +opus_val16 celt_rsqrt_norm(opus_val32 x) +{ + opus_val16 n; + opus_val16 r; + opus_val16 r2; + opus_val16 y; + /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */ + n = x-32768; + /* Get a rough initial guess for the root. + The optimal minimax quadratic approximation (using relative error) is + r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485). + Coefficients here, and the final result r, are Q14.*/ + r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713)))); + /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14. + We can compute the result from n and r using Q15 multiplies with some + adjustment, carefully done to avoid overflow. + Range of y is [-1564,1594]. */ + r2 = MULT16_16_Q15(r, r); + y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1); + /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5). + This yields the Q14 reciprocal square root of the Q16 x, with a maximum + relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a + peak absolute error of 2.26591/16384. */ + return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y, + SUB16(MULT16_16_Q15(y, 12288), 16384)))); +} + +/** Sqrt approximation (QX input, QX/2 output) */ +opus_val32 celt_sqrt(opus_val32 x) +{ + int k; + opus_val16 n; + opus_val32 rt; + static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664}; + if (x==0) + return 0; + else if (x>=1073741824) + return 32767; + k = (celt_ilog2(x)>>1)-7; + x = VSHR32(x, 2*k); + n = x-32768; + rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], + MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4]))))))))); + rt = VSHR32(rt,7-k); + return rt; +} + +#define L1 32767 +#define L2 -7651 +#define L3 8277 +#define L4 -626 + +static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x) +{ + opus_val16 x2; + + x2 = MULT16_16_P15(x,x); + return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2 + )))))))); +} + +#undef L1 +#undef L2 +#undef L3 +#undef L4 + +opus_val16 celt_cos_norm(opus_val32 x) +{ + x = x&0x0001ffff; + if (x>SHL32(EXTEND32(1), 16)) + x = SUB32(SHL32(EXTEND32(1), 17),x); + if (x&0x00007fff) + { + if (x0); + i = celt_ilog2(x); + /* n is Q15 with range [0,1). */ + n = VSHR32(x,i-15)-32768; + /* Start with a linear approximation: + r = 1.8823529411764706-0.9411764705882353*n. + The coefficients and the result are Q14 in the range [15420,30840].*/ + r = ADD16(30840, MULT16_16_Q15(-15420, n)); + /* Perform two Newton iterations: + r -= r*((r*n)-1.Q15) + = r*((r*n)+(r-1.Q15)). */ + r = SUB16(r, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))); + /* We subtract an extra 1 in the second iteration to avoid overflow; it also + neatly compensates for truncation error in the rest of the process. */ + r = SUB16(r, ADD16(1, MULT16_16_Q15(r, + ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))))); + /* r is now the Q15 solution to 2/(n+1), with a maximum relative error + of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute + error of 1.24665/32768. */ + return VSHR32(EXTEND32(r),i-16); +} + +#endif diff --git a/src/libopus/celt/mathops.h b/src/libopus/celt/mathops.h new file mode 100644 index 00000000..5e86ff0d --- /dev/null +++ b/src/libopus/celt/mathops.h @@ -0,0 +1,290 @@ +/* Copyright (c) 2002-2008 Jean-Marc Valin + Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file mathops.h + @brief Various math functions +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MATHOPS_H +#define MATHOPS_H + +#include "arch.h" +#include "entcode.h" +#include "os_support.h" + +#define PI 3.141592653f + +/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */ +#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15) + +unsigned isqrt32(opus_uint32 _val); + +/* CELT doesn't need it for fixed-point, by analysis.c does. */ +#if !defined(FIXED_POINT) || defined(ANALYSIS_C) +#define cA 0.43157974f +#define cB 0.67848403f +#define cC 0.08595542f +#define cE ((float)PI/2) +static OPUS_INLINE float fast_atan2f(float y, float x) { + float x2, y2; + x2 = x*x; + y2 = y*y; + /* For very small values, we don't care about the answer, so + we can just return 0. */ + if (x2 + y2 < 1e-18f) + { + return 0; + } + if(x2>23)-127; + in.i -= integer<<23; + frac = in.f - 1.5f; + frac = -0.41445418f + frac*(0.95909232f + + frac*(-0.33951290f + frac*0.16541097f)); + return 1+integer+frac; +} + +/** Base-2 exponential approximation (2^x). */ +static OPUS_INLINE float celt_exp2(float x) +{ + int integer; + float frac; + union { + float f; + opus_uint32 i; + } res; + integer = floor(x); + if (integer < -50) + return 0; + frac = x-integer; + /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */ + res.f = 0.99992522f + frac * (0.69583354f + + frac * (0.22606716f + 0.078024523f*frac)); + res.i = (res.i + (integer<<23)) & 0x7fffffff; + return res.f; +} + +#else +#define celt_log2(x) ((float)(1.442695040888963387*log(x))) +#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x))) +#endif + +#endif + +#ifdef FIXED_POINT + +#include "os_support.h" + +#ifndef OVERRIDE_CELT_ILOG2 +/** Integer log in base2. Undefined for zero and negative numbers */ +static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x) +{ + celt_sig_assert(x>0); + return EC_ILOG(x)-1; +} +#endif + + +/** Integer log in base2. Defined for zero, but not for negative numbers */ +static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x) +{ + return x <= 0 ? 0 : celt_ilog2(x); +} + +opus_val16 celt_rsqrt_norm(opus_val32 x); + +opus_val32 celt_sqrt(opus_val32 x); + +opus_val16 celt_cos_norm(opus_val32 x); + +/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */ +static OPUS_INLINE opus_val16 celt_log2(opus_val32 x) +{ + int i; + opus_val16 n, frac; + /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605, + 0.15530808010959576, -0.08556153059057618 */ + static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401}; + if (x==0) + return -32767; + i = celt_ilog2(x); + n = VSHR32(x,i-15)-32768-16384; + frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4])))))))); + return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT); +} + +/* + K0 = 1 + K1 = log(2) + K2 = 3-4*log(2) + K3 = 3*log(2) - 2 +*/ +#define D0 16383 +#define D1 22804 +#define D2 14819 +#define D3 10204 + +static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x) +{ + opus_val16 frac; + frac = SHL16(x, 4); + return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac)))))); +} +/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */ +static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x) +{ + int integer; + opus_val16 frac; + integer = SHR16(x,10); + if (integer>14) + return 0x7f000000; + else if (integer < -15) + return 0; + frac = celt_exp2_frac(x-SHL16(integer,10)); + return VSHR32(EXTEND32(frac), -integer-2); +} + +opus_val32 celt_rcp(opus_val32 x); + +#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b)) + +opus_val32 frac_div32(opus_val32 a, opus_val32 b); + +#define M1 32767 +#define M2 -21 +#define M3 -11943 +#define M4 4936 + +/* Atan approximation using a 4th order polynomial. Input is in Q15 format + and normalized by pi/4. Output is in Q15 format */ +static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x) +{ + return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x))))))); +} + +#undef M1 +#undef M2 +#undef M3 +#undef M4 + +/* atan2() approximation valid for positive input values */ +static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x) +{ + if (y < x) + { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(y),15),x); + if (arg >= 32767) + arg = 32767; + return SHR16(celt_atan01(EXTRACT16(arg)),1); + } else { + opus_val32 arg; + arg = celt_div(SHL32(EXTEND32(x),15),y); + if (arg >= 32767) + arg = 32767; + return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1); + } +} + +#endif /* FIXED_POINT */ +#endif /* MATHOPS_H */ diff --git a/src/libopus/celt/mdct.c b/src/libopus/celt/mdct.c new file mode 100644 index 00000000..f484a179 --- /dev/null +++ b/src/libopus/celt/mdct.c @@ -0,0 +1,343 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef SKIP_CONFIG_H +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#endif + +#include "mdct.h" +#include "kiss_fft.h" +#include "_kiss_fft_guts.h" +#include +#include "os_support.h" +#include "mathops.h" +#include "stack_alloc.h" + +#if defined(MIPSr1_ASM) +#include "mips/mdct_mipsr1.h" +#endif + + +#ifdef CUSTOM_MODES + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch) +{ + int i; + kiss_twiddle_scalar *trig; + int shift; + int N2=N>>1; + l->n = N; + l->maxshift = maxshift; + for (i=0;i<=maxshift;i++) + { + if (i==0) + l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0, arch); + else + l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0], arch); +#ifndef ENABLE_TI_DSPLIB55 + if (l->kfft[i]==NULL) + return 0; +#endif + } + l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N-(N2>>maxshift))*sizeof(kiss_twiddle_scalar)); + if (l->trig==NULL) + return 0; + for (shift=0;shift<=maxshift;shift++) + { + /* We have enough points that sine isn't necessary */ +#if defined(FIXED_POINT) +#if 1 + for (i=0;i>= 1; + N >>= 1; + } + return 1; +} + +void clt_mdct_clear(mdct_lookup *l, int arch) +{ + int i; + for (i=0;i<=l->maxshift;i++) + opus_fft_free(l->kfft[i], arch); + opus_free((kiss_twiddle_scalar*)l->trig); +} + +#endif /* CUSTOM_MODES */ + +/* Forward MDCT trashes the input array */ +#ifndef OVERRIDE_clt_mdct_forward +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + VARDECL(kiss_fft_scalar, f); + VARDECL(kiss_fft_cpx, f2); + const kiss_fft_state *st = l->kfft[shift]; + const kiss_twiddle_scalar *trig; + opus_val16 scale; +#ifdef FIXED_POINT + /* Allows us to scale with MULT16_32_Q16(), which is faster than + MULT16_32_Q15() on ARM. */ + int scale_shift = st->scale_shift-1; +#endif + SAVE_STACK; + (void)arch; + scale = st->scale; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + ALLOC(f, N2, kiss_fft_scalar); + ALLOC(f2, N4, kiss_fft_cpx); + + /* Consider the input to be composed of four blocks: [a, b, c, d] */ + /* Window, shuffle, fold */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1); + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1); + kiss_fft_scalar * OPUS_RESTRICT yp = f; + const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1); + const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1; + for(i=0;i<((overlap+3)>>2);i++) + { + /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/ + *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2); + *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]); + xp1+=2; + xp2-=2; + wp1+=2; + wp2-=2; + } + wp1 = window; + wp2 = window+overlap-1; + for(;i>2);i++) + { + /* Real part arranged as a-bR, Imag part arranged as -c-dR */ + *yp++ = *xp2; + *yp++ = *xp1; + xp1+=2; + xp2-=2; + } + for(;ibitrev[i]] = yc; + } + } + + /* N/4 complex FFT, does not downscale anymore */ + opus_fft_impl(st, f2); + + /* Post-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_cpx * OPUS_RESTRICT fp = f2; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1); + const kiss_twiddle_scalar *t = &trig[0]; + /* Temp pointers to make it really clear to the compiler what we're doing */ + for(i=0;ii,t[N4+i]) - S_MUL(fp->r,t[i]); + yi = S_MUL(fp->r,t[N4+i]) + S_MUL(fp->i,t[i]); + *yp1 = yr; + *yp2 = yi; + fp++; + yp1 += 2*stride; + yp2 -= 2*stride; + } + } + RESTORE_STACK; +} +#endif /* OVERRIDE_clt_mdct_forward */ + +#ifndef OVERRIDE_clt_mdct_backward +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride, int arch) +{ + int i; + int N, N2, N4; + const kiss_twiddle_scalar *trig; + (void) arch; + + N = l->n; + trig = l->trig; + for (i=0;i>= 1; + trig += N; + } + N2 = N>>1; + N4 = N>>2; + + /* Pre-rotate */ + { + /* Temp pointers to make it really clear to the compiler what we're doing */ + const kiss_fft_scalar * OPUS_RESTRICT xp1 = in; + const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1); + kiss_fft_scalar * OPUS_RESTRICT yp = out+(overlap>>1); + const kiss_twiddle_scalar * OPUS_RESTRICT t = &trig[0]; + const opus_int16 * OPUS_RESTRICT bitrev = l->kfft[shift]->bitrev; + for(i=0;ikfft[shift], (kiss_fft_cpx*)(out+(overlap>>1))); + + /* Post-rotate and de-shuffle from both ends of the buffer at once to make + it in-place. */ + { + kiss_fft_scalar * yp0 = out+(overlap>>1); + kiss_fft_scalar * yp1 = out+(overlap>>1)+N2-2; + const kiss_twiddle_scalar *t = &trig[0]; + /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the + middle pair will be computed twice. */ + for(i=0;i<(N4+1)>>1;i++) + { + kiss_fft_scalar re, im, yr, yi; + kiss_twiddle_scalar t0, t1; + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp0[1]; + im = yp0[0]; + t0 = t[i]; + t1 = t[N4+i]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + /* We swap real and imag because we're using an FFT instead of an IFFT. */ + re = yp1[1]; + im = yp1[0]; + yp0[0] = yr; + yp1[1] = yi; + + t0 = t[(N4-i-1)]; + t1 = t[(N2-i-1)]; + /* We'd scale up by 2 here, but instead it's done when mixing the windows */ + yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1)); + yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0)); + yp1[0] = yr; + yp0[1] = yi; + yp0 += 2; + yp1 -= 2; + } + } + + /* Mirror on both sides for TDAC */ + { + kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1; + kiss_fft_scalar * OPUS_RESTRICT yp1 = out; + const opus_val16 * OPUS_RESTRICT wp1 = window; + const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1; + + for(i = 0; i < overlap/2; i++) + { + kiss_fft_scalar x1, x2; + x1 = *xp1; + x2 = *yp1; + *yp1++ = SUB32_ovflw(MULT16_32_Q15(*wp2, x2), MULT16_32_Q15(*wp1, x1)); + *xp1-- = ADD32_ovflw(MULT16_32_Q15(*wp1, x2), MULT16_32_Q15(*wp2, x1)); + wp1++; + wp2--; + } + } +} +#endif /* OVERRIDE_clt_mdct_backward */ diff --git a/src/libopus/celt/mdct.h b/src/libopus/celt/mdct.h new file mode 100644 index 00000000..9f92a856 --- /dev/null +++ b/src/libopus/celt/mdct.h @@ -0,0 +1,112 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2008 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* This is a simple MDCT implementation that uses a N/4 complex FFT + to do most of the work. It should be relatively straightforward to + plug in pretty much and FFT here. + + This replaces the Vorbis FFT (and uses the exact same API), which + was a bit too messy and that was ending up duplicating code + (might as well use the same FFT everywhere). + + The algorithm is similar to (and inspired from) Fabrice Bellard's + MDCT implementation in FFMPEG, but has differences in signs, ordering + and scaling in many places. +*/ + +#ifndef MDCT_H +#define MDCT_H + +#include "../opus_defines.h" +#include "kiss_fft.h" +#include "arch.h" + +typedef struct { + int n; + int maxshift; + const kiss_fft_state *kfft[4]; + const kiss_twiddle_scalar * OPUS_RESTRICT trig; +} mdct_lookup; + +#if defined(HAVE_ARM_NE10) +#include "arm/mdct_arm.h" +#endif + + +int clt_mdct_init(mdct_lookup *l,int N, int maxshift, int arch); +void clt_mdct_clear(mdct_lookup *l, int arch); + +/** Compute a forward MDCT and scale by 4/N, trashes the input array */ +void clt_mdct_forward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 *window, int overlap, + int shift, int stride, int arch); + +/** Compute a backward MDCT (no scaling) and performs weighted overlap-add + (scales implicitly by 1/2) */ +void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, + const opus_val16 * OPUS_RESTRICT window, + int overlap, int shift, int stride, int arch); + +#if !defined(OVERRIDE_OPUS_MDCT) +/* Is run-time CPU detection enabled on this platform? */ +#if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) + +extern void (*const CLT_MDCT_FORWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + ((*CLT_MDCT_FORWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch)) + +extern void (*const CLT_MDCT_BACKWARD_IMPL[OPUS_ARCHMASK+1])( + const mdct_lookup *l, kiss_fft_scalar *in, + kiss_fft_scalar * OPUS_RESTRICT out, const opus_val16 *window, + int overlap, int shift, int stride, int arch); + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + (*CLT_MDCT_BACKWARD_IMPL[(arch)&OPUS_ARCHMASK])(_l, _in, _out, \ + _window, _overlap, _shift, \ + _stride, _arch) + +#else /* if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) */ + +#define clt_mdct_forward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_forward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#define clt_mdct_backward(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) \ + clt_mdct_backward_c(_l, _in, _out, _window, _overlap, _shift, _stride, _arch) + +#endif /* end if defined(OPUS_HAVE_RTCD) && defined(HAVE_ARM_NE10) && !defined(FIXED_POINT) */ +#endif /* end if !defined(OVERRIDE_OPUS_MDCT) */ + +#endif diff --git a/src/libopus/celt/mfrngcod.h b/src/libopus/celt/mfrngcod.h new file mode 100644 index 00000000..809152a5 --- /dev/null +++ b/src/libopus/celt/mfrngcod.h @@ -0,0 +1,48 @@ +/* Copyright (c) 2001-2008 Timothy B. Terriberry + Copyright (c) 2008-2009 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#if !defined(_mfrngcode_H) +# define _mfrngcode_H (1) +# include "entcode.h" + +/*Constants used by the entropy encoder/decoder.*/ + +/*The number of bits to output at a time.*/ +# define EC_SYM_BITS (8) +/*The total number of bits in each of the state registers.*/ +# define EC_CODE_BITS (32) +/*The maximum symbol value.*/ +# define EC_SYM_MAX ((1U<>EC_SYM_BITS) +/*The number of bits available for the last, partial symbol in the code field.*/ +# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1) +#endif diff --git a/src/libopus/celt/modes.c b/src/libopus/celt/modes.c new file mode 100644 index 00000000..394a5909 --- /dev/null +++ b/src/libopus/celt/modes.c @@ -0,0 +1,442 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "celt.h" +#include "modes.h" +#include "rate.h" +#include "os_support.h" +#include "stack_alloc.h" +#include "quant_bands.h" +#include "cpu_support.h" + +static const opus_int16 eband5ms[] = { +/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100 +}; + +/* Alternate tuning (partially derived from Vorbis) */ +#define BITALLOC_SIZE 11 +/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */ +static const unsigned char band_allocation[] = { +/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0, +110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0, +118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0, +126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0, +134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1, +144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1, +152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1, +162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1, +172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20, +200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104, +}; + +#ifndef CUSTOM_MODES_ONLY + #ifdef FIXED_POINT + #include "static_modes_fixed.h" + #else + #include "static_modes_float.h" + #endif +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef M_PI +#define M_PI 3.141592653 +#endif + +#ifdef CUSTOM_MODES + +/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth + Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */ +#define BARK_BANDS 25 +static const opus_int16 bark_freq[BARK_BANDS+1] = { + 0, 100, 200, 300, 400, + 510, 630, 770, 920, 1080, + 1270, 1480, 1720, 2000, 2320, + 2700, 3150, 3700, 4400, 5300, + 6400, 7700, 9500, 12000, 15500, + 20000}; + +static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands) +{ + opus_int16 *eBands; + int i, j, lin, low, high, nBark, offset=0; + + /* All modes that have 2.5 ms short blocks use the same definition */ + if (Fs == 400*(opus_int32)frame_size) + { + *nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1)); + for (i=0;i<*nbEBands+1;i++) + eBands[i] = eband5ms[i]; + return eBands; + } + /* Find the number of critical bands supported by our sampling rate */ + for (nBark=1;nBark= Fs) + break; + + /* Find where the linear part ends (i.e. where the spacing is more than min_width */ + for (lin=0;lin= res) + break; + + low = (bark_freq[lin]+res/2)/res; + high = nBark-lin; + *nbEBands = low+high; + eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2)); + + if (eBands==NULL) + return NULL; + + /* Linear spacing (min_width) */ + for (i=0;i0) + offset = eBands[low-1]*res - bark_freq[lin-1]; + /* Spacing follows critical bands */ + for (i=0;i frame_size) + eBands[*nbEBands] = frame_size; + for (i=1;i<*nbEBands-1;i++) + { + if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1]) + { + eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2; + } + } + /* Remove any empty bands. */ + for (i=j=0;i<*nbEBands;i++) + if(eBands[i+1]>eBands[j]) + eBands[++j]=eBands[i+1]; + *nbEBands=j; + + for (i=1;i<*nbEBands;i++) + { + /* Every band must be smaller than the last band. */ + celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]); + /* Each band must be no larger than twice the size of the previous one. */ + celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1])); + } + + return eBands; +} + +static void compute_allocation_table(CELTMode *mode) +{ + int i, j; + unsigned char *allocVectors; + int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1; + + mode->nbAllocVectors = BITALLOC_SIZE; + allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands)); + if (allocVectors==NULL) + return; + + /* Check for standard mode */ + if (mode->Fs == 400*(opus_int32)mode->shortMdctSize) + { + for (i=0;inbEBands;i++) + allocVectors[i] = band_allocation[i]; + mode->allocVectors = allocVectors; + return; + } + /* If not the standard mode, interpolate */ + /* Compute per-codec-band allocation from per-critical-band matrix */ + for (i=0;inbEBands;j++) + { + int k; + for (k=0;k mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize) + break; + } + if (k>maxBands-1) + allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1]; + else { + opus_int32 a0, a1; + a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1]; + a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize; + allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1] + + a1*band_allocation[i*maxBands+k])/(a0+a1); + } + } + } + + /*printf ("\n"); + for (i=0;inbEBands;j++) + printf ("%d ", allocVectors[i*mode->nbEBands+j]); + printf ("\n"); + } + exit(0);*/ + + mode->allocVectors = allocVectors; +} + +#endif /* CUSTOM_MODES */ + +CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error) +{ + int i; +#ifdef CUSTOM_MODES + CELTMode *mode=NULL; + int res; + opus_val16 *window; + opus_int16 *logN; + int LM; + int arch = opus_select_arch(); + ALLOC_STACK; +#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA) + if (global_stack==NULL) + goto failure; +#endif +#endif + +#ifndef CUSTOM_MODES_ONLY + for (i=0;iFs && + (frame_size<shortMdctSize*static_mode_list[i]->nbShortMdcts) + { + if (error) + *error = OPUS_OK; + return (CELTMode*)static_mode_list[i]; + } + } + } +#endif /* CUSTOM_MODES_ONLY */ + +#ifndef CUSTOM_MODES + if (error) + *error = OPUS_BAD_ARG; + return NULL; +#else + + /* The good thing here is that permutation of the arguments will automatically be invalid */ + + if (Fs < 8000 || Fs > 96000) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + /* Frames of less than 1ms are not supported. */ + if ((opus_int32)frame_size*1000 < Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0) + { + LM = 3; + } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0) + { + LM = 2; + } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0) + { + LM = 1; + } else + { + LM = 0; + } + + /* Shorts longer than 3.3ms are not supported. */ + if ((opus_int32)(frame_size>>LM)*300 > Fs) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + + mode = opus_alloc(sizeof(CELTMode)); + if (mode==NULL) + goto failure; + mode->Fs = Fs; + + /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis + is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should + approximate that. */ + if(Fs < 12000) /* 8 kHz */ + { + mode->preemph[0] = QCONST16(0.3500061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(3.6765136719f, 13); + } else if(Fs < 24000) /* 16 kHz */ + { + mode->preemph[0] = QCONST16(0.6000061035f, 15); + mode->preemph[1] = -QCONST16(0.1799926758f, 15); + mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(2.2598876953f, 13); + } else if(Fs < 40000) /* 32 kHz */ + { + mode->preemph[0] = QCONST16(0.7799987793f, 15); + mode->preemph[1] = -QCONST16(0.1000061035f, 15); + mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */ + mode->preemph[3] = QCONST16(1.3333740234f, 13); + } else /* 48 kHz */ + { + mode->preemph[0] = QCONST16(0.8500061035f, 15); + mode->preemph[1] = QCONST16(0.0f, 15); + mode->preemph[2] = QCONST16(1.f, SIG_SHIFT); + mode->preemph[3] = QCONST16(1.f, 13); + } + + mode->maxLM = LM; + mode->nbShortMdcts = 1<shortMdctSize = frame_size/mode->nbShortMdcts; + res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize); + + mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands); + if (mode->eBands==NULL) + goto failure; +#if !defined(SMALL_FOOTPRINT) + /* Make sure we don't allocate a band larger than our PVQ table. + 208 should be enough, but let's be paranoid. */ + if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])< + 208) { + goto failure; + } +#endif + + mode->effEBands = mode->nbEBands; + while (mode->eBands[mode->effEBands] > mode->shortMdctSize) + mode->effEBands--; + + /* Overlap must be divisible by 4 */ + mode->overlap = ((mode->shortMdctSize>>2)<<2); + + compute_allocation_table(mode); + if (mode->allocVectors==NULL) + goto failure; + + window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16)); + if (window==NULL) + goto failure; + +#ifndef FIXED_POINT + for (i=0;ioverlap;i++) + window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)); +#else + for (i=0;ioverlap;i++) + window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap)))); +#endif + mode->window = window; + + logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16)); + if (logN==NULL) + goto failure; + + for (i=0;inbEBands;i++) + logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES); + mode->logN = logN; + + compute_pulse_cache(mode, mode->maxLM); + + if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts, + mode->maxLM, arch) == 0) + goto failure; + + if (error) + *error = OPUS_OK; + + return mode; +failure: + if (error) + *error = OPUS_ALLOC_FAIL; + if (mode!=NULL) + opus_custom_mode_destroy(mode); + return NULL; +#endif /* !CUSTOM_MODES */ +} + +#ifdef CUSTOM_MODES +void opus_custom_mode_destroy(CELTMode *mode) +{ + int arch = opus_select_arch(); + + if (mode == NULL) + return; +#ifndef CUSTOM_MODES_ONLY + { + int i; + for (i=0;ieBands); + opus_free((unsigned char*)mode->allocVectors); + + opus_free((opus_val16*)mode->window); + opus_free((opus_int16*)mode->logN); + + opus_free((opus_int16*)mode->cache.index); + opus_free((unsigned char*)mode->cache.bits); + opus_free((unsigned char*)mode->cache.caps); + clt_mdct_clear(&mode->mdct, arch); + + opus_free((CELTMode *)mode); +} +#endif diff --git a/src/libopus/celt/modes.h b/src/libopus/celt/modes.h new file mode 100644 index 00000000..52a1562e --- /dev/null +++ b/src/libopus/celt/modes.h @@ -0,0 +1,75 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef MODES_H +#define MODES_H + +#include "../opus_types.h" +#include "celt.h" +#include "arch.h" +#include "mdct.h" +#include "entenc.h" +#include "entdec.h" + +#define MAX_PERIOD 1024 + +typedef struct { + int size; + const opus_int16 *index; + const unsigned char *bits; + const unsigned char *caps; +} PulseCache; + +/** Mode definition (opaque) + @brief Mode definition + */ +struct OpusCustomMode { + opus_int32 Fs; + int overlap; + + int nbEBands; + int effEBands; + opus_val16 preemph[4]; + const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */ + + int maxLM; + int nbShortMdcts; + int shortMdctSize; + + int nbAllocVectors; /**< Number of lines in the matrix below */ + const unsigned char *allocVectors; /**< Number of bits in each band for several rates */ + const opus_int16 *logN; + + const opus_val16 *window; + mdct_lookup mdct; + PulseCache cache; +}; + + +#endif diff --git a/src/libopus/celt/os_support.h b/src/libopus/celt/os_support.h new file mode 100644 index 00000000..52286a5f --- /dev/null +++ b/src/libopus/celt/os_support.h @@ -0,0 +1,92 @@ +/* Copyright (C) 2007 Jean-Marc Valin + + File: os_support.h + This is the (tiny) OS abstraction layer. Aside from math.h, this is the + only place where system headers are allowed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OS_SUPPORT_H +#define OS_SUPPORT_H + +#ifdef CUSTOM_SUPPORT +# include "custom_support.h" +#endif + +#include "../opus_types.h" +#include "../opus_defines.h" + +#include +#include +#include + +/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */ +#ifndef OVERRIDE_OPUS_ALLOC +static OPUS_INLINE void *opus_alloc (size_t size) +{ + return malloc(size); +} +#endif + +/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */ +#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH +static OPUS_INLINE void *opus_alloc_scratch (size_t size) +{ + /* Scratch space doesn't need to be cleared */ + return opus_alloc(size); +} +#endif + +/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */ +#ifndef OVERRIDE_OPUS_FREE +static OPUS_INLINE void opus_free (void *ptr) +{ + free(ptr); +} +#endif + +/** Copy n elements from src to dst. The 0* term provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_COPY +#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Copy n elements from src to dst, allowing overlapping regions. The 0* term + provides compile-time type checking */ +#ifndef OVERRIDE_OPUS_MOVE +#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) )) +#endif + +/** Set n elements of dst to zero */ +#ifndef OVERRIDE_OPUS_CLEAR +#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst)))) +#endif + +/*#ifdef __GNUC__ +#pragma GCC poison printf sprintf +#pragma GCC poison malloc free realloc calloc +#endif*/ + +#endif /* OS_SUPPORT_H */ + diff --git a/src/libopus/celt/pitch.c b/src/libopus/celt/pitch.c new file mode 100644 index 00000000..6b180530 --- /dev/null +++ b/src/libopus/celt/pitch.c @@ -0,0 +1,537 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/** + @file pitch.c + @brief Pitch analysis + */ + +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "pitch.h" +#include "os_support.h" +#include "modes.h" +#include "stack_alloc.h" +#include "mathops.h" +#include "celt_lpc.h" + +static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len, + int max_pitch, int *best_pitch +#ifdef FIXED_POINT + , int yshift, opus_val32 maxcorr +#endif + ) +{ + int i, j; + opus_val32 Syy=1; + opus_val16 best_num[2]; + opus_val32 best_den[2]; +#ifdef FIXED_POINT + int xshift; + + xshift = celt_ilog2(maxcorr)-14; +#endif + + best_num[0] = -1; + best_num[1] = -1; + best_den[0] = 0; + best_den[1] = 0; + best_pitch[0] = 0; + best_pitch[1] = 1; + for (j=0;j0) + { + opus_val16 num; + opus_val32 xcorr16; + xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift)); +#ifndef FIXED_POINT + /* Considering the range of xcorr16, this should avoid both underflows + and overflows (inf) when squaring xcorr16 */ + xcorr16 *= 1e-12f; +#endif + num = MULT16_16_Q15(xcorr16,xcorr16); + if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy)) + { + if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy)) + { + best_num[1] = best_num[0]; + best_den[1] = best_den[0]; + best_pitch[1] = best_pitch[0]; + best_num[0] = num; + best_den[0] = Syy; + best_pitch[0] = i; + } else { + best_num[1] = num; + best_den[1] = Syy; + best_pitch[1] = i; + } + } + } + Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift); + Syy = MAX32(1, Syy); + } +} + +static void celt_fir5(opus_val16 *x, + const opus_val16 *num, + int N) +{ + int i; + opus_val16 num0, num1, num2, num3, num4; + opus_val32 mem0, mem1, mem2, mem3, mem4; + num0=num[0]; + num1=num[1]; + num2=num[2]; + num3=num[3]; + num4=num[4]; + mem0=0; + mem1=0; + mem2=0; + mem3=0; + mem4=0; + for (i=0;i>1;i++) + x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift); + x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift); + if (C==2) + { + for (i=1;i>1;i++) + x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift); + x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift); + } + + _celt_autocorr(x_lp, ac, NULL, 0, + 4, len>>1, arch); + + /* Noise floor -40 dB */ +#ifdef FIXED_POINT + ac[0] += SHR32(ac[0],13); +#else + ac[0] *= 1.0001f; +#endif + /* Lag windowing */ + for (i=1;i<=4;i++) + { + /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/ +#ifdef FIXED_POINT + ac[i] -= MULT16_32_Q15(2*i*i, ac[i]); +#else + ac[i] -= ac[i]*(.008f*i)*(.008f*i); +#endif + } + + _celt_lpc(lpc, ac, 4); + for (i=0;i<4;i++) + { + tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp); + lpc[i] = MULT16_16_Q15(lpc[i], tmp); + } + /* Add a zero */ + lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT); + lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]); + lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]); + lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]); + lpc2[4] = MULT16_16_Q15(c1,lpc[3]); + celt_fir5(x_lp, lpc2, len>>1); +} + +/* Pure C implementation. */ +#ifdef FIXED_POINT +opus_val32 +#else +void +#endif +celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, + opus_val32 *xcorr, int len, int max_pitch, int arch) +{ + +#if 0 /* This is a simple version of the pitch correlation that should work + well on DSPs like Blackfin and TI C5x/C6x */ + int i, j; +#ifdef FIXED_POINT + opus_val32 maxcorr=1; +#endif +#if !defined(OVERRIDE_PITCH_XCORR) + (void)arch; +#endif + for (i=0;i0); + celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0); + for (i=0;i0); + celt_assert(max_pitch>0); + lag = len+max_pitch; + + ALLOC(x_lp4, len>>2, opus_val16); + ALLOC(y_lp4, lag>>2, opus_val16); + ALLOC(xcorr, max_pitch>>1, opus_val32); + + /* Downsample by 2 again */ + for (j=0;j>2;j++) + x_lp4[j] = x_lp[2*j]; + for (j=0;j>2;j++) + y_lp4[j] = y[2*j]; + +#ifdef FIXED_POINT + xmax = celt_maxabs16(x_lp4, len>>2); + ymax = celt_maxabs16(y_lp4, lag>>2); + shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11; + if (shift>0) + { + for (j=0;j>2;j++) + x_lp4[j] = SHR16(x_lp4[j], shift); + for (j=0;j>2;j++) + y_lp4[j] = SHR16(y_lp4[j], shift); + /* Use double the shift for a MAC */ + shift *= 2; + } else { + shift = 0; + } +#endif + + /* Coarse search with 4x decimation */ + +#ifdef FIXED_POINT + maxcorr = +#endif + celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch); + + find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch +#ifdef FIXED_POINT + , 0, maxcorr +#endif + ); + + /* Finer search with 2x decimation */ +#ifdef FIXED_POINT + maxcorr=1; +#endif + for (i=0;i>1;i++) + { + opus_val32 sum; + xcorr[i] = 0; + if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2) + continue; +#ifdef FIXED_POINT + sum = 0; + for (j=0;j>1;j++) + sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift); +#else + sum = celt_inner_prod(x_lp, y+i, len>>1, arch); +#endif + xcorr[i] = MAX32(-1, sum); +#ifdef FIXED_POINT + maxcorr = MAX32(maxcorr, sum); +#endif + } + find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch +#ifdef FIXED_POINT + , shift+1, maxcorr +#endif + ); + + /* Refine by pseudo-interpolation */ + if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1) + { + opus_val32 a, b, c; + a = xcorr[best_pitch[0]-1]; + b = xcorr[best_pitch[0]]; + c = xcorr[best_pitch[0]+1]; + if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a)) + offset = 1; + else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c)) + offset = -1; + else + offset = 0; + } else { + offset = 0; + } + *pitch = 2*best_pitch[0]-offset; + + RESTORE_STACK; +} + +#ifdef FIXED_POINT +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + opus_val32 x2y2; + int sx, sy, shift; + opus_val32 g; + opus_val16 den; + if (xy == 0 || xx == 0 || yy == 0) + return 0; + sx = celt_ilog2(xx)-14; + sy = celt_ilog2(yy)-14; + shift = sx + sy; + x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14); + if (shift & 1) { + if (x2y2 < 32768) + { + x2y2 <<= 1; + shift--; + } else { + x2y2 >>= 1; + shift++; + } + } + den = celt_rsqrt_norm(x2y2); + g = MULT16_32_Q15(den, xy); + g = VSHR32(g, (shift>>1)-1); + return EXTRACT16(MIN32(g, Q15ONE)); +} +#else +static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy) +{ + return xy/celt_sqrt(1+xx*yy); +} +#endif + +static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2}; +opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod, + int N, int *T0_, int prev_period, opus_val16 prev_gain, int arch) +{ + int k, i, T, T0; + opus_val16 g, g0; + opus_val16 pg; + opus_val32 xy,xx,yy,xy2; + opus_val32 xcorr[3]; + opus_val32 best_xy, best_yy; + int offset; + int minperiod0; + VARDECL(opus_val32, yy_lookup); + SAVE_STACK; + + minperiod0 = minperiod; + maxperiod /= 2; + minperiod /= 2; + *T0_ /= 2; + prev_period /= 2; + N /= 2; + x += maxperiod; + if (*T0_>=maxperiod) + *T0_=maxperiod-1; + + T = T0 = *T0_; + ALLOC(yy_lookup, maxperiod+1, opus_val32); + dual_inner_prod(x, x, x-T0, N, &xx, &xy, arch); + yy_lookup[0] = xx; + yy=xx; + for (i=1;i<=maxperiod;i++) + { + yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]); + yy_lookup[i] = MAX32(0, yy); + } + yy = yy_lookup[T0]; + best_xy = xy; + best_yy = yy; + g = g0 = compute_pitch_gain(xy, xx, yy); + /* Look for any pitch at T/k */ + for (k=2;k<=15;k++) + { + int T1, T1b; + opus_val16 g1; + opus_val16 cont=0; + opus_val16 thresh; + T1 = celt_udiv(2*T0+k, 2*k); + if (T1 < minperiod) + break; + /* Look for another strong correlation at T1b */ + if (k==2) + { + if (T1+T0>maxperiod) + T1b = T0; + else + T1b = T0+T1; + } else + { + T1b = celt_udiv(2*second_check[k]*T0+k, 2*k); + } + dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2, arch); + xy = HALF32(xy + xy2); + yy = HALF32(yy_lookup[T1] + yy_lookup[T1b]); + g1 = compute_pitch_gain(xy, xx, yy); + if (abs(T1-prev_period)<=1) + cont = prev_gain; + else if (abs(T1-prev_period)<=2 && 5*k*k < T0) + cont = HALF16(prev_gain); + else + cont = 0; + thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont); + /* Bias against very high pitch (very short period) to avoid false-positives + due to short-term correlation */ + if (T1<3*minperiod) + thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont); + else if (T1<2*minperiod) + thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont); + if (g1 > thresh) + { + best_xy = xy; + best_yy = yy; + T = T1; + g = g1; + } + } + best_xy = MAX32(0, best_xy); + if (best_yy <= best_xy) + pg = Q15ONE; + else + pg = SHR32(frac_div32(best_xy,best_yy+1),16); + + for (k=0;k<3;k++) + xcorr[k] = celt_inner_prod(x, x-(T+k-1), N, arch); + if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0])) + offset = 1; + else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2])) + offset = -1; + else + offset = 0; + if (pg > g) + pg = g; + *T0_ = 2*T+offset; + + if (*T0_=3); + y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */ + y_0=*y++; + y_1=*y++; + y_2=*y++; + for (j=0;j +#include "os_support.h" +#include "arch.h" +#include "mathops.h" +#include "stack_alloc.h" +#include "rate.h" + +#ifdef FIXED_POINT +/* Mean energy in each band quantized in Q4 */ +const signed char eMeans[25] = { + 103,100, 92, 85, 81, + 77, 72, 70, 78, 75, + 73, 71, 78, 74, 69, + 72, 70, 74, 76, 71, + 60, 60, 60, 60, 60 +}; +#else +/* Mean energy in each band quantized in Q4 and converted back to float */ +const opus_val16 eMeans[25] = { + 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f, + 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f, + 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f, + 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f, + 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f +}; +#endif +/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */ +#ifdef FIXED_POINT +static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384}; +static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554}; +static const opus_val16 beta_intra = 4915; +#else +static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.}; +static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.}; +static const opus_val16 beta_intra = 4915/32768.; +#endif + +/*Parameters of the Laplace-like probability models used for the coarse energy. + There is one pair of parameters for each frame size, prediction type + (inter/intra), and band number. + The first number of each pair is the probability of 0, and the second is the + decay rate, both in Q8 precision.*/ +static const unsigned char e_prob_model[4][2][42] = { + /*120 sample frames.*/ + { + /*Inter*/ + { + 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128, + 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40, + 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11 + }, + /*Intra*/ + { + 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132, + 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66, + 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50 + } + }, + /*240 sample frames.*/ + { + /*Inter*/ + { + 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74, + 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18, + 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9 + }, + /*Intra*/ + { + 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91, + 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60, + 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45 + } + }, + /*480 sample frames.*/ + { + /*Inter*/ + { + 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38, + 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16, + 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10 + }, + /*Intra*/ + { + 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73, + 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55, + 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42 + } + }, + /*960 sample frames.*/ + { + /*Inter*/ + { + 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36, + 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25, + 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15 + }, + /*Intra*/ + { + 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72, + 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52, + 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40 + } + } +}; + +static const unsigned char small_energy_icdf[3]={2,1,0}; + +static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C) +{ + int c, i; + opus_val32 dist = 0; + c=0; do { + for (i=start;inbEBands]; + oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); +#ifdef FIXED_POINT + f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7); + decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT), + SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay))); +#else + f = x-coef*oldE-prev[c]; + /* Rounding to nearest integer here is really important! */ + qi = (int)floor(.5f+f); + decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay; +#endif + /* Prevent the energy from going down too quickly (e.g. for bands + that have just one bin) */ + if (qi < 0 && x < decay_bound) + { + qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT); + if (qi > 0) + qi = 0; + } + qi0 = qi; + /* If we don't have enough bits to encode all the energy, just assume + something safe. */ + tell = ec_tell(enc); + bits_left = budget-tell-3*C*(end-i); + if (i!=start && bits_left < 30) + { + if (bits_left < 24) + qi = IMIN(1, qi); + if (bits_left < 16) + qi = IMAX(-1, qi); + } + if (lfe && i>=2) + qi = IMIN(qi, 0); + if (budget-tell >= 15) + { + int pi; + pi = 2*IMIN(i,20); + ec_laplace_encode(enc, &qi, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell >= 2) + { + qi = IMAX(-1, IMIN(qi, 1)); + ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2); + } + else if(budget-tell >= 1) + { + qi = IMIN(0, qi); + ec_enc_bit_logp(enc, -qi, 1); + } + else + qi = -1; + error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT); + badness += abs(qi0-qi); + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } + return lfe ? 0 : badness; +} + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes, + int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe) +{ + int intra; + opus_val16 max_decay; + VARDECL(opus_val16, oldEBands_intra); + VARDECL(opus_val16, error_intra); + ec_enc enc_start_state; + opus_uint32 tell; + int badness1=0; + opus_int32 intra_bias; + opus_val32 new_distortion; + SAVE_STACK; + + intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C); + intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512)); + new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C); + + tell = ec_tell(enc); + if (tell+3 > budget) + two_pass = intra = 0; + + max_decay = QCONST16(16.f,DB_SHIFT); + if (end-start>10) + { +#ifdef FIXED_POINT + max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3)); +#else + max_decay = MIN32(max_decay, .125f*nbAvailableBytes); +#endif + } + if (lfe) + max_decay = QCONST16(3.f,DB_SHIFT); + enc_start_state = *enc; + + ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16); + ALLOC(error_intra, C*m->nbEBands, opus_val16); + OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands); + + if (two_pass || intra) + { + badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget, + tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe); + } + + if (!intra) + { + unsigned char *intra_buf; + ec_enc enc_intra_state; + opus_int32 tell_intra; + opus_uint32 nstart_bytes; + opus_uint32 nintra_bytes; + opus_uint32 save_bytes; + int badness2; + VARDECL(unsigned char, intra_bits); + + tell_intra = ec_tell_frac(enc); + + enc_intra_state = *enc; + + nstart_bytes = ec_range_bytes(&enc_start_state); + nintra_bytes = ec_range_bytes(&enc_intra_state); + intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes; + save_bytes = nintra_bytes-nstart_bytes; + if (save_bytes == 0) + save_bytes = ALLOC_NONE; + ALLOC(intra_bits, save_bytes, unsigned char); + /* Copy bits from intra bit-stream */ + OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes); + + *enc = enc_start_state; + + badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget, + tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe); + + if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra))) + { + *enc = enc_intra_state; + /* Copy intra bits to bit-stream */ + OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes); + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + intra = 1; + } + } else { + OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands); + OPUS_COPY(error, error_intra, C*m->nbEBands); + } + + if (intra) + *delayedIntra = new_distortion; + else + *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra), + new_distortion); + + RESTORE_STACK; +} + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C) +{ + int i, c; + + /* Encode finer resolution */ + for (i=start;inbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]); +#else + q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac); +#endif + if (q2 > frac-1) + q2 = frac-1; + if (q2<0) + q2 = 0; + ec_enc_bits(enc, q2, fine_quant[i]); +#ifdef FIXED_POINT + offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT)); +#else + offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f; +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + /*printf ("%f ", error[i] - offset);*/ + } while (++c < C); + } +} + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = error[i+c*m->nbEBands]<0 ? 0 : 1; + ec_enc_bits(enc, q2, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + error[i+c*m->nbEBands] -= offset; + bits_left--; + } while (++c < C); + } + } +} + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM) +{ + const unsigned char *prob_model = e_prob_model[LM][intra]; + int i, c; + opus_val32 prev[2] = {0, 0}; + opus_val16 coef; + opus_val16 beta; + opus_int32 budget; + opus_int32 tell; + + if (intra) + { + coef = 0; + beta = beta_intra; + } else { + beta = beta_coef[LM]; + coef = pred_coef[LM]; + } + + budget = dec->storage*8; + + /* Decode at a fixed coarse resolution */ + for (i=start;i=15) + { + int pi; + pi = 2*IMIN(i,20); + qi = ec_laplace_decode(dec, + prob_model[pi]<<7, prob_model[pi+1]<<6); + } + else if(budget-tell>=2) + { + qi = ec_dec_icdf(dec, small_energy_icdf, 2); + qi = (qi>>1)^-(qi&1); + } + else if(budget-tell>=1) + { + qi = -ec_dec_bit_logp(dec, 1); + } + else + qi = -1; + q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT); + + oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]); + tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7); +#ifdef FIXED_POINT + tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp); +#endif + oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7); + prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8)); + } while (++c < C); + } +} + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C) +{ + int i, c; + /* Decode finer resolution */ + for (i=start;inbEBands] += offset; + } while (++c < C); + } +} + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C) +{ + int i, prio, c; + + /* Use up the remaining bits */ + for (prio=0;prio<2;prio++) + { + for (i=start;i=C ;i++) + { + if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio) + continue; + c=0; + do { + int q2; + opus_val16 offset; + q2 = ec_dec_bits(dec, 1); +#ifdef FIXED_POINT + offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1); +#else + offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384); +#endif + oldEBands[i+c*m->nbEBands] += offset; + bits_left--; + } while (++c < C); + } + } +} + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C) +{ + int c, i; + c=0; + do { + for (i=0;inbEBands] = + celt_log2(bandE[i+c*m->nbEBands]) + - SHL16((opus_val16)eMeans[i],6); +#ifdef FIXED_POINT + /* Compensate for bandE[] being Q12 but celt_log2() taking a Q14 input. */ + bandLogE[i+c*m->nbEBands] += QCONST16(2.f, DB_SHIFT); +#endif + } + for (i=effEnd;inbEBands+i] = -QCONST16(14.f,DB_SHIFT); + } while (++c < C); +} diff --git a/src/libopus/celt/quant_bands.h b/src/libopus/celt/quant_bands.h new file mode 100644 index 00000000..0490bca4 --- /dev/null +++ b/src/libopus/celt/quant_bands.h @@ -0,0 +1,66 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef QUANT_BANDS +#define QUANT_BANDS + +#include "arch.h" +#include "modes.h" +#include "entenc.h" +#include "entdec.h" +#include "mathops.h" + +#ifdef FIXED_POINT +extern const signed char eMeans[25]; +#else +extern const opus_val16 eMeans[25]; +#endif + +void amp2Log2(const CELTMode *m, int effEnd, int end, + celt_ener *bandE, opus_val16 *bandLogE, int C); + +void log2Amp(const CELTMode *m, int start, int end, + celt_ener *eBands, const opus_val16 *oldEBands, int C); + +void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd, + const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget, + opus_val16 *error, ec_enc *enc, int C, int LM, + int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra, + int two_pass, int loss_rate, int lfe); + +void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C); + +void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C); + +void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM); + +void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C); + +void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C); + +#endif /* QUANT_BANDS */ diff --git a/src/libopus/celt/rate.c b/src/libopus/celt/rate.c new file mode 100644 index 00000000..e5b6f0a2 --- /dev/null +++ b/src/libopus/celt/rate.c @@ -0,0 +1,644 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include +#include "modes.h" +#include "cwrs.h" +#include "arch.h" +#include "os_support.h" + +#include "entcode.h" +#include "rate.h" + +static const unsigned char LOG2_FRAC_TABLE[24]={ + 0, + 8,13, + 16,19,21,23, + 24,26,27,28,29,30,31,32, + 32,33,34,34,35,36,36,37,37 +}; + +#ifdef CUSTOM_MODES + +/*Determines if V(N,K) fits in a 32-bit unsigned integer. + N and K are themselves limited to 15 bits.*/ +static int fits_in32(int _n, int _k) +{ + static const opus_int16 maxN[15] = { + 32767, 32767, 32767, 1476, 283, 109, 60, 40, + 29, 24, 20, 18, 16, 14, 13}; + static const opus_int16 maxK[15] = { + 32767, 32767, 32767, 32767, 1172, 238, 95, 53, + 36, 27, 22, 18, 16, 15, 13}; + if (_n>=14) + { + if (_k>=14) + return 0; + else + return _n <= maxN[_k]; + } else { + return _k <= maxK[_n]; + } +} + +void compute_pulse_cache(CELTMode *m, int LM) +{ + int C; + int i; + int j; + int curr=0; + int nbEntries=0; + int entryN[100], entryK[100], entryI[100]; + const opus_int16 *eBands = m->eBands; + PulseCache *cache = &m->cache; + opus_int16 *cindex; + unsigned char *bits; + unsigned char *cap; + + cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2)); + cache->index = cindex; + + /* Scan for all unique band sizes */ + for (i=0;i<=LM+1;i++) + { + for (j=0;jnbEBands;j++) + { + int k; + int N = (eBands[j+1]-eBands[j])<>1; + cindex[i*m->nbEBands+j] = -1; + /* Find other bands that have the same size */ + for (k=0;k<=i;k++) + { + int n; + for (n=0;nnbEBands && (k!=i || n>1) + { + cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n]; + break; + } + } + } + if (cache->index[i*m->nbEBands+j] == -1 && N!=0) + { + int K; + entryN[nbEntries] = N; + K = 0; + while (fits_in32(N,get_pulses(K+1)) && KnbEBands+j] = curr; + entryI[nbEntries] = curr; + + curr += K+1; + nbEntries++; + } + } + } + bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr); + cache->bits = bits; + cache->size = curr; + /* Compute the cache for all unique sizes */ + for (i=0;icaps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands); + for (i=0;i<=LM;i++) + { + for (C=1;C<=2;C++) + { + for (j=0;jnbEBands;j++) + { + int N0; + int max_bits; + N0 = m->eBands[j+1]-m->eBands[j]; + /* N=1 bands only have a sign bit and fine bits. */ + if (N0<1 are even, including custom modes.*/ + if (N0 > 2) + { + N0>>=1; + LM0--; + } + /* N0=1 bands can't be split down to N<2. */ + else if (N0 <= 1) + { + LM0=IMIN(i,1); + N0<<=LM0; + } + /* Compute the cost for the lowest-level PVQ of a fully split + band. */ + pcache = bits + cindex[(LM0+1)*m->nbEBands+j]; + max_bits = pcache[pcache[0]]+1; + /* Add in the cost of coding regular splits. */ + N = N0; + for(k=0;klogN[j]+((LM0+k)<>1)-QTHETA_OFFSET; + /* The number of qtheta bits we'll allocate if the remainder + is to be max_bits. + The average measured cost for theta is 0.89701 times qb, + approximated here as 459/512. */ + num=459*(opus_int32)((2*N-1)*offset+max_bits); + den=((opus_int32)(2*N-1)<<9)-459; + qb = IMIN((num+(den>>1))/den, 57); + celt_assert(qb >= 0); + max_bits += qb; + N <<= 1; + } + /* Add in the cost of a stereo split, if necessary. */ + if (C==2) + { + max_bits <<= 1; + offset = ((m->logN[j]+(i<>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET); + ndof = 2*N-1-(N==2); + /* The average measured cost for theta with the step PDF is + 0.95164 times qb, approximated here as 487/512. */ + num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset); + den = ((opus_int32)ndof<<9)-(N==2?512:487); + qb = IMIN((num+(den>>1))/den, (N==2?64:61)); + celt_assert(qb >= 0); + max_bits += qb; + } + /* Add the fine bits we'll use. */ + /* Compensate for the extra DoF in stereo */ + ndof = C*N + ((C==2 && N>2) ? 1 : 0); + /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = ((m->logN[j] + (i<>1)-FINE_OFFSET; + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += 1<>2; + /* The number of fine bits we'll allocate if the remainder is + to be max_bits. */ + num = max_bits+ndof*offset; + den = (ndof-1)<>1))/den, MAX_FINE_BITS); + celt_assert(qb >= 0); + max_bits += C*qb<eBands[j+1]-m->eBands[j])<= 0); + celt_assert(max_bits < 256); + *cap++ = (unsigned char)max_bits; + } + } + } +} + +#endif /* CUSTOM_MODES */ + +#define ALLOC_STEPS 6 + +static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start, + const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance, + int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits, + int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth) +{ + opus_int32 psum; + int lo, hi; + int i, j; + int logM; + int stereo; + int codedBands=-1; + int alloc_floor; + opus_int32 left, percoeff; + int done; + opus_int32 balance; + SAVE_STACK; + + alloc_floor = C<1; + + logM = LM<>1; + psum = 0; + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS); + if (tmp >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(tmp, cap[j]); + } else { + if (tmp >= alloc_floor) + psum += alloc_floor; + } + } + if (psum > total) + hi = mid; + else + lo = mid; + } + psum = 0; + /*printf ("interp bisection gave %d\n", lo);*/ + done = 0; + for (j=end;j-->start;) + { + int tmp = bits1[j] + ((opus_int32)lo*bits2[j]>>ALLOC_STEPS); + if (tmp < thresh[j] && !done) + { + if (tmp >= alloc_floor) + tmp = alloc_floor; + else + tmp = 0; + } else + done = 1; + /* Don't allocate more than we can actually use */ + tmp = IMIN(tmp, cap[j]); + bits[j] = tmp; + psum += tmp; + } + + /* Decide which bands to skip, working backwards from the end. */ + for (codedBands=end;;codedBands--) + { + int band_width; + int band_bits; + int rem; + j = codedBands-1; + /* Never skip the first band, nor a band that has been boosted by + dynalloc. + In the first case, we'd be coding a bit to signal we're going to waste + all the other bits. + In the second case, we'd be coding a bit to redistribute all the bits + we just signaled should be cocentrated in this band. */ + if (j<=skip_start) + { + /* Give the bit we reserved to end skipping back. */ + total += skip_rsv; + break; + } + /*Figure out how many left-over bits we would be adding to this band. + This can include bits we've stolen back from higher, skipped bands.*/ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0); + band_width = m->eBands[codedBands]-m->eBands[j]; + band_bits = (int)(bits[j] + percoeff*band_width + rem); + /*Only code a skip decision if we're above the threshold for this band. + Otherwise it is force-skipped. + This ensures that we have enough bits to code the skip flag.*/ + if (band_bits >= IMAX(thresh[j], alloc_floor+(1< 17) + depth_threshold = j (depth_threshold*band_width<>4 && j<=signalBandwidth)) +#endif + { + ec_enc_bit_logp(ec, 1, 1); + break; + } + ec_enc_bit_logp(ec, 0, 1); + } else if (ec_dec_bit_logp(ec, 1)) { + break; + } + /*We used a bit to skip this band.*/ + psum += 1< 0) + intensity_rsv = LOG2_FRAC_TABLE[j-start]; + psum += intensity_rsv; + if (band_bits >= alloc_floor) + { + /*If we have enough for a fine energy bit per channel, use it.*/ + psum += alloc_floor; + bits[j] = alloc_floor; + } else { + /*Otherwise this band gets nothing at all.*/ + bits[j] = 0; + } + } + + celt_assert(codedBands > start); + /* Code the intensity and dual stereo parameters. */ + if (intensity_rsv > 0) + { + if (encode) + { + *intensity = IMIN(*intensity, codedBands); + ec_enc_uint(ec, *intensity-start, codedBands+1-start); + } + else + *intensity = start+ec_dec_uint(ec, codedBands+1-start); + } + else + *intensity = 0; + if (*intensity <= start) + { + total += dual_stereo_rsv; + dual_stereo_rsv = 0; + } + if (dual_stereo_rsv > 0) + { + if (encode) + ec_enc_bit_logp(ec, *dual_stereo, 1); + else + *dual_stereo = ec_dec_bit_logp(ec, 1); + } + else + *dual_stereo = 0; + + /* Allocate the remaining bits */ + left = total-psum; + percoeff = celt_udiv(left, m->eBands[codedBands]-m->eBands[start]); + left -= (m->eBands[codedBands]-m->eBands[start])*percoeff; + for (j=start;jeBands[j+1]-m->eBands[j])); + for (j=start;jeBands[j+1]-m->eBands[j]); + bits[j] += tmp; + left -= tmp; + } + /*for (j=0;j= 0); + N0 = m->eBands[j+1]-m->eBands[j]; + N=N0<1) + { + excess = MAX32(bit-cap[j],0); + bits[j] = bit-excess; + + /* Compensate for the extra DoF in stereo */ + den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0)); + + NClogN = den*(m->logN[j] + logM); + + /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET + compared to their "fair share" of total/N */ + offset = (NClogN>>1)-den*FINE_OFFSET; + + /* N=2 is the only point that doesn't match the curve */ + if (N==2) + offset += den<>2; + + /* Changing the offset for allocating the second and third + fine energy bit */ + if (bits[j] + offset < den*2<>2; + else if (bits[j] + offset < den*3<>3; + + /* Divide with rounding */ + ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1)))); + ebits[j] = celt_udiv(ebits[j], den)>>BITRES; + + /* Make sure not to bust */ + if (C*ebits[j] > (bits[j]>>BITRES)) + ebits[j] = bits[j] >> stereo >> BITRES; + + /* More than that is useless because that's about as far as PVQ can go */ + ebits[j] = IMIN(ebits[j], MAX_FINE_BITS); + + /* If we rounded down or capped this band, make it a candidate for the + final fine energy pass */ + fine_priority[j] = ebits[j]*(den<= bits[j]+offset; + + /* Remove the allocated fine bits; the rest are assigned to PVQ */ + bits[j] -= C*ebits[j]< 0) + { + int extra_fine; + int extra_bits; + extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]); + ebits[j] += extra_fine; + extra_bits = extra_fine*C<= excess-balance; + excess -= extra_bits; + } + balance = excess; + + celt_assert(bits[j] >= 0); + celt_assert(ebits[j] >= 0); + } + /* Save any remaining bits over the cap for the rebalancing in + quant_all_bands(). */ + *_balance = balance; + + /* The skipped bands use all their bits for fine energy. */ + for (;j> stereo >> BITRES; + celt_assert(C*ebits[j]<nbEBands; + skip_start = start; + /* Reserve a bit to signal the end of manually skipped bands. */ + skip_rsv = total >= 1<total) + intensity_rsv = 0; + else + { + total -= intensity_rsv; + dual_stereo_rsv = total>=1<eBands[j+1]-m->eBands[j])<>4); + /* Tilt of the allocation curve */ + trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1) + *(1<<(LM+BITRES))>>6; + /* Giving less resolution to single-coefficient bands because they get + more benefit from having one coarse value per coefficient*/ + if ((m->eBands[j+1]-m->eBands[j])<nbAllocVectors - 1; + do + { + int done = 0; + int psum = 0; + int mid = (lo+hi) >> 1; + for (j=end;j-->start;) + { + int bitsj; + int N = m->eBands[j+1]-m->eBands[j]; + bitsj = C*N*m->allocVectors[mid*len+j]<>2; + if (bitsj > 0) + bitsj = IMAX(0, bitsj + trim_offset[j]); + bitsj += offsets[j]; + if (bitsj >= thresh[j] || done) + { + done = 1; + /* Don't allocate more than we can actually use */ + psum += IMIN(bitsj, cap[j]); + } else { + if (bitsj >= C< total) + hi = mid - 1; + else + lo = mid + 1; + /*printf ("lo = %d, hi = %d\n", lo, hi);*/ + } + while (lo <= hi); + hi = lo--; + /*printf ("interp between %d and %d\n", lo, hi);*/ + for (j=start;jeBands[j+1]-m->eBands[j]; + bits1j = C*N*m->allocVectors[lo*len+j]<>2; + bits2j = hi>=m->nbAllocVectors ? + cap[j] : C*N*m->allocVectors[hi*len+j]<>2; + if (bits1j > 0) + bits1j = IMAX(0, bits1j + trim_offset[j]); + if (bits2j > 0) + bits2j = IMAX(0, bits2j + trim_offset[j]); + if (lo > 0) + bits1j += offsets[j]; + bits2j += offsets[j]; + if (offsets[j]>0) + skip_start = j; + bits2j = IMAX(0,bits2j-bits1j); + bits1[j] = bits1j; + bits2[j] = bits2j; + } + codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap, + total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv, + pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth); + RESTORE_STACK; + return codedBands; +} + diff --git a/src/libopus/celt/rate.h b/src/libopus/celt/rate.h new file mode 100644 index 00000000..fad5e412 --- /dev/null +++ b/src/libopus/celt/rate.h @@ -0,0 +1,101 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RATE_H +#define RATE_H + +#define MAX_PSEUDO 40 +#define LOG_MAX_PSEUDO 6 + +#define CELT_MAX_PULSES 128 + +#define MAX_FINE_BITS 8 + +#define FINE_OFFSET 21 +#define QTHETA_OFFSET 4 +#define QTHETA_OFFSET_TWOPHASE 16 + +#include "cwrs.h" +#include "modes.h" + +void compute_pulse_cache(CELTMode *m, int LM); + +static OPUS_INLINE int get_pulses(int i) +{ + return i<8 ? i : (8 + (i&7)) << ((i>>3)-1); +} + +static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits) +{ + int i; + int lo, hi; + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + + lo = 0; + hi = cache[0]; + bits--; + for (i=0;i>1; + /* OPT: Make sure this is implemented with a conditional move */ + if ((int)cache[mid] >= bits) + hi = mid; + else + lo = mid; + } + if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits) + return lo; + else + return hi; +} + +static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses) +{ + const unsigned char *cache; + + LM++; + cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band]; + return pulses == 0 ? 0 : cache[pulses]+1; +} + +/** Compute the pulse allocation, i.e. how many pulses will go in each + * band. + @param m mode + @param offsets Requested increase or decrease in the number of bits for + each band + @param total Number of bands + @param pulses Number of pulses per band (returned) + @return Total number of bits allocated +*/ +int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo, + opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth); + +#endif diff --git a/src/libopus/celt/stack_alloc.h b/src/libopus/celt/stack_alloc.h new file mode 100644 index 00000000..a05120bd --- /dev/null +++ b/src/libopus/celt/stack_alloc.h @@ -0,0 +1,184 @@ +/* Copyright (C) 2002-2003 Jean-Marc Valin + Copyright (C) 2007-2009 Xiph.Org Foundation */ +/** + @file stack_alloc.h + @brief Temporary memory allocation on stack +*/ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef STACK_ALLOC_H +#define STACK_ALLOC_H + +#include "../opus_types.h" +#include "../opus_defines.h" + +#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK)) +#error "Opus requires one of VAR_ARRAYS, USE_ALLOCA, or NONTHREADSAFE_PSEUDOSTACK be defined to select the temporary allocation mode." +#endif + +#ifdef USE_ALLOCA +# ifdef WIN32 +# include +# else +# ifdef HAVE_ALLOCA_H +# include +# else +# include +# endif +# endif +#endif + +/** + * @def ALIGN(stack, size) + * + * Aligns the stack to a 'size' boundary + * + * @param stack Stack + * @param size New size boundary + */ + +/** + * @def PUSH(stack, size, type) + * + * Allocates 'size' elements of type 'type' on the stack + * + * @param stack Stack + * @param size Number of elements + * @param type Type of element + */ + +/** + * @def VARDECL(var) + * + * Declare variable on stack + * + * @param var Variable to declare + */ + +/** + * @def ALLOC(var, size, type) + * + * Allocate 'size' elements of 'type' on stack + * + * @param var Name of variable to allocate + * @param size Number of elements + * @param type Type of element + */ + +#if defined(VAR_ARRAYS) + +#define VARDECL(type, var) +#define ALLOC(var, size, type) type var[size] +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +/* C99 does not allow VLAs of size zero */ +#define ALLOC_NONE 1 + +#elif defined(USE_ALLOCA) + +#define VARDECL(type, var) type *var + +# ifdef WIN32 +# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size))) +# else +# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size))) +# endif + +#define SAVE_STACK +#define RESTORE_STACK +#define ALLOC_STACK +#define ALLOC_NONE 0 + +#else + +#ifdef CELT_C +char *scratch_ptr=0; +char *global_stack=0; +#else +extern char *global_stack; +extern char *scratch_ptr; +#endif /* CELT_C */ + +#ifdef ENABLE_VALGRIND + +#include + +#ifdef CELT_C +char *global_stack_top=0; +#else +extern char *global_stack_top; +#endif /* CELT_C */ + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char)))) +#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)) +#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack; + +#else + +#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1)) +#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char)))) +#if 0 /* Set this to 1 to instrument pseudostack usage */ +#define RESTORE_STACK (printf("%ld %s:%d\n", global_stack-scratch_ptr, __FILE__, __LINE__),global_stack = _saved_stack) +#else +#define RESTORE_STACK (global_stack = _saved_stack) +#endif +#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? (scratch_ptr=opus_alloc_scratch(GLOBAL_STACK_SIZE)) : global_stack); _saved_stack = global_stack; + +#endif /* ENABLE_VALGRIND */ + +#include "os_support.h" +#define VARDECL(type, var) type *var +#define ALLOC(var, size, type) var = PUSH(global_stack, size, type) +#define SAVE_STACK char *_saved_stack = global_stack; +#define ALLOC_NONE 0 + +#endif /* VAR_ARRAYS */ + + +#ifdef ENABLE_VALGRIND + +#include +#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr)) +#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value) +#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0) +#define OPUS_FPRINTF fprintf + +#else + +static OPUS_INLINE int _opus_false(void) {return 0;} +#define OPUS_CHECK_ARRAY(ptr, len) _opus_false() +#define OPUS_CHECK_VALUE(value) _opus_false() +#define OPUS_PRINT_INT(value) do{}while(0) +#define OPUS_FPRINTF (void) + +#endif + + +#endif /* STACK_ALLOC_H */ diff --git a/src/libopus/celt/static_modes_fixed.h b/src/libopus/celt/static_modes_fixed.h new file mode 100644 index 00000000..8717d626 --- /dev/null +++ b/src/libopus/celt/static_modes_fixed.h @@ -0,0 +1,892 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_fixed_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +2, 20, 55, 108, 178, +266, 372, 494, 635, 792, +966, 1157, 1365, 1590, 1831, +2089, 2362, 2651, 2956, 3276, +3611, 3961, 4325, 4703, 5094, +5499, 5916, 6346, 6788, 7241, +7705, 8179, 8663, 9156, 9657, +10167, 10684, 11207, 11736, 12271, +12810, 13353, 13899, 14447, 14997, +15547, 16098, 16648, 17197, 17744, +18287, 18827, 19363, 19893, 20418, +20936, 21447, 21950, 22445, 22931, +23407, 23874, 24330, 24774, 25208, +25629, 26039, 26435, 26819, 27190, +27548, 27893, 28224, 28541, 28845, +29135, 29411, 29674, 29924, 30160, +30384, 30594, 30792, 30977, 31151, +31313, 31463, 31602, 31731, 31849, +31958, 32057, 32148, 32229, 32303, +32370, 32429, 32481, 32528, 32568, +32604, 32634, 32661, 32683, 32701, +32717, 32729, 32740, 32748, 32754, +32758, 32762, 32764, 32766, 32767, +32767, 32767, 32767, 32767, 32767, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{32767, 0}, {32766, -429}, +{32757, -858}, {32743, -1287}, +{32724, -1715}, {32698, -2143}, +{32667, -2570}, {32631, -2998}, +{32588, -3425}, {32541, -3851}, +{32488, -4277}, {32429, -4701}, +{32364, -5125}, {32295, -5548}, +{32219, -5971}, {32138, -6393}, +{32051, -6813}, {31960, -7231}, +{31863, -7650}, {31760, -8067}, +{31652, -8481}, {31539, -8895}, +{31419, -9306}, {31294, -9716}, +{31165, -10126}, {31030, -10532}, +{30889, -10937}, {30743, -11340}, +{30592, -11741}, {30436, -12141}, +{30274, -12540}, {30107, -12935}, +{29936, -13328}, {29758, -13718}, +{29577, -14107}, {29390, -14493}, +{29197, -14875}, {29000, -15257}, +{28797, -15635}, {28590, -16010}, +{28379, -16384}, {28162, -16753}, +{27940, -17119}, {27714, -17484}, +{27482, -17845}, {27246, -18205}, +{27006, -18560}, {26760, -18911}, +{26510, -19260}, {26257, -19606}, +{25997, -19947}, {25734, -20286}, +{25466, -20621}, {25194, -20952}, +{24918, -21281}, {24637, -21605}, +{24353, -21926}, {24063, -22242}, +{23770, -22555}, {23473, -22865}, +{23171, -23171}, {22866, -23472}, +{22557, -23769}, {22244, -24063}, +{21927, -24352}, {21606, -24636}, +{21282, -24917}, {20954, -25194}, +{20622, -25465}, {20288, -25733}, +{19949, -25997}, {19607, -26255}, +{19261, -26509}, {18914, -26760}, +{18561, -27004}, {18205, -27246}, +{17846, -27481}, {17485, -27713}, +{17122, -27940}, {16755, -28162}, +{16385, -28378}, {16012, -28590}, +{15636, -28797}, {15258, -28999}, +{14878, -29197}, {14494, -29389}, +{14108, -29576}, {13720, -29757}, +{13329, -29934}, {12937, -30107}, +{12540, -30274}, {12142, -30435}, +{11744, -30592}, {11342, -30743}, +{10939, -30889}, {10534, -31030}, +{10127, -31164}, {9718, -31294}, +{9307, -31418}, {8895, -31537}, +{8482, -31652}, {8067, -31759}, +{7650, -31862}, {7233, -31960}, +{6815, -32051}, {6393, -32138}, +{5973, -32219}, {5549, -32294}, +{5127, -32364}, {4703, -32429}, +{4278, -32487}, {3852, -32541}, +{3426, -32588}, {2999, -32630}, +{2572, -32667}, {2144, -32698}, +{1716, -32724}, {1287, -32742}, +{860, -32757}, {430, -32766}, +{0, -32767}, {-429, -32766}, +{-858, -32757}, {-1287, -32743}, +{-1715, -32724}, {-2143, -32698}, +{-2570, -32667}, {-2998, -32631}, +{-3425, -32588}, {-3851, -32541}, +{-4277, -32488}, {-4701, -32429}, +{-5125, -32364}, {-5548, -32295}, +{-5971, -32219}, {-6393, -32138}, +{-6813, -32051}, {-7231, -31960}, +{-7650, -31863}, {-8067, -31760}, +{-8481, -31652}, {-8895, -31539}, +{-9306, -31419}, {-9716, -31294}, +{-10126, -31165}, {-10532, -31030}, +{-10937, -30889}, {-11340, -30743}, +{-11741, -30592}, {-12141, -30436}, +{-12540, -30274}, {-12935, -30107}, +{-13328, -29936}, {-13718, -29758}, +{-14107, -29577}, {-14493, -29390}, +{-14875, -29197}, {-15257, -29000}, +{-15635, -28797}, {-16010, -28590}, +{-16384, -28379}, {-16753, -28162}, +{-17119, -27940}, {-17484, -27714}, +{-17845, -27482}, {-18205, -27246}, +{-18560, -27006}, {-18911, -26760}, +{-19260, -26510}, {-19606, -26257}, +{-19947, -25997}, {-20286, -25734}, +{-20621, -25466}, {-20952, -25194}, +{-21281, -24918}, {-21605, -24637}, +{-21926, -24353}, {-22242, -24063}, +{-22555, -23770}, {-22865, -23473}, +{-23171, -23171}, {-23472, -22866}, +{-23769, -22557}, {-24063, -22244}, +{-24352, -21927}, {-24636, -21606}, +{-24917, -21282}, {-25194, -20954}, +{-25465, -20622}, {-25733, -20288}, +{-25997, -19949}, {-26255, -19607}, +{-26509, -19261}, {-26760, -18914}, +{-27004, -18561}, {-27246, -18205}, +{-27481, -17846}, {-27713, -17485}, +{-27940, -17122}, {-28162, -16755}, +{-28378, -16385}, {-28590, -16012}, +{-28797, -15636}, {-28999, -15258}, +{-29197, -14878}, {-29389, -14494}, +{-29576, -14108}, {-29757, -13720}, +{-29934, -13329}, {-30107, -12937}, +{-30274, -12540}, {-30435, -12142}, +{-30592, -11744}, {-30743, -11342}, +{-30889, -10939}, {-31030, -10534}, +{-31164, -10127}, {-31294, -9718}, +{-31418, -9307}, {-31537, -8895}, +{-31652, -8482}, {-31759, -8067}, +{-31862, -7650}, {-31960, -7233}, +{-32051, -6815}, {-32138, -6393}, +{-32219, -5973}, {-32294, -5549}, +{-32364, -5127}, {-32429, -4703}, +{-32487, -4278}, {-32541, -3852}, +{-32588, -3426}, {-32630, -2999}, +{-32667, -2572}, {-32698, -2144}, +{-32724, -1716}, {-32742, -1287}, +{-32757, -860}, {-32766, -430}, +{-32767, 0}, {-32766, 429}, +{-32757, 858}, {-32743, 1287}, +{-32724, 1715}, {-32698, 2143}, +{-32667, 2570}, {-32631, 2998}, +{-32588, 3425}, {-32541, 3851}, +{-32488, 4277}, {-32429, 4701}, +{-32364, 5125}, {-32295, 5548}, +{-32219, 5971}, {-32138, 6393}, +{-32051, 6813}, {-31960, 7231}, +{-31863, 7650}, {-31760, 8067}, +{-31652, 8481}, {-31539, 8895}, +{-31419, 9306}, {-31294, 9716}, +{-31165, 10126}, {-31030, 10532}, +{-30889, 10937}, {-30743, 11340}, +{-30592, 11741}, {-30436, 12141}, +{-30274, 12540}, {-30107, 12935}, +{-29936, 13328}, {-29758, 13718}, +{-29577, 14107}, {-29390, 14493}, +{-29197, 14875}, {-29000, 15257}, +{-28797, 15635}, {-28590, 16010}, +{-28379, 16384}, {-28162, 16753}, +{-27940, 17119}, {-27714, 17484}, +{-27482, 17845}, {-27246, 18205}, +{-27006, 18560}, {-26760, 18911}, +{-26510, 19260}, {-26257, 19606}, +{-25997, 19947}, {-25734, 20286}, +{-25466, 20621}, {-25194, 20952}, +{-24918, 21281}, {-24637, 21605}, +{-24353, 21926}, {-24063, 22242}, +{-23770, 22555}, {-23473, 22865}, +{-23171, 23171}, {-22866, 23472}, +{-22557, 23769}, {-22244, 24063}, +{-21927, 24352}, {-21606, 24636}, +{-21282, 24917}, {-20954, 25194}, +{-20622, 25465}, {-20288, 25733}, +{-19949, 25997}, {-19607, 26255}, +{-19261, 26509}, {-18914, 26760}, +{-18561, 27004}, {-18205, 27246}, +{-17846, 27481}, {-17485, 27713}, +{-17122, 27940}, {-16755, 28162}, +{-16385, 28378}, {-16012, 28590}, +{-15636, 28797}, {-15258, 28999}, +{-14878, 29197}, {-14494, 29389}, +{-14108, 29576}, {-13720, 29757}, +{-13329, 29934}, {-12937, 30107}, +{-12540, 30274}, {-12142, 30435}, +{-11744, 30592}, {-11342, 30743}, +{-10939, 30889}, {-10534, 31030}, +{-10127, 31164}, {-9718, 31294}, +{-9307, 31418}, {-8895, 31537}, +{-8482, 31652}, {-8067, 31759}, +{-7650, 31862}, {-7233, 31960}, +{-6815, 32051}, {-6393, 32138}, +{-5973, 32219}, {-5549, 32294}, +{-5127, 32364}, {-4703, 32429}, +{-4278, 32487}, {-3852, 32541}, +{-3426, 32588}, {-2999, 32630}, +{-2572, 32667}, {-2144, 32698}, +{-1716, 32724}, {-1287, 32742}, +{-860, 32757}, {-430, 32766}, +{0, 32767}, {429, 32766}, +{858, 32757}, {1287, 32743}, +{1715, 32724}, {2143, 32698}, +{2570, 32667}, {2998, 32631}, +{3425, 32588}, {3851, 32541}, +{4277, 32488}, {4701, 32429}, +{5125, 32364}, {5548, 32295}, +{5971, 32219}, {6393, 32138}, +{6813, 32051}, {7231, 31960}, +{7650, 31863}, {8067, 31760}, +{8481, 31652}, {8895, 31539}, +{9306, 31419}, {9716, 31294}, +{10126, 31165}, {10532, 31030}, +{10937, 30889}, {11340, 30743}, +{11741, 30592}, {12141, 30436}, +{12540, 30274}, {12935, 30107}, +{13328, 29936}, {13718, 29758}, +{14107, 29577}, {14493, 29390}, +{14875, 29197}, {15257, 29000}, +{15635, 28797}, {16010, 28590}, +{16384, 28379}, {16753, 28162}, +{17119, 27940}, {17484, 27714}, +{17845, 27482}, {18205, 27246}, +{18560, 27006}, {18911, 26760}, +{19260, 26510}, {19606, 26257}, +{19947, 25997}, {20286, 25734}, +{20621, 25466}, {20952, 25194}, +{21281, 24918}, {21605, 24637}, +{21926, 24353}, {22242, 24063}, +{22555, 23770}, {22865, 23473}, +{23171, 23171}, {23472, 22866}, +{23769, 22557}, {24063, 22244}, +{24352, 21927}, {24636, 21606}, +{24917, 21282}, {25194, 20954}, +{25465, 20622}, {25733, 20288}, +{25997, 19949}, {26255, 19607}, +{26509, 19261}, {26760, 18914}, +{27004, 18561}, {27246, 18205}, +{27481, 17846}, {27713, 17485}, +{27940, 17122}, {28162, 16755}, +{28378, 16385}, {28590, 16012}, +{28797, 15636}, {28999, 15258}, +{29197, 14878}, {29389, 14494}, +{29576, 14108}, {29757, 13720}, +{29934, 13329}, {30107, 12937}, +{30274, 12540}, {30435, 12142}, +{30592, 11744}, {30743, 11342}, +{30889, 10939}, {31030, 10534}, +{31164, 10127}, {31294, 9718}, +{31418, 9307}, {31537, 8895}, +{31652, 8482}, {31759, 8067}, +{31862, 7650}, {31960, 7233}, +{32051, 6815}, {32138, 6393}, +{32219, 5973}, {32294, 5549}, +{32364, 5127}, {32429, 4703}, +{32487, 4278}, {32541, 3852}, +{32588, 3426}, {32630, 2999}, +{32667, 2572}, {32698, 2144}, +{32724, 1716}, {32742, 1287}, +{32757, 860}, {32766, 430}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, +8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, +16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, +24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, +4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, +12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, +20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, +28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, +1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, +9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, +17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, +25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, +5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, +13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, +21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, +29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, +2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, +10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, +18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, +26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, +6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, +14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, +22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, +30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, +3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, +11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, +19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, +27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, +7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, +15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, +23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, +31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, +4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, +8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, +12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, +1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, +5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, +9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, +13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, +2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, +6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, +10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, +14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, +3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, +7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, +11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, +15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, +4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, +1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, +5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, +2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, +6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, +3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, +7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, +1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, +2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, +3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +17476, /* scale */ +8, /* scale_shift */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +17476, /* scale */ +7, /* scale_shift */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +17476, /* scale */ +6, /* scale_shift */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +17476, /* scale */ +5, /* scale_shift */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +32767, 32767, 32767, 32766, 32765, +32763, 32761, 32759, 32756, 32753, +32750, 32746, 32742, 32738, 32733, +32728, 32722, 32717, 32710, 32704, +32697, 32690, 32682, 32674, 32666, +32657, 32648, 32639, 32629, 32619, +32609, 32598, 32587, 32576, 32564, +32552, 32539, 32526, 32513, 32500, +32486, 32472, 32457, 32442, 32427, +32411, 32395, 32379, 32362, 32345, +32328, 32310, 32292, 32274, 32255, +32236, 32217, 32197, 32177, 32157, +32136, 32115, 32093, 32071, 32049, +32027, 32004, 31981, 31957, 31933, +31909, 31884, 31859, 31834, 31809, +31783, 31756, 31730, 31703, 31676, +31648, 31620, 31592, 31563, 31534, +31505, 31475, 31445, 31415, 31384, +31353, 31322, 31290, 31258, 31226, +31193, 31160, 31127, 31093, 31059, +31025, 30990, 30955, 30920, 30884, +30848, 30812, 30775, 30738, 30701, +30663, 30625, 30587, 30548, 30509, +30470, 30430, 30390, 30350, 30309, +30269, 30227, 30186, 30144, 30102, +30059, 30016, 29973, 29930, 29886, +29842, 29797, 29752, 29707, 29662, +29616, 29570, 29524, 29477, 29430, +29383, 29335, 29287, 29239, 29190, +29142, 29092, 29043, 28993, 28943, +28892, 28842, 28791, 28739, 28688, +28636, 28583, 28531, 28478, 28425, +28371, 28317, 28263, 28209, 28154, +28099, 28044, 27988, 27932, 27876, +27820, 27763, 27706, 27648, 27591, +27533, 27474, 27416, 27357, 27298, +27238, 27178, 27118, 27058, 26997, +26936, 26875, 26814, 26752, 26690, +26628, 26565, 26502, 26439, 26375, +26312, 26247, 26183, 26119, 26054, +25988, 25923, 25857, 25791, 25725, +25658, 25592, 25524, 25457, 25389, +25322, 25253, 25185, 25116, 25047, +24978, 24908, 24838, 24768, 24698, +24627, 24557, 24485, 24414, 24342, +24270, 24198, 24126, 24053, 23980, +23907, 23834, 23760, 23686, 23612, +23537, 23462, 23387, 23312, 23237, +23161, 23085, 23009, 22932, 22856, +22779, 22701, 22624, 22546, 22468, +22390, 22312, 22233, 22154, 22075, +21996, 21916, 21836, 21756, 21676, +21595, 21515, 21434, 21352, 21271, +21189, 21107, 21025, 20943, 20860, +20777, 20694, 20611, 20528, 20444, +20360, 20276, 20192, 20107, 20022, +19937, 19852, 19767, 19681, 19595, +19509, 19423, 19336, 19250, 19163, +19076, 18988, 18901, 18813, 18725, +18637, 18549, 18460, 18372, 18283, +18194, 18104, 18015, 17925, 17835, +17745, 17655, 17565, 17474, 17383, +17292, 17201, 17110, 17018, 16927, +16835, 16743, 16650, 16558, 16465, +16372, 16279, 16186, 16093, 15999, +15906, 15812, 15718, 15624, 15529, +15435, 15340, 15245, 15150, 15055, +14960, 14864, 14769, 14673, 14577, +14481, 14385, 14288, 14192, 14095, +13998, 13901, 13804, 13706, 13609, +13511, 13414, 13316, 13218, 13119, +13021, 12923, 12824, 12725, 12626, +12527, 12428, 12329, 12230, 12130, +12030, 11930, 11831, 11730, 11630, +11530, 11430, 11329, 11228, 11128, +11027, 10926, 10824, 10723, 10622, +10520, 10419, 10317, 10215, 10113, +10011, 9909, 9807, 9704, 9602, +9499, 9397, 9294, 9191, 9088, +8985, 8882, 8778, 8675, 8572, +8468, 8364, 8261, 8157, 8053, +7949, 7845, 7741, 7637, 7532, +7428, 7323, 7219, 7114, 7009, +6905, 6800, 6695, 6590, 6485, +6380, 6274, 6169, 6064, 5958, +5853, 5747, 5642, 5536, 5430, +5325, 5219, 5113, 5007, 4901, +4795, 4689, 4583, 4476, 4370, +4264, 4157, 4051, 3945, 3838, +3732, 3625, 3518, 3412, 3305, +3198, 3092, 2985, 2878, 2771, +2664, 2558, 2451, 2344, 2237, +2130, 2023, 1916, 1809, 1702, +1594, 1487, 1380, 1273, 1166, +1059, 952, 844, 737, 630, +523, 416, 308, 201, 94, +-13, -121, -228, -335, -442, +-550, -657, -764, -871, -978, +-1086, -1193, -1300, -1407, -1514, +-1621, -1728, -1835, -1942, -2049, +-2157, -2263, -2370, -2477, -2584, +-2691, -2798, -2905, -3012, -3118, +-3225, -3332, -3439, -3545, -3652, +-3758, -3865, -3971, -4078, -4184, +-4290, -4397, -4503, -4609, -4715, +-4821, -4927, -5033, -5139, -5245, +-5351, -5457, -5562, -5668, -5774, +-5879, -5985, -6090, -6195, -6301, +-6406, -6511, -6616, -6721, -6826, +-6931, -7036, -7140, -7245, -7349, +-7454, -7558, -7663, -7767, -7871, +-7975, -8079, -8183, -8287, -8390, +-8494, -8597, -8701, -8804, -8907, +-9011, -9114, -9217, -9319, -9422, +-9525, -9627, -9730, -9832, -9934, +-10037, -10139, -10241, -10342, -10444, +-10546, -10647, -10748, -10850, -10951, +-11052, -11153, -11253, -11354, -11455, +-11555, -11655, -11756, -11856, -11955, +-12055, -12155, -12254, -12354, -12453, +-12552, -12651, -12750, -12849, -12947, +-13046, -13144, -13242, -13340, -13438, +-13536, -13633, -13731, -13828, -13925, +-14022, -14119, -14216, -14312, -14409, +-14505, -14601, -14697, -14793, -14888, +-14984, -15079, -15174, -15269, -15364, +-15459, -15553, -15647, -15741, -15835, +-15929, -16023, -16116, -16210, -16303, +-16396, -16488, -16581, -16673, -16766, +-16858, -16949, -17041, -17133, -17224, +-17315, -17406, -17497, -17587, -17678, +-17768, -17858, -17948, -18037, -18127, +-18216, -18305, -18394, -18483, -18571, +-18659, -18747, -18835, -18923, -19010, +-19098, -19185, -19271, -19358, -19444, +-19531, -19617, -19702, -19788, -19873, +-19959, -20043, -20128, -20213, -20297, +-20381, -20465, -20549, -20632, -20715, +-20798, -20881, -20963, -21046, -21128, +-21210, -21291, -21373, -21454, -21535, +-21616, -21696, -21776, -21856, -21936, +-22016, -22095, -22174, -22253, -22331, +-22410, -22488, -22566, -22643, -22721, +-22798, -22875, -22951, -23028, -23104, +-23180, -23256, -23331, -23406, -23481, +-23556, -23630, -23704, -23778, -23852, +-23925, -23998, -24071, -24144, -24216, +-24288, -24360, -24432, -24503, -24574, +-24645, -24716, -24786, -24856, -24926, +-24995, -25064, -25133, -25202, -25270, +-25339, -25406, -25474, -25541, -25608, +-25675, -25742, -25808, -25874, -25939, +-26005, -26070, -26135, -26199, -26264, +-26327, -26391, -26455, -26518, -26581, +-26643, -26705, -26767, -26829, -26891, +-26952, -27013, -27073, -27133, -27193, +-27253, -27312, -27372, -27430, -27489, +-27547, -27605, -27663, -27720, -27777, +-27834, -27890, -27946, -28002, -28058, +-28113, -28168, -28223, -28277, -28331, +-28385, -28438, -28491, -28544, -28596, +-28649, -28701, -28752, -28803, -28854, +-28905, -28955, -29006, -29055, -29105, +-29154, -29203, -29251, -29299, -29347, +-29395, -29442, -29489, -29535, -29582, +-29628, -29673, -29719, -29764, -29808, +-29853, -29897, -29941, -29984, -30027, +-30070, -30112, -30154, -30196, -30238, +-30279, -30320, -30360, -30400, -30440, +-30480, -30519, -30558, -30596, -30635, +-30672, -30710, -30747, -30784, -30821, +-30857, -30893, -30929, -30964, -30999, +-31033, -31068, -31102, -31135, -31168, +-31201, -31234, -31266, -31298, -31330, +-31361, -31392, -31422, -31453, -31483, +-31512, -31541, -31570, -31599, -31627, +-31655, -31682, -31710, -31737, -31763, +-31789, -31815, -31841, -31866, -31891, +-31915, -31939, -31963, -31986, -32010, +-32032, -32055, -32077, -32099, -32120, +-32141, -32162, -32182, -32202, -32222, +-32241, -32260, -32279, -32297, -32315, +-32333, -32350, -32367, -32383, -32399, +-32415, -32431, -32446, -32461, -32475, +-32489, -32503, -32517, -32530, -32542, +-32555, -32567, -32579, -32590, -32601, +-32612, -32622, -32632, -32641, -32651, +-32659, -32668, -32676, -32684, -32692, +-32699, -32706, -32712, -32718, -32724, +-32729, -32734, -32739, -32743, -32747, +-32751, -32754, -32757, -32760, -32762, +-32764, -32765, -32767, -32767, -32767, +32767, 32767, 32765, 32761, 32756, +32750, 32742, 32732, 32722, 32710, +32696, 32681, 32665, 32647, 32628, +32608, 32586, 32562, 32538, 32512, +32484, 32455, 32425, 32393, 32360, +32326, 32290, 32253, 32214, 32174, +32133, 32090, 32046, 32001, 31954, +31906, 31856, 31805, 31753, 31700, +31645, 31588, 31530, 31471, 31411, +31349, 31286, 31222, 31156, 31089, +31020, 30951, 30880, 30807, 30733, +30658, 30582, 30504, 30425, 30345, +30263, 30181, 30096, 30011, 29924, +29836, 29747, 29656, 29564, 29471, +29377, 29281, 29184, 29086, 28987, +28886, 28784, 28681, 28577, 28471, +28365, 28257, 28147, 28037, 27925, +27812, 27698, 27583, 27467, 27349, +27231, 27111, 26990, 26868, 26744, +26620, 26494, 26367, 26239, 26110, +25980, 25849, 25717, 25583, 25449, +25313, 25176, 25038, 24900, 24760, +24619, 24477, 24333, 24189, 24044, +23898, 23751, 23602, 23453, 23303, +23152, 22999, 22846, 22692, 22537, +22380, 22223, 22065, 21906, 21746, +21585, 21423, 21261, 21097, 20933, +20767, 20601, 20434, 20265, 20096, +19927, 19756, 19584, 19412, 19239, +19065, 18890, 18714, 18538, 18361, +18183, 18004, 17824, 17644, 17463, +17281, 17098, 16915, 16731, 16546, +16361, 16175, 15988, 15800, 15612, +15423, 15234, 15043, 14852, 14661, +14469, 14276, 14083, 13889, 13694, +13499, 13303, 13107, 12910, 12713, +12515, 12317, 12118, 11918, 11718, +11517, 11316, 11115, 10913, 10710, +10508, 10304, 10100, 9896, 9691, +9486, 9281, 9075, 8869, 8662, +8455, 8248, 8040, 7832, 7623, +7415, 7206, 6996, 6787, 6577, +6366, 6156, 5945, 5734, 5523, +5311, 5100, 4888, 4675, 4463, +4251, 4038, 3825, 3612, 3399, +3185, 2972, 2758, 2544, 2330, +2116, 1902, 1688, 1474, 1260, +1045, 831, 617, 402, 188, +-27, -241, -456, -670, -885, +-1099, -1313, -1528, -1742, -1956, +-2170, -2384, -2598, -2811, -3025, +-3239, -3452, -3665, -3878, -4091, +-4304, -4516, -4728, -4941, -5153, +-5364, -5576, -5787, -5998, -6209, +-6419, -6629, -6839, -7049, -7258, +-7467, -7676, -7884, -8092, -8300, +-8507, -8714, -8920, -9127, -9332, +-9538, -9743, -9947, -10151, -10355, +-10558, -10761, -10963, -11165, -11367, +-11568, -11768, -11968, -12167, -12366, +-12565, -12762, -12960, -13156, -13352, +-13548, -13743, -13937, -14131, -14324, +-14517, -14709, -14900, -15091, -15281, +-15470, -15659, -15847, -16035, -16221, +-16407, -16593, -16777, -16961, -17144, +-17326, -17508, -17689, -17869, -18049, +-18227, -18405, -18582, -18758, -18934, +-19108, -19282, -19455, -19627, -19799, +-19969, -20139, -20308, -20475, -20642, +-20809, -20974, -21138, -21301, -21464, +-21626, -21786, -21946, -22105, -22263, +-22420, -22575, -22730, -22884, -23037, +-23189, -23340, -23490, -23640, -23788, +-23935, -24080, -24225, -24369, -24512, +-24654, -24795, -24934, -25073, -25211, +-25347, -25482, -25617, -25750, -25882, +-26013, -26143, -26272, -26399, -26526, +-26651, -26775, -26898, -27020, -27141, +-27260, -27379, -27496, -27612, -27727, +-27841, -27953, -28065, -28175, -28284, +-28391, -28498, -28603, -28707, -28810, +-28911, -29012, -29111, -29209, -29305, +-29401, -29495, -29587, -29679, -29769, +-29858, -29946, -30032, -30118, -30201, +-30284, -30365, -30445, -30524, -30601, +-30677, -30752, -30825, -30897, -30968, +-31038, -31106, -31172, -31238, -31302, +-31365, -31426, -31486, -31545, -31602, +-31658, -31713, -31766, -31818, -31869, +-31918, -31966, -32012, -32058, -32101, +-32144, -32185, -32224, -32262, -32299, +-32335, -32369, -32401, -32433, -32463, +-32491, -32518, -32544, -32568, -32591, +-32613, -32633, -32652, -32669, -32685, +-32700, -32713, -32724, -32735, -32744, +-32751, -32757, -32762, -32766, -32767, +32767, 32764, 32755, 32741, 32720, +32694, 32663, 32626, 32583, 32535, +32481, 32421, 32356, 32286, 32209, +32128, 32041, 31948, 31850, 31747, +31638, 31523, 31403, 31278, 31148, +31012, 30871, 30724, 30572, 30415, +30253, 30086, 29913, 29736, 29553, +29365, 29172, 28974, 28771, 28564, +28351, 28134, 27911, 27684, 27452, +27216, 26975, 26729, 26478, 26223, +25964, 25700, 25432, 25159, 24882, +24601, 24315, 24026, 23732, 23434, +23133, 22827, 22517, 22204, 21886, +21565, 21240, 20912, 20580, 20244, +19905, 19563, 19217, 18868, 18516, +18160, 17802, 17440, 17075, 16708, +16338, 15964, 15588, 15210, 14829, +14445, 14059, 13670, 13279, 12886, +12490, 12093, 11693, 11291, 10888, +10482, 10075, 9666, 9255, 8843, +8429, 8014, 7597, 7180, 6760, +6340, 5919, 5496, 5073, 4649, +4224, 3798, 3372, 2945, 2517, +2090, 1661, 1233, 804, 375, +-54, -483, -911, -1340, -1768, +-2197, -2624, -3052, -3479, -3905, +-4330, -4755, -5179, -5602, -6024, +-6445, -6865, -7284, -7702, -8118, +-8533, -8946, -9358, -9768, -10177, +-10584, -10989, -11392, -11793, -12192, +-12589, -12984, -13377, -13767, -14155, +-14541, -14924, -15305, -15683, -16058, +-16430, -16800, -17167, -17531, -17892, +-18249, -18604, -18956, -19304, -19649, +-19990, -20329, -20663, -20994, -21322, +-21646, -21966, -22282, -22595, -22904, +-23208, -23509, -23806, -24099, -24387, +-24672, -24952, -25228, -25499, -25766, +-26029, -26288, -26541, -26791, -27035, +-27275, -27511, -27741, -27967, -28188, +-28405, -28616, -28823, -29024, -29221, +-29412, -29599, -29780, -29957, -30128, +-30294, -30455, -30611, -30761, -30906, +-31046, -31181, -31310, -31434, -31552, +-31665, -31773, -31875, -31972, -32063, +-32149, -32229, -32304, -32373, -32437, +-32495, -32547, -32594, -32635, -32671, +-32701, -32726, -32745, -32758, -32766, +32767, 32754, 32717, 32658, 32577, +32473, 32348, 32200, 32029, 31837, +31624, 31388, 31131, 30853, 30553, +30232, 29891, 29530, 29148, 28746, +28324, 27883, 27423, 26944, 26447, +25931, 25398, 24847, 24279, 23695, +23095, 22478, 21846, 21199, 20538, +19863, 19174, 18472, 17757, 17030, +16291, 15541, 14781, 14010, 13230, +12441, 11643, 10837, 10024, 9204, +8377, 7545, 6708, 5866, 5020, +4171, 3319, 2464, 1608, 751, +-107, -965, -1822, -2678, -3532, +-4383, -5232, -6077, -6918, -7754, +-8585, -9409, -10228, -11039, -11843, +-12639, -13426, -14204, -14972, -15730, +-16477, -17213, -17937, -18648, -19347, +-20033, -20705, -21363, -22006, -22634, +-23246, -23843, -24423, -24986, -25533, +-26062, -26573, -27066, -27540, -27995, +-28431, -28848, -29245, -29622, -29979, +-30315, -30630, -30924, -31197, -31449, +-31679, -31887, -32074, -32239, -32381, +-32501, -32600, -32675, -32729, -32759, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{27853, 0, 4096, 8192, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/src/libopus/celt/static_modes_float.h b/src/libopus/celt/static_modes_float.h new file mode 100644 index 00000000..e102a383 --- /dev/null +++ b/src/libopus/celt/static_modes_float.h @@ -0,0 +1,888 @@ +/* The contents of this file was automatically generated by dump_modes.c + with arguments: 48000 960 + It contains static definitions for some pre-defined modes. */ +#include "modes.h" +#include "rate.h" + +#ifdef HAVE_ARM_NE10 +#define OVERRIDE_FFT 1 +#include "static_modes_float_arm_ne10.h" +#endif + +#ifndef DEF_WINDOW120 +#define DEF_WINDOW120 +static const opus_val16 window120[120] = { +6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f, +0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f, +0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f, +0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f, +0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f, +0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f, +0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f, +0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f, +0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f, +0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f, +0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f, +0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f, +0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f, +0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f, +0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f, +0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f, +0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f, +0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f, +0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f, +0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f, +0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f, +0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f, +0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f, +0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f, +}; +#endif + +#ifndef DEF_LOGN400 +#define DEF_LOGN400 +static const opus_int16 logN400[21] = { +0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, }; +#endif + +#ifndef DEF_PULSE_CACHE50 +#define DEF_PULSE_CACHE50 +static const opus_int16 cache_index50[105] = { +-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41, +82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41, +41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41, +41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305, +318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240, +305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240, +240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387, +}; +static const unsigned char cache_bits50[392] = { +40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, +7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28, +31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50, +51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65, +66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61, +64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92, +94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123, +124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94, +97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139, +142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35, +28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149, +153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225, +229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157, +166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63, +86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250, +25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180, +185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89, +110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41, +74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138, +163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214, +228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49, +90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47, +87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57, +106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187, +224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127, +182, 234, }; +static const unsigned char cache_caps50[168] = { +224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185, +178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240, +240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160, +160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172, +138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207, +204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185, +185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39, +207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201, +188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204, +204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175, +140, 66, 40, }; +#endif + +#ifndef FFT_TWIDDLES48000_960 +#define FFT_TWIDDLES48000_960 +static const kiss_twiddle_cpx fft_twiddles48000_960[480] = { +{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f}, +{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f}, +{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f}, +{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f}, +{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f}, +{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f}, +{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f}, +{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f}, +{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f}, +{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f}, +{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f}, +{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f}, +{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f}, +{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f}, +{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f}, +{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f}, +{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f}, +{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f}, +{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f}, +{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f}, +{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f}, +{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f}, +{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f}, +{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f}, +{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f}, +{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f}, +{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f}, +{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f}, +{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f}, +{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f}, +{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f}, +{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f}, +{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f}, +{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f}, +{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f}, +{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f}, +{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f}, +{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f}, +{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f}, +{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f}, +{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f}, +{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f}, +{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f}, +{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f}, +{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f}, +{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f}, +{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f}, +{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f}, +{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f}, +{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f}, +{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f}, +{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f}, +{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f}, +{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f}, +{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f}, +{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f}, +{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f}, +{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f}, +{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f}, +{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f}, +{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f}, +{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f}, +{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f}, +{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f}, +{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f}, +{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f}, +{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f}, +{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f}, +{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f}, +{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f}, +{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f}, +{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f}, +{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f}, +{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f}, +{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f}, +{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f}, +{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f}, +{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f}, +{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f}, +{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f}, +{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f}, +{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f}, +{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f}, +{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f}, +{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f}, +{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f}, +{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f}, +{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f}, +{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f}, +{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f}, +{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f}, +{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f}, +{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f}, +{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f}, +{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f}, +{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f}, +{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f}, +{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f}, +{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f}, +{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f}, +{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f}, +{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f}, +{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f}, +{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f}, +{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f}, +{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f}, +{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f}, +{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f}, +{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f}, +{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f}, +{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f}, +{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f}, +{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f}, +{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f}, +{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f}, +{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f}, +{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f}, +{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f}, +{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f}, +{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f}, +{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f}, +{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f}, +{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f}, +{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f}, +{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f}, +{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f}, +{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f}, +{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f}, +{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f}, +{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f}, +{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f}, +{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f}, +{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f}, +{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f}, +{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f}, +{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f}, +{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f}, +{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f}, +{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f}, +{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f}, +{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f}, +{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f}, +{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f}, +{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f}, +{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f}, +{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f}, +{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f}, +{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f}, +{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f}, +{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f}, +{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f}, +{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f}, +{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f}, +{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f}, +{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f}, +{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f}, +{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f}, +{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f}, +{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f}, +{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f}, +{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f}, +{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f}, +{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f}, +{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f}, +{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f}, +{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f}, +{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f}, +{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f}, +{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f}, +{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f}, +{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f}, +{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f}, +{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f}, +{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f}, +{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f}, +{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f}, +{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f}, +{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f}, +{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f}, +{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f}, +{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f}, +{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f}, +{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f}, +{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f}, +{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f}, +{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f}, +{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f}, +{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f}, +{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f}, +{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f}, +{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f}, +{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f}, +{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f}, +{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f}, +{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f}, +{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f}, +{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f}, +{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f}, +{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f}, +{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f}, +{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f}, +{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f}, +{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f}, +{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f}, +{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f}, +{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f}, +{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f}, +{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f}, +{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f}, +{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f}, +{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f}, +{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f}, +{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f}, +{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f}, +{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f}, +{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f}, +{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f}, +{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f}, +{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f}, +{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f}, +{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f}, +{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f}, +{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f}, +{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f}, +{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f}, +{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f}, +{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f}, +{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f}, +{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f}, +{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f}, +{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f}, +{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f}, +{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f}, +{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f}, +{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f}, +{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f}, +{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f}, +{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f}, +{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f}, +{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f}, +}; +#ifndef FFT_BITREV480 +#define FFT_BITREV480 +static const opus_int16 fft_bitrev480[480] = { +0, 96, 192, 288, 384, 32, 128, 224, 320, 416, 64, 160, 256, 352, 448, +8, 104, 200, 296, 392, 40, 136, 232, 328, 424, 72, 168, 264, 360, 456, +16, 112, 208, 304, 400, 48, 144, 240, 336, 432, 80, 176, 272, 368, 464, +24, 120, 216, 312, 408, 56, 152, 248, 344, 440, 88, 184, 280, 376, 472, +4, 100, 196, 292, 388, 36, 132, 228, 324, 420, 68, 164, 260, 356, 452, +12, 108, 204, 300, 396, 44, 140, 236, 332, 428, 76, 172, 268, 364, 460, +20, 116, 212, 308, 404, 52, 148, 244, 340, 436, 84, 180, 276, 372, 468, +28, 124, 220, 316, 412, 60, 156, 252, 348, 444, 92, 188, 284, 380, 476, +1, 97, 193, 289, 385, 33, 129, 225, 321, 417, 65, 161, 257, 353, 449, +9, 105, 201, 297, 393, 41, 137, 233, 329, 425, 73, 169, 265, 361, 457, +17, 113, 209, 305, 401, 49, 145, 241, 337, 433, 81, 177, 273, 369, 465, +25, 121, 217, 313, 409, 57, 153, 249, 345, 441, 89, 185, 281, 377, 473, +5, 101, 197, 293, 389, 37, 133, 229, 325, 421, 69, 165, 261, 357, 453, +13, 109, 205, 301, 397, 45, 141, 237, 333, 429, 77, 173, 269, 365, 461, +21, 117, 213, 309, 405, 53, 149, 245, 341, 437, 85, 181, 277, 373, 469, +29, 125, 221, 317, 413, 61, 157, 253, 349, 445, 93, 189, 285, 381, 477, +2, 98, 194, 290, 386, 34, 130, 226, 322, 418, 66, 162, 258, 354, 450, +10, 106, 202, 298, 394, 42, 138, 234, 330, 426, 74, 170, 266, 362, 458, +18, 114, 210, 306, 402, 50, 146, 242, 338, 434, 82, 178, 274, 370, 466, +26, 122, 218, 314, 410, 58, 154, 250, 346, 442, 90, 186, 282, 378, 474, +6, 102, 198, 294, 390, 38, 134, 230, 326, 422, 70, 166, 262, 358, 454, +14, 110, 206, 302, 398, 46, 142, 238, 334, 430, 78, 174, 270, 366, 462, +22, 118, 214, 310, 406, 54, 150, 246, 342, 438, 86, 182, 278, 374, 470, +30, 126, 222, 318, 414, 62, 158, 254, 350, 446, 94, 190, 286, 382, 478, +3, 99, 195, 291, 387, 35, 131, 227, 323, 419, 67, 163, 259, 355, 451, +11, 107, 203, 299, 395, 43, 139, 235, 331, 427, 75, 171, 267, 363, 459, +19, 115, 211, 307, 403, 51, 147, 243, 339, 435, 83, 179, 275, 371, 467, +27, 123, 219, 315, 411, 59, 155, 251, 347, 443, 91, 187, 283, 379, 475, +7, 103, 199, 295, 391, 39, 135, 231, 327, 423, 71, 167, 263, 359, 455, +15, 111, 207, 303, 399, 47, 143, 239, 335, 431, 79, 175, 271, 367, 463, +23, 119, 215, 311, 407, 55, 151, 247, 343, 439, 87, 183, 279, 375, 471, +31, 127, 223, 319, 415, 63, 159, 255, 351, 447, 95, 191, 287, 383, 479, +}; +#endif + +#ifndef FFT_BITREV240 +#define FFT_BITREV240 +static const opus_int16 fft_bitrev240[240] = { +0, 48, 96, 144, 192, 16, 64, 112, 160, 208, 32, 80, 128, 176, 224, +4, 52, 100, 148, 196, 20, 68, 116, 164, 212, 36, 84, 132, 180, 228, +8, 56, 104, 152, 200, 24, 72, 120, 168, 216, 40, 88, 136, 184, 232, +12, 60, 108, 156, 204, 28, 76, 124, 172, 220, 44, 92, 140, 188, 236, +1, 49, 97, 145, 193, 17, 65, 113, 161, 209, 33, 81, 129, 177, 225, +5, 53, 101, 149, 197, 21, 69, 117, 165, 213, 37, 85, 133, 181, 229, +9, 57, 105, 153, 201, 25, 73, 121, 169, 217, 41, 89, 137, 185, 233, +13, 61, 109, 157, 205, 29, 77, 125, 173, 221, 45, 93, 141, 189, 237, +2, 50, 98, 146, 194, 18, 66, 114, 162, 210, 34, 82, 130, 178, 226, +6, 54, 102, 150, 198, 22, 70, 118, 166, 214, 38, 86, 134, 182, 230, +10, 58, 106, 154, 202, 26, 74, 122, 170, 218, 42, 90, 138, 186, 234, +14, 62, 110, 158, 206, 30, 78, 126, 174, 222, 46, 94, 142, 190, 238, +3, 51, 99, 147, 195, 19, 67, 115, 163, 211, 35, 83, 131, 179, 227, +7, 55, 103, 151, 199, 23, 71, 119, 167, 215, 39, 87, 135, 183, 231, +11, 59, 107, 155, 203, 27, 75, 123, 171, 219, 43, 91, 139, 187, 235, +15, 63, 111, 159, 207, 31, 79, 127, 175, 223, 47, 95, 143, 191, 239, +}; +#endif + +#ifndef FFT_BITREV120 +#define FFT_BITREV120 +static const opus_int16 fft_bitrev120[120] = { +0, 24, 48, 72, 96, 8, 32, 56, 80, 104, 16, 40, 64, 88, 112, +4, 28, 52, 76, 100, 12, 36, 60, 84, 108, 20, 44, 68, 92, 116, +1, 25, 49, 73, 97, 9, 33, 57, 81, 105, 17, 41, 65, 89, 113, +5, 29, 53, 77, 101, 13, 37, 61, 85, 109, 21, 45, 69, 93, 117, +2, 26, 50, 74, 98, 10, 34, 58, 82, 106, 18, 42, 66, 90, 114, +6, 30, 54, 78, 102, 14, 38, 62, 86, 110, 22, 46, 70, 94, 118, +3, 27, 51, 75, 99, 11, 35, 59, 83, 107, 19, 43, 67, 91, 115, +7, 31, 55, 79, 103, 15, 39, 63, 87, 111, 23, 47, 71, 95, 119, +}; +#endif + +#ifndef FFT_BITREV60 +#define FFT_BITREV60 +static const opus_int16 fft_bitrev60[60] = { +0, 12, 24, 36, 48, 4, 16, 28, 40, 52, 8, 20, 32, 44, 56, +1, 13, 25, 37, 49, 5, 17, 29, 41, 53, 9, 21, 33, 45, 57, +2, 14, 26, 38, 50, 6, 18, 30, 42, 54, 10, 22, 34, 46, 58, +3, 15, 27, 39, 51, 7, 19, 31, 43, 55, 11, 23, 35, 47, 59, +}; +#endif + +#ifndef FFT_STATE48000_960_0 +#define FFT_STATE48000_960_0 +static const kiss_fft_state fft_state48000_960_0 = { +480, /* nfft */ +0.002083333f, /* scale */ +-1, /* shift */ +{5, 96, 3, 32, 4, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev480, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_480, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_1 +#define FFT_STATE48000_960_1 +static const kiss_fft_state fft_state48000_960_1 = { +240, /* nfft */ +0.004166667f, /* scale */ +1, /* shift */ +{5, 48, 3, 16, 4, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev240, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_240, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_2 +#define FFT_STATE48000_960_2 +static const kiss_fft_state fft_state48000_960_2 = { +120, /* nfft */ +0.008333333f, /* scale */ +2, /* shift */ +{5, 24, 3, 8, 2, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev120, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_120, +#else +NULL, +#endif +}; +#endif + +#ifndef FFT_STATE48000_960_3 +#define FFT_STATE48000_960_3 +static const kiss_fft_state fft_state48000_960_3 = { +60, /* nfft */ +0.016666667f, /* scale */ +3, /* shift */ +{5, 12, 3, 4, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */ +fft_bitrev60, /* bitrev */ +fft_twiddles48000_960, /* bitrev */ +#ifdef OVERRIDE_FFT +(arch_fft_state *)&cfg_arch_60, +#else +NULL, +#endif +}; +#endif + +#endif + +#ifndef MDCT_TWIDDLES960 +#define MDCT_TWIDDLES960 +static const opus_val16 mdct_twiddles960[1800] = { +0.99999994f, 0.99999321f, 0.99997580f, 0.99994773f, 0.99990886f, +0.99985933f, 0.99979913f, 0.99972820f, 0.99964654f, 0.99955416f, +0.99945110f, 0.99933738f, 0.99921292f, 0.99907774f, 0.99893188f, +0.99877530f, 0.99860805f, 0.99843007f, 0.99824142f, 0.99804211f, +0.99783206f, 0.99761140f, 0.99737996f, 0.99713790f, 0.99688518f, +0.99662173f, 0.99634761f, 0.99606287f, 0.99576741f, 0.99546129f, +0.99514455f, 0.99481714f, 0.99447906f, 0.99413031f, 0.99377096f, +0.99340093f, 0.99302030f, 0.99262899f, 0.99222708f, 0.99181455f, +0.99139136f, 0.99095762f, 0.99051321f, 0.99005818f, 0.98959261f, +0.98911643f, 0.98862964f, 0.98813224f, 0.98762429f, 0.98710573f, +0.98657662f, 0.98603696f, 0.98548669f, 0.98492593f, 0.98435456f, +0.98377270f, 0.98318028f, 0.98257732f, 0.98196387f, 0.98133987f, +0.98070538f, 0.98006040f, 0.97940493f, 0.97873890f, 0.97806245f, +0.97737551f, 0.97667813f, 0.97597027f, 0.97525197f, 0.97452319f, +0.97378403f, 0.97303438f, 0.97227436f, 0.97150391f, 0.97072303f, +0.96993178f, 0.96913016f, 0.96831810f, 0.96749574f, 0.96666300f, +0.96581990f, 0.96496642f, 0.96410263f, 0.96322852f, 0.96234411f, +0.96144938f, 0.96054435f, 0.95962906f, 0.95870346f, 0.95776761f, +0.95682150f, 0.95586514f, 0.95489854f, 0.95392174f, 0.95293468f, +0.95193744f, 0.95093000f, 0.94991243f, 0.94888461f, 0.94784665f, +0.94679856f, 0.94574034f, 0.94467193f, 0.94359344f, 0.94250488f, +0.94140619f, 0.94029742f, 0.93917859f, 0.93804967f, 0.93691075f, +0.93576175f, 0.93460274f, 0.93343377f, 0.93225473f, 0.93106574f, +0.92986679f, 0.92865789f, 0.92743903f, 0.92621022f, 0.92497152f, +0.92372292f, 0.92246443f, 0.92119598f, 0.91991776f, 0.91862965f, +0.91733170f, 0.91602397f, 0.91470635f, 0.91337901f, 0.91204184f, +0.91069490f, 0.90933824f, 0.90797186f, 0.90659571f, 0.90520984f, +0.90381432f, 0.90240908f, 0.90099424f, 0.89956969f, 0.89813554f, +0.89669174f, 0.89523834f, 0.89377540f, 0.89230281f, 0.89082074f, +0.88932908f, 0.88782793f, 0.88631725f, 0.88479710f, 0.88326746f, +0.88172835f, 0.88017982f, 0.87862182f, 0.87705445f, 0.87547767f, +0.87389153f, 0.87229604f, 0.87069118f, 0.86907703f, 0.86745358f, +0.86582077f, 0.86417878f, 0.86252749f, 0.86086690f, 0.85919720f, +0.85751826f, 0.85583007f, 0.85413277f, 0.85242635f, 0.85071075f, +0.84898609f, 0.84725231f, 0.84550947f, 0.84375757f, 0.84199661f, +0.84022665f, 0.83844769f, 0.83665979f, 0.83486289f, 0.83305705f, +0.83124226f, 0.82941860f, 0.82758605f, 0.82574469f, 0.82389444f, +0.82203537f, 0.82016748f, 0.81829083f, 0.81640542f, 0.81451124f, +0.81260836f, 0.81069672f, 0.80877650f, 0.80684757f, 0.80490994f, +0.80296379f, 0.80100900f, 0.79904562f, 0.79707366f, 0.79509324f, +0.79310423f, 0.79110676f, 0.78910083f, 0.78708643f, 0.78506362f, +0.78303236f, 0.78099275f, 0.77894479f, 0.77688843f, 0.77482378f, +0.77275085f, 0.77066964f, 0.76858020f, 0.76648247f, 0.76437658f, +0.76226246f, 0.76014024f, 0.75800985f, 0.75587130f, 0.75372469f, +0.75157005f, 0.74940729f, 0.74723655f, 0.74505776f, 0.74287105f, +0.74067634f, 0.73847371f, 0.73626316f, 0.73404479f, 0.73181850f, +0.72958434f, 0.72734243f, 0.72509271f, 0.72283524f, 0.72057003f, +0.71829706f, 0.71601641f, 0.71372813f, 0.71143216f, 0.70912862f, +0.70681745f, 0.70449871f, 0.70217246f, 0.69983864f, 0.69749737f, +0.69514859f, 0.69279242f, 0.69042879f, 0.68805778f, 0.68567938f, +0.68329364f, 0.68090063f, 0.67850029f, 0.67609268f, 0.67367786f, +0.67125577f, 0.66882652f, 0.66639012f, 0.66394657f, 0.66149592f, +0.65903819f, 0.65657341f, 0.65410155f, 0.65162271f, 0.64913690f, +0.64664418f, 0.64414448f, 0.64163786f, 0.63912445f, 0.63660413f, +0.63407701f, 0.63154310f, 0.62900239f, 0.62645501f, 0.62390089f, +0.62134010f, 0.61877263f, 0.61619854f, 0.61361790f, 0.61103064f, +0.60843682f, 0.60583651f, 0.60322970f, 0.60061646f, 0.59799677f, +0.59537065f, 0.59273821f, 0.59009939f, 0.58745426f, 0.58480281f, +0.58214509f, 0.57948118f, 0.57681108f, 0.57413477f, 0.57145232f, +0.56876373f, 0.56606907f, 0.56336832f, 0.56066155f, 0.55794877f, +0.55523002f, 0.55250537f, 0.54977477f, 0.54703826f, 0.54429591f, +0.54154772f, 0.53879374f, 0.53603399f, 0.53326851f, 0.53049731f, +0.52772039f, 0.52493787f, 0.52214974f, 0.51935595f, 0.51655668f, +0.51375180f, 0.51094145f, 0.50812566f, 0.50530440f, 0.50247771f, +0.49964568f, 0.49680826f, 0.49396557f, 0.49111754f, 0.48826426f, +0.48540577f, 0.48254207f, 0.47967321f, 0.47679919f, 0.47392011f, +0.47103590f, 0.46814668f, 0.46525243f, 0.46235323f, 0.45944905f, +0.45653993f, 0.45362595f, 0.45070711f, 0.44778344f, 0.44485497f, +0.44192174f, 0.43898380f, 0.43604112f, 0.43309379f, 0.43014181f, +0.42718524f, 0.42422408f, 0.42125839f, 0.41828820f, 0.41531351f, +0.41233435f, 0.40935081f, 0.40636289f, 0.40337059f, 0.40037400f, +0.39737311f, 0.39436796f, 0.39135858f, 0.38834500f, 0.38532731f, +0.38230544f, 0.37927949f, 0.37624949f, 0.37321547f, 0.37017745f, +0.36713544f, 0.36408952f, 0.36103970f, 0.35798600f, 0.35492846f, +0.35186714f, 0.34880206f, 0.34573323f, 0.34266070f, 0.33958447f, +0.33650464f, 0.33342120f, 0.33033419f, 0.32724363f, 0.32414958f, +0.32105204f, 0.31795108f, 0.31484672f, 0.31173897f, 0.30862790f, +0.30551350f, 0.30239585f, 0.29927495f, 0.29615086f, 0.29302359f, +0.28989318f, 0.28675964f, 0.28362307f, 0.28048345f, 0.27734083f, +0.27419522f, 0.27104670f, 0.26789525f, 0.26474094f, 0.26158381f, +0.25842386f, 0.25526115f, 0.25209570f, 0.24892756f, 0.24575676f, +0.24258332f, 0.23940729f, 0.23622867f, 0.23304754f, 0.22986393f, +0.22667783f, 0.22348931f, 0.22029841f, 0.21710514f, 0.21390954f, +0.21071166f, 0.20751151f, 0.20430915f, 0.20110460f, 0.19789790f, +0.19468907f, 0.19147816f, 0.18826519f, 0.18505022f, 0.18183327f, +0.17861435f, 0.17539354f, 0.17217083f, 0.16894630f, 0.16571994f, +0.16249183f, 0.15926196f, 0.15603039f, 0.15279715f, 0.14956227f, +0.14632578f, 0.14308774f, 0.13984816f, 0.13660708f, 0.13336454f, +0.13012058f, 0.12687522f, 0.12362850f, 0.12038045f, 0.11713112f, +0.11388054f, 0.11062872f, 0.10737573f, 0.10412160f, 0.10086634f, +0.097609997f, 0.094352618f, 0.091094226f, 0.087834857f, 0.084574550f, +0.081313334f, 0.078051247f, 0.074788325f, 0.071524605f, 0.068260118f, +0.064994894f, 0.061728980f, 0.058462404f, 0.055195201f, 0.051927410f, +0.048659060f, 0.045390189f, 0.042120833f, 0.038851023f, 0.035580799f, +0.032310195f, 0.029039243f, 0.025767982f, 0.022496443f, 0.019224664f, +0.015952680f, 0.012680525f, 0.0094082337f, 0.0061358409f, 0.0028633832f, +-0.00040910527f, -0.0036815894f, -0.0069540343f, -0.010226404f, -0.013498665f, +-0.016770782f, -0.020042717f, -0.023314439f, -0.026585912f, -0.029857099f, +-0.033127967f, -0.036398482f, -0.039668605f, -0.042938303f, -0.046207540f, +-0.049476285f, -0.052744497f, -0.056012146f, -0.059279196f, -0.062545612f, +-0.065811358f, -0.069076397f, -0.072340697f, -0.075604223f, -0.078866936f, +-0.082128808f, -0.085389800f, -0.088649876f, -0.091909006f, -0.095167145f, +-0.098424271f, -0.10168034f, -0.10493532f, -0.10818918f, -0.11144188f, +-0.11469338f, -0.11794366f, -0.12119267f, -0.12444039f, -0.12768677f, +-0.13093179f, -0.13417540f, -0.13741758f, -0.14065829f, -0.14389749f, +-0.14713514f, -0.15037122f, -0.15360570f, -0.15683852f, -0.16006967f, +-0.16329910f, -0.16652679f, -0.16975269f, -0.17297678f, -0.17619900f, +-0.17941935f, -0.18263777f, -0.18585424f, -0.18906870f, -0.19228116f, +-0.19549155f, -0.19869985f, -0.20190603f, -0.20511003f, -0.20831184f, +-0.21151142f, -0.21470875f, -0.21790376f, -0.22109644f, -0.22428675f, +-0.22747467f, -0.23066014f, -0.23384315f, -0.23702365f, -0.24020162f, +-0.24337701f, -0.24654980f, -0.24971995f, -0.25288740f, -0.25605217f, +-0.25921419f, -0.26237345f, -0.26552987f, -0.26868346f, -0.27183419f, +-0.27498198f, -0.27812684f, -0.28126872f, -0.28440759f, -0.28754342f, +-0.29067615f, -0.29380578f, -0.29693225f, -0.30005556f, -0.30317566f, +-0.30629250f, -0.30940607f, -0.31251630f, -0.31562322f, -0.31872672f, +-0.32182685f, -0.32492352f, -0.32801670f, -0.33110636f, -0.33419248f, +-0.33727503f, -0.34035397f, -0.34342924f, -0.34650084f, -0.34956875f, +-0.35263291f, -0.35569328f, -0.35874987f, -0.36180258f, -0.36485144f, +-0.36789638f, -0.37093741f, -0.37397444f, -0.37700745f, -0.38003644f, +-0.38306138f, -0.38608220f, -0.38909888f, -0.39211139f, -0.39511973f, +-0.39812380f, -0.40112361f, -0.40411916f, -0.40711036f, -0.41009718f, +-0.41307965f, -0.41605768f, -0.41903123f, -0.42200032f, -0.42496487f, +-0.42792490f, -0.43088034f, -0.43383113f, -0.43677729f, -0.43971881f, +-0.44265559f, -0.44558764f, -0.44851488f, -0.45143735f, -0.45435500f, +-0.45726776f, -0.46017563f, -0.46307856f, -0.46597654f, -0.46886954f, +-0.47175750f, -0.47464043f, -0.47751826f, -0.48039100f, -0.48325855f, +-0.48612097f, -0.48897815f, -0.49183011f, -0.49467680f, -0.49751821f, +-0.50035429f, -0.50318497f, -0.50601029f, -0.50883019f, -0.51164466f, +-0.51445359f, -0.51725709f, -0.52005500f, -0.52284735f, -0.52563411f, +-0.52841520f, -0.53119069f, -0.53396046f, -0.53672451f, -0.53948283f, +-0.54223537f, -0.54498214f, -0.54772300f, -0.55045801f, -0.55318713f, +-0.55591035f, -0.55862761f, -0.56133890f, -0.56404412f, -0.56674337f, +-0.56943649f, -0.57212353f, -0.57480448f, -0.57747924f, -0.58014780f, +-0.58281022f, -0.58546633f, -0.58811617f, -0.59075975f, -0.59339696f, +-0.59602785f, -0.59865236f, -0.60127044f, -0.60388207f, -0.60648727f, +-0.60908598f, -0.61167812f, -0.61426371f, -0.61684275f, -0.61941516f, +-0.62198097f, -0.62454009f, -0.62709254f, -0.62963831f, -0.63217729f, +-0.63470948f, -0.63723493f, -0.63975352f, -0.64226526f, -0.64477009f, +-0.64726806f, -0.64975911f, -0.65224314f, -0.65472025f, -0.65719032f, +-0.65965337f, -0.66210932f, -0.66455823f, -0.66700000f, -0.66943461f, +-0.67186207f, -0.67428231f, -0.67669535f, -0.67910111f, -0.68149966f, +-0.68389088f, -0.68627477f, -0.68865126f, -0.69102043f, -0.69338220f, +-0.69573659f, -0.69808346f, -0.70042288f, -0.70275480f, -0.70507920f, +-0.70739603f, -0.70970529f, -0.71200693f, -0.71430099f, -0.71658736f, +-0.71886611f, -0.72113711f, -0.72340041f, -0.72565591f, -0.72790372f, +-0.73014367f, -0.73237586f, -0.73460019f, -0.73681659f, -0.73902518f, +-0.74122584f, -0.74341851f, -0.74560326f, -0.74778003f, -0.74994880f, +-0.75210953f, -0.75426215f, -0.75640678f, -0.75854325f, -0.76067162f, +-0.76279181f, -0.76490390f, -0.76700771f, -0.76910341f, -0.77119076f, +-0.77326995f, -0.77534080f, -0.77740335f, -0.77945763f, -0.78150350f, +-0.78354102f, -0.78557014f, -0.78759086f, -0.78960317f, -0.79160696f, +-0.79360235f, -0.79558921f, -0.79756755f, -0.79953730f, -0.80149853f, +-0.80345118f, -0.80539525f, -0.80733067f, -0.80925739f, -0.81117553f, +-0.81308490f, -0.81498563f, -0.81687760f, -0.81876087f, -0.82063532f, +-0.82250100f, -0.82435787f, -0.82620591f, -0.82804507f, -0.82987541f, +-0.83169687f, -0.83350939f, -0.83531296f, -0.83710766f, -0.83889335f, +-0.84067005f, -0.84243774f, -0.84419644f, -0.84594607f, -0.84768665f, +-0.84941816f, -0.85114056f, -0.85285389f, -0.85455805f, -0.85625303f, +-0.85793889f, -0.85961550f, -0.86128294f, -0.86294121f, -0.86459017f, +-0.86622989f, -0.86786032f, -0.86948150f, -0.87109333f, -0.87269586f, +-0.87428904f, -0.87587279f, -0.87744725f, -0.87901229f, -0.88056785f, +-0.88211405f, -0.88365078f, -0.88517809f, -0.88669586f, -0.88820416f, +-0.88970292f, -0.89119220f, -0.89267188f, -0.89414203f, -0.89560264f, +-0.89705360f, -0.89849502f, -0.89992678f, -0.90134889f, -0.90276134f, +-0.90416414f, -0.90555727f, -0.90694070f, -0.90831441f, -0.90967834f, +-0.91103262f, -0.91237706f, -0.91371179f, -0.91503674f, -0.91635185f, +-0.91765714f, -0.91895264f, -0.92023826f, -0.92151409f, -0.92277998f, +-0.92403603f, -0.92528218f, -0.92651838f, -0.92774469f, -0.92896110f, +-0.93016750f, -0.93136400f, -0.93255049f, -0.93372697f, -0.93489349f, +-0.93604994f, -0.93719643f, -0.93833286f, -0.93945926f, -0.94057560f, +-0.94168180f, -0.94277799f, -0.94386405f, -0.94494003f, -0.94600588f, +-0.94706154f, -0.94810712f, -0.94914252f, -0.95016778f, -0.95118284f, +-0.95218778f, -0.95318246f, -0.95416695f, -0.95514119f, -0.95610523f, +-0.95705903f, -0.95800257f, -0.95893586f, -0.95985889f, -0.96077162f, +-0.96167403f, -0.96256620f, -0.96344805f, -0.96431959f, -0.96518075f, +-0.96603161f, -0.96687216f, -0.96770233f, -0.96852213f, -0.96933156f, +-0.97013056f, -0.97091925f, -0.97169751f, -0.97246534f, -0.97322279f, +-0.97396982f, -0.97470641f, -0.97543252f, -0.97614825f, -0.97685349f, +-0.97754824f, -0.97823256f, -0.97890645f, -0.97956979f, -0.98022264f, +-0.98086500f, -0.98149687f, -0.98211825f, -0.98272908f, -0.98332942f, +-0.98391914f, -0.98449844f, -0.98506713f, -0.98562527f, -0.98617285f, +-0.98670989f, -0.98723638f, -0.98775226f, -0.98825759f, -0.98875231f, +-0.98923647f, -0.98971003f, -0.99017298f, -0.99062532f, -0.99106705f, +-0.99149817f, -0.99191868f, -0.99232858f, -0.99272782f, -0.99311644f, +-0.99349445f, -0.99386179f, -0.99421853f, -0.99456459f, -0.99489999f, +-0.99522477f, -0.99553883f, -0.99584228f, -0.99613506f, -0.99641716f, +-0.99668860f, -0.99694937f, -0.99719942f, -0.99743885f, -0.99766755f, +-0.99788558f, -0.99809295f, -0.99828959f, -0.99847561f, -0.99865085f, +-0.99881548f, -0.99896932f, -0.99911255f, -0.99924499f, -0.99936682f, +-0.99947786f, -0.99957830f, -0.99966794f, -0.99974692f, -0.99981517f, +-0.99987274f, -0.99991959f, -0.99995571f, -0.99998116f, -0.99999589f, +0.99999964f, 0.99997288f, 0.99990326f, 0.99979085f, 0.99963558f, +0.99943751f, 0.99919659f, 0.99891287f, 0.99858636f, 0.99821711f, +0.99780506f, 0.99735034f, 0.99685282f, 0.99631262f, 0.99572974f, +0.99510419f, 0.99443603f, 0.99372530f, 0.99297196f, 0.99217612f, +0.99133772f, 0.99045694f, 0.98953366f, 0.98856801f, 0.98756003f, +0.98650974f, 0.98541719f, 0.98428243f, 0.98310548f, 0.98188645f, +0.98062533f, 0.97932225f, 0.97797716f, 0.97659022f, 0.97516143f, +0.97369087f, 0.97217858f, 0.97062469f, 0.96902919f, 0.96739221f, +0.96571374f, 0.96399397f, 0.96223283f, 0.96043050f, 0.95858705f, +0.95670253f, 0.95477700f, 0.95281059f, 0.95080340f, 0.94875544f, +0.94666684f, 0.94453770f, 0.94236809f, 0.94015813f, 0.93790787f, +0.93561745f, 0.93328691f, 0.93091643f, 0.92850608f, 0.92605597f, +0.92356616f, 0.92103678f, 0.91846794f, 0.91585976f, 0.91321236f, +0.91052586f, 0.90780038f, 0.90503591f, 0.90223277f, 0.89939094f, +0.89651060f, 0.89359182f, 0.89063478f, 0.88763964f, 0.88460642f, +0.88153529f, 0.87842643f, 0.87527996f, 0.87209594f, 0.86887461f, +0.86561602f, 0.86232042f, 0.85898781f, 0.85561842f, 0.85221243f, +0.84876984f, 0.84529096f, 0.84177583f, 0.83822471f, 0.83463764f, +0.83101481f, 0.82735640f, 0.82366252f, 0.81993335f, 0.81616908f, +0.81236988f, 0.80853581f, 0.80466717f, 0.80076402f, 0.79682660f, +0.79285502f, 0.78884947f, 0.78481019f, 0.78073722f, 0.77663082f, +0.77249116f, 0.76831841f, 0.76411277f, 0.75987434f, 0.75560343f, +0.75130010f, 0.74696463f, 0.74259710f, 0.73819780f, 0.73376691f, +0.72930455f, 0.72481096f, 0.72028631f, 0.71573079f, 0.71114463f, +0.70652801f, 0.70188117f, 0.69720417f, 0.69249737f, 0.68776089f, +0.68299496f, 0.67819971f, 0.67337549f, 0.66852236f, 0.66364062f, +0.65873051f, 0.65379208f, 0.64882571f, 0.64383155f, 0.63880974f, +0.63376063f, 0.62868434f, 0.62358117f, 0.61845124f, 0.61329484f, +0.60811216f, 0.60290343f, 0.59766883f, 0.59240872f, 0.58712316f, +0.58181250f, 0.57647687f, 0.57111657f, 0.56573176f, 0.56032276f, +0.55488980f, 0.54943299f, 0.54395270f, 0.53844911f, 0.53292239f, +0.52737290f, 0.52180082f, 0.51620632f, 0.51058978f, 0.50495136f, +0.49929130f, 0.49360985f, 0.48790723f, 0.48218375f, 0.47643960f, +0.47067502f, 0.46489030f, 0.45908567f, 0.45326138f, 0.44741765f, +0.44155475f, 0.43567297f, 0.42977250f, 0.42385364f, 0.41791660f, +0.41196167f, 0.40598908f, 0.39999911f, 0.39399201f, 0.38796803f, +0.38192743f, 0.37587047f, 0.36979741f, 0.36370850f, 0.35760403f, +0.35148421f, 0.34534934f, 0.33919969f, 0.33303553f, 0.32685706f, +0.32066461f, 0.31445843f, 0.30823877f, 0.30200592f, 0.29576012f, +0.28950164f, 0.28323078f, 0.27694780f, 0.27065292f, 0.26434645f, +0.25802869f, 0.25169984f, 0.24536023f, 0.23901010f, 0.23264973f, +0.22627939f, 0.21989937f, 0.21350993f, 0.20711134f, 0.20070387f, +0.19428782f, 0.18786344f, 0.18143101f, 0.17499080f, 0.16854310f, +0.16208819f, 0.15562633f, 0.14915779f, 0.14268288f, 0.13620184f, +0.12971498f, 0.12322257f, 0.11672486f, 0.11022217f, 0.10371475f, +0.097202882f, 0.090686858f, 0.084166944f, 0.077643424f, 0.071116582f, +0.064586692f, 0.058054037f, 0.051518895f, 0.044981543f, 0.038442269f, +0.031901345f, 0.025359053f, 0.018815678f, 0.012271495f, 0.0057267868f, +-0.00081816671f, -0.0073630852f, -0.013907688f, -0.020451695f, -0.026994826f, +-0.033536803f, -0.040077340f, -0.046616159f, -0.053152986f, -0.059687532f, +-0.066219524f, -0.072748676f, -0.079274714f, -0.085797355f, -0.092316322f, +-0.098831341f, -0.10534211f, -0.11184838f, -0.11834986f, -0.12484626f, +-0.13133731f, -0.13782275f, -0.14430228f, -0.15077563f, -0.15724251f, +-0.16370267f, -0.17015581f, -0.17660165f, -0.18303993f, -0.18947038f, +-0.19589271f, -0.20230664f, -0.20871192f, -0.21510825f, -0.22149536f, +-0.22787298f, -0.23424086f, -0.24059868f, -0.24694622f, -0.25328314f, +-0.25960925f, -0.26592422f, -0.27222782f, -0.27851975f, -0.28479972f, +-0.29106751f, -0.29732284f, -0.30356544f, -0.30979502f, -0.31601134f, +-0.32221413f, -0.32840309f, -0.33457801f, -0.34073856f, -0.34688455f, +-0.35301566f, -0.35913166f, -0.36523229f, -0.37131724f, -0.37738630f, +-0.38343921f, -0.38947567f, -0.39549544f, -0.40149832f, -0.40748394f, +-0.41345215f, -0.41940263f, -0.42533514f, -0.43124944f, -0.43714526f, +-0.44302234f, -0.44888046f, -0.45471936f, -0.46053877f, -0.46633846f, +-0.47211814f, -0.47787762f, -0.48361665f, -0.48933494f, -0.49503228f, +-0.50070840f, -0.50636309f, -0.51199609f, -0.51760709f, -0.52319598f, +-0.52876246f, -0.53430629f, -0.53982723f, -0.54532504f, -0.55079949f, +-0.55625033f, -0.56167740f, -0.56708032f, -0.57245898f, -0.57781315f, +-0.58314258f, -0.58844697f, -0.59372622f, -0.59897995f, -0.60420811f, +-0.60941035f, -0.61458647f, -0.61973625f, -0.62485951f, -0.62995601f, +-0.63502556f, -0.64006782f, -0.64508271f, -0.65007001f, -0.65502942f, +-0.65996075f, -0.66486382f, -0.66973841f, -0.67458433f, -0.67940134f, +-0.68418926f, -0.68894786f, -0.69367695f, -0.69837630f, -0.70304573f, +-0.70768511f, -0.71229410f, -0.71687263f, -0.72142041f, -0.72593731f, +-0.73042315f, -0.73487765f, -0.73930067f, -0.74369204f, -0.74805158f, +-0.75237900f, -0.75667429f, -0.76093709f, -0.76516730f, -0.76936477f, +-0.77352923f, -0.77766061f, -0.78175867f, -0.78582323f, -0.78985411f, +-0.79385114f, -0.79781419f, -0.80174309f, -0.80563760f, -0.80949765f, +-0.81332302f, -0.81711352f, -0.82086903f, -0.82458937f, -0.82827437f, +-0.83192390f, -0.83553779f, -0.83911592f, -0.84265804f, -0.84616417f, +-0.84963393f, -0.85306740f, -0.85646427f, -0.85982448f, -0.86314780f, +-0.86643422f, -0.86968350f, -0.87289548f, -0.87607014f, -0.87920725f, +-0.88230664f, -0.88536829f, -0.88839203f, -0.89137769f, -0.89432514f, +-0.89723432f, -0.90010506f, -0.90293723f, -0.90573072f, -0.90848541f, +-0.91120118f, -0.91387796f, -0.91651553f, -0.91911387f, -0.92167282f, +-0.92419231f, -0.92667222f, -0.92911243f, -0.93151283f, -0.93387336f, +-0.93619382f, -0.93847424f, -0.94071442f, -0.94291431f, -0.94507378f, +-0.94719279f, -0.94927126f, -0.95130903f, -0.95330608f, -0.95526224f, +-0.95717752f, -0.95905179f, -0.96088499f, -0.96267700f, -0.96442777f, +-0.96613729f, -0.96780539f, -0.96943200f, -0.97101706f, -0.97256058f, +-0.97406244f, -0.97552258f, -0.97694093f, -0.97831738f, -0.97965199f, +-0.98094457f, -0.98219514f, -0.98340368f, -0.98457009f, -0.98569429f, +-0.98677629f, -0.98781598f, -0.98881340f, -0.98976845f, -0.99068111f, +-0.99155134f, -0.99237907f, -0.99316430f, -0.99390697f, -0.99460709f, +-0.99526459f, -0.99587947f, -0.99645168f, -0.99698120f, -0.99746799f, +-0.99791211f, -0.99831343f, -0.99867201f, -0.99898779f, -0.99926084f, +-0.99949104f, -0.99967843f, -0.99982297f, -0.99992472f, -0.99998361f, +0.99999869f, 0.99989158f, 0.99961317f, 0.99916345f, 0.99854255f, +0.99775058f, 0.99678761f, 0.99565387f, 0.99434954f, 0.99287480f, +0.99122995f, 0.98941529f, 0.98743105f, 0.98527765f, 0.98295540f, +0.98046476f, 0.97780609f, 0.97497988f, 0.97198665f, 0.96882683f, +0.96550101f, 0.96200979f, 0.95835376f, 0.95453346f, 0.95054960f, +0.94640291f, 0.94209403f, 0.93762374f, 0.93299282f, 0.92820197f, +0.92325211f, 0.91814411f, 0.91287869f, 0.90745693f, 0.90187967f, +0.89614785f, 0.89026248f, 0.88422459f, 0.87803519f, 0.87169534f, +0.86520612f, 0.85856867f, 0.85178405f, 0.84485358f, 0.83777827f, +0.83055943f, 0.82319832f, 0.81569612f, 0.80805415f, 0.80027372f, +0.79235619f, 0.78430289f, 0.77611518f, 0.76779449f, 0.75934225f, +0.75075996f, 0.74204898f, 0.73321080f, 0.72424710f, 0.71515924f, +0.70594883f, 0.69661748f, 0.68716675f, 0.67759830f, 0.66791373f, +0.65811473f, 0.64820296f, 0.63818014f, 0.62804794f, 0.61780810f, +0.60746247f, 0.59701276f, 0.58646071f, 0.57580817f, 0.56505698f, +0.55420899f, 0.54326600f, 0.53222996f, 0.52110273f, 0.50988621f, +0.49858227f, 0.48719296f, 0.47572014f, 0.46416581f, 0.45253196f, +0.44082057f, 0.42903364f, 0.41717321f, 0.40524128f, 0.39323992f, +0.38117120f, 0.36903715f, 0.35683987f, 0.34458145f, 0.33226398f, +0.31988961f, 0.30746040f, 0.29497850f, 0.28244606f, 0.26986524f, +0.25723818f, 0.24456702f, 0.23185398f, 0.21910121f, 0.20631088f, +0.19348522f, 0.18062639f, 0.16773662f, 0.15481812f, 0.14187308f, +0.12890373f, 0.11591230f, 0.10290100f, 0.089872077f, 0.076827750f, +0.063770257f, 0.050701842f, 0.037624735f, 0.024541186f, 0.011453429f, +-0.0016362892f, -0.014725727f, -0.027812643f, -0.040894791f, -0.053969935f, +-0.067035832f, -0.080090240f, -0.093130924f, -0.10615565f, -0.11916219f, +-0.13214831f, -0.14511178f, -0.15805040f, -0.17096193f, -0.18384418f, +-0.19669491f, -0.20951195f, -0.22229309f, -0.23503613f, -0.24773891f, +-0.26039925f, -0.27301496f, -0.28558388f, -0.29810387f, -0.31057280f, +-0.32298848f, -0.33534884f, -0.34765175f, -0.35989508f, -0.37207675f, +-0.38419467f, -0.39624676f, -0.40823093f, -0.42014518f, -0.43198743f, +-0.44375566f, -0.45544785f, -0.46706200f, -0.47859612f, -0.49004826f, +-0.50141639f, -0.51269865f, -0.52389306f, -0.53499764f, -0.54601061f, +-0.55693001f, -0.56775403f, -0.57848072f, -0.58910829f, -0.59963489f, +-0.61005878f, -0.62037814f, -0.63059121f, -0.64069623f, -0.65069145f, +-0.66057515f, -0.67034572f, -0.68000144f, -0.68954057f, -0.69896162f, +-0.70826286f, -0.71744281f, -0.72649974f, -0.73543227f, -0.74423873f, +-0.75291771f, -0.76146764f, -0.76988715f, -0.77817470f, -0.78632891f, +-0.79434842f, -0.80223179f, -0.80997771f, -0.81758487f, -0.82505190f, +-0.83237761f, -0.83956063f, -0.84659988f, -0.85349399f, -0.86024189f, +-0.86684239f, -0.87329435f, -0.87959671f, -0.88574833f, -0.89174819f, +-0.89759529f, -0.90328854f, -0.90882701f, -0.91420978f, -0.91943592f, +-0.92450452f, -0.92941469f, -0.93416560f, -0.93875647f, -0.94318646f, +-0.94745487f, -0.95156091f, -0.95550388f, -0.95928317f, -0.96289814f, +-0.96634805f, -0.96963239f, -0.97275060f, -0.97570217f, -0.97848648f, +-0.98110318f, -0.98355180f, -0.98583186f, -0.98794299f, -0.98988485f, +-0.99165714f, -0.99325943f, -0.99469161f, -0.99595332f, -0.99704438f, +-0.99796462f, -0.99871385f, -0.99929196f, -0.99969882f, -0.99993443f, +0.99999464f, 0.99956632f, 0.99845290f, 0.99665523f, 0.99417448f, +0.99101239f, 0.98717111f, 0.98265326f, 0.97746199f, 0.97160077f, +0.96507365f, 0.95788515f, 0.95004016f, 0.94154406f, 0.93240267f, +0.92262226f, 0.91220951f, 0.90117162f, 0.88951606f, 0.87725091f, +0.86438453f, 0.85092574f, 0.83688372f, 0.82226819f, 0.80708915f, +0.79135692f, 0.77508235f, 0.75827658f, 0.74095112f, 0.72311783f, +0.70478898f, 0.68597710f, 0.66669506f, 0.64695615f, 0.62677377f, +0.60616189f, 0.58513457f, 0.56370622f, 0.54189157f, 0.51970547f, +0.49716324f, 0.47428027f, 0.45107225f, 0.42755505f, 0.40374488f, +0.37965798f, 0.35531086f, 0.33072025f, 0.30590299f, 0.28087607f, +0.25565663f, 0.23026201f, 0.20470956f, 0.17901683f, 0.15320139f, +0.12728097f, 0.10127331f, 0.075196236f, 0.049067631f, 0.022905400f, +-0.0032725304f, -0.029448219f, -0.055603724f, -0.081721120f, -0.10778251f, +-0.13377003f, -0.15966587f, -0.18545228f, -0.21111161f, -0.23662624f, +-0.26197869f, -0.28715160f, -0.31212771f, -0.33688989f, -0.36142120f, +-0.38570482f, -0.40972409f, -0.43346253f, -0.45690393f, -0.48003218f, +-0.50283146f, -0.52528608f, -0.54738069f, -0.56910020f, -0.59042966f, +-0.61135447f, -0.63186026f, -0.65193301f, -0.67155898f, -0.69072473f, +-0.70941705f, -0.72762316f, -0.74533063f, -0.76252723f, -0.77920127f, +-0.79534131f, -0.81093621f, -0.82597536f, -0.84044844f, -0.85434550f, +-0.86765707f, -0.88037395f, -0.89248747f, -0.90398932f, -0.91487163f, +-0.92512697f, -0.93474823f, -0.94372886f, -0.95206273f, -0.95974404f, +-0.96676767f, -0.97312868f, -0.97882277f, -0.98384601f, -0.98819500f, +-0.99186671f, -0.99485862f, -0.99716878f, -0.99879545f, -0.99973762f, +}; +#endif + +static const CELTMode mode48000_960_120 = { +48000, /* Fs */ +120, /* overlap */ +21, /* nbEBands */ +21, /* effEBands */ +{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */ +eband5ms, /* eBands */ +3, /* maxLM */ +8, /* nbShortMdcts */ +120, /* shortMdctSize */ +11, /* nbAllocVectors */ +band_allocation, /* allocVectors */ +logN400, /* logN */ +window120, /* window */ +{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */ +{392, cache_index50, cache_bits50, cache_caps50}, /* cache */ +}; + +/* List of all the available modes */ +#define TOTAL_MODES 1 +static const CELTMode * const static_mode_list[TOTAL_MODES] = { +&mode48000_960_120, +}; diff --git a/src/libopus/celt/vq.c b/src/libopus/celt/vq.c new file mode 100644 index 00000000..bc0493f0 --- /dev/null +++ b/src/libopus/celt/vq.c @@ -0,0 +1,442 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "mathops.h" +#include "cwrs.h" +#include "vq.h" +#include "arch.h" +#include "os_support.h" +#include "bands.h" +#include "rate.h" +#include "pitch.h" + +#if defined(MIPSr1_ASM) +#include "mips/vq_mipsr1.h" +#endif + +#ifndef OVERRIDE_vq_exp_rotation1 +static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s) +{ + int i; + opus_val16 ms; + celt_norm *Xptr; + Xptr = X; + ms = NEG16(s); + for (i=0;i=0;i--) + { + celt_norm x1, x2; + x1 = Xptr[0]; + x2 = Xptr[stride]; + Xptr[stride] = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x2), s, x1), 15)); + *Xptr-- = EXTRACT16(PSHR32(MAC16_16(MULT16_16(c, x1), ms, x2), 15)); + } +} +#endif /* OVERRIDE_vq_exp_rotation1 */ + +void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread) +{ + static const int SPREAD_FACTOR[3]={15,10,5}; + int i; + opus_val16 c, s; + opus_val16 gain, theta; + int stride2=0; + int factor; + + if (2*K>=len || spread==SPREAD_NONE) + return; + factor = SPREAD_FACTOR[spread-1]; + + gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K)); + theta = HALF16(MULT16_16_Q15(gain,gain)); + + c = celt_cos_norm(EXTEND32(theta)); + s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */ + + if (len>=8*stride) + { + stride2 = 1; + /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding. + It's basically incrementing long as (stride2+0.5)^2 < len/stride. */ + while ((stride2*stride2+stride2)*stride + (stride>>2) < len) + stride2++; + } + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + extract_collapse_mask().*/ + len = celt_udiv(len, stride); + for (i=0;i>1; +#endif + t = VSHR32(Ryy, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + i=0; + do + X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1)); + while (++i < N); +} + +static unsigned extract_collapse_mask(int *iy, int N, int B) +{ + unsigned collapse_mask; + int N0; + int i; + if (B<=1) + return 1; + /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for + exp_rotation().*/ + N0 = celt_udiv(N, B); + collapse_mask = 0; + i=0; do { + int j; + unsigned tmp=0; + j=0; do { + tmp |= iy[i*N0+j]; + } while (++j (N>>1)) + { + opus_val16 rcp; + j=0; do { + sum += X[j]; + } while (++j EPSILON && sum < 64)) +#endif + { + X[0] = QCONST16(1.f,14); + j=1; do + X[j]=0; + while (++j=0); + + /* This should never happen, but just in case it does (e.g. on silence) + we fill the first bin with pulses. */ +#ifdef FIXED_POINT_DEBUG + celt_sig_assert(pulsesLeft<=N+3); +#endif + if (pulsesLeft > N+3) + { + opus_val16 tmp = (opus_val16)pulsesLeft; + yy = MAC16_16(yy, tmp, tmp); + yy = MAC16_16(yy, tmp, y[0]); + iy[0] += pulsesLeft; + pulsesLeft=0; + } + + for (i=0;i= best_num/best_den, but that way + we can do it without any division */ + /* OPT: It's not clear whether a cmov is faster than a branch here + since the condition is more often false than true and using + a cmov introduces data dependencies across iterations. The optimal + choice may be architecture-dependent. */ + if (opus_unlikely(MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))) + { + best_den = Ryy; + best_num = Rxy; + best_id = j; + } + } while (++j0, "alg_quant() needs at least one pulse"); + celt_assert2(N>1, "alg_quant() needs at least two dimensions"); + + /* Covers vectorization by up to 4. */ + ALLOC(iy, N+3, int); + + exp_rotation(X, N, 1, B, K, spread); + + yy = op_pvq_search(X, iy, K, N, arch); + + encode_pulses(iy, N, K, enc); + + if (resynth) + { + normalise_residual(iy, X, N, yy, gain); + exp_rotation(X, N, -1, B, K, spread); + } + + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +/** Decode pulse vector and combine the result with the pitch vector to produce + the final normalised signal in the current band. */ +unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B, + ec_dec *dec, opus_val16 gain) +{ + opus_val32 Ryy; + unsigned collapse_mask; + VARDECL(int, iy); + SAVE_STACK; + + celt_assert2(K>0, "alg_unquant() needs at least one pulse"); + celt_assert2(N>1, "alg_unquant() needs at least two dimensions"); + ALLOC(iy, N, int); + Ryy = decode_pulses(iy, N, K, dec); + normalise_residual(iy, X, N, Ryy, gain); + exp_rotation(X, N, -1, B, K, spread); + collapse_mask = extract_collapse_mask(iy, N, B); + RESTORE_STACK; + return collapse_mask; +} + +#ifndef OVERRIDE_renormalise_vector +void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch) +{ + int i; +#ifdef FIXED_POINT + int k; +#endif + opus_val32 E; + opus_val16 g; + opus_val32 t; + celt_norm *xptr; + E = EPSILON + celt_inner_prod(X, X, N, arch); +#ifdef FIXED_POINT + k = celt_ilog2(E)>>1; +#endif + t = VSHR32(E, 2*(k-7)); + g = MULT16_16_P15(celt_rsqrt_norm(t),gain); + + xptr = X; + for (i=0;i header file. */ +/* #undef HAVE_ALLOCA_H */ + +/* NE10 library is installed on host. Make sure it is on target! */ +/* #undef HAVE_ARM_NE10 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `lrint' function. */ +#define HAVE_LRINT 0 + +/* Define to 1 if you have the `lrintf' function. */ +#define HAVE_LRINTF 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 0 + +/* Define to 1 if you have the `__malloc_hook' function. */ +#define HAVE___MALLOC_HOOK 1 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Make use of ARM asm optimization */ +/* #undef OPUS_ARM_ASM */ + +/* Use generic ARMv4 inline asm optimizations */ +/* #undef OPUS_ARM_INLINE_ASM */ + +/* Use ARMv5E inline asm optimizations */ +/* #undef OPUS_ARM_INLINE_EDSP */ + +/* Use ARMv6 inline asm optimizations */ +/* #undef OPUS_ARM_INLINE_MEDIA */ + +/* Use ARM NEON inline asm optimizations */ +/* #undef OPUS_ARM_INLINE_NEON */ + +/* Define if assembler supports EDSP instructions */ +/* #undef OPUS_ARM_MAY_HAVE_EDSP */ + +/* Define if assembler supports ARMv6 media instructions */ +/* #undef OPUS_ARM_MAY_HAVE_MEDIA */ + +/* Define if compiler supports NEON instructions */ +/* #undef OPUS_ARM_MAY_HAVE_NEON */ + +/* Compiler supports ARMv7/Aarch64 Neon Intrinsics */ +/* #undef OPUS_ARM_MAY_HAVE_NEON_INTR */ + +/* Define if binary requires Aarch64 Neon Intrinsics */ +/* #undef OPUS_ARM_PRESUME_AARCH64_NEON_INTR */ + +/* Define if binary requires EDSP instruction support */ +/* #undef OPUS_ARM_PRESUME_EDSP */ + +/* Define if binary requires ARMv6 media instruction support */ +/* #undef OPUS_ARM_PRESUME_MEDIA */ + +/* Define if binary requires NEON instruction support */ +/* #undef OPUS_ARM_PRESUME_NEON */ + +/* Define if binary requires NEON intrinsics support */ +/* #undef OPUS_ARM_PRESUME_NEON_INTR */ + +/* This is a build of OPUS */ +#define OPUS_BUILD /**/ + +/* Run bit-exactness checks between optimized and c implementations */ +/* #undef OPUS_CHECK_ASM */ + +/* Use run-time CPU capabilities detection */ +/* #undef OPUS_HAVE_RTCD */ + +/* Compiler supports X86 AVX Intrinsics */ +/* #undef OPUS_X86_MAY_HAVE_AVX */ + +/* Compiler supports X86 SSE Intrinsics */ +/* #undef OPUS_X86_MAY_HAVE_SSE */ + +/* Compiler supports X86 SSE2 Intrinsics */ +/* #undef OPUS_X86_MAY_HAVE_SSE2 */ + +/* Compiler supports X86 SSE4.1 Intrinsics */ +/* #undef OPUS_X86_MAY_HAVE_SSE4_1 */ + +/* Define if binary requires AVX intrinsics support */ +/* #undef OPUS_X86_PRESUME_AVX */ + +/* Define if binary requires SSE intrinsics support */ +/* #undef OPUS_X86_PRESUME_SSE */ + +/* Define if binary requires SSE2 intrinsics support */ +/* #undef OPUS_X86_PRESUME_SSE2 */ + +/* Define if binary requires SSE4.1 intrinsics support */ +/* #undef OPUS_X86_PRESUME_SSE4_1 */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "opus@xiph.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "opus" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "opus 1.3.1" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "opus" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "1.3.1" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Make use of alloca */ +/* #undef USE_ALLOCA */ + +/* Use C99 variable-size arrays */ +#define VAR_ARRAYS 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +/* #undef inline */ +#endif + +/* Define to the equivalent of the C99 'restrict' keyword, or to + nothing if this is not supported. Do not define if restrict is + supported directly. */ +#define restrict __restrict +/* Work around a bug in Sun C++: it does not support _Restrict or + __restrict__, even though the corresponding Sun C compiler ends up with + "#define restrict _Restrict" or "#define restrict __restrict__" in the + previous line. Perhaps some future version of Sun C++ will work with + restrict; if so, hopefully it defines __RESTRICT like Sun C does. */ +#if defined __SUNPRO_CC && !defined __RESTRICT +# define _Restrict +# define __restrict__ +#endif diff --git a/src/libopus/mapping_matrix.c b/src/libopus/mapping_matrix.c new file mode 100644 index 00000000..eb5a68c4 --- /dev/null +++ b/src/libopus/mapping_matrix.c @@ -0,0 +1,378 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "celt/arch.h" +#include "celt/float_cast.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "mapping_matrix.h" + +#define MATRIX_INDEX(nb_rows, row, col) (nb_rows * col + row) + +opus_int32 mapping_matrix_get_size(int rows, int cols) +{ + opus_int32 size; + + /* Mapping Matrix must only support up to 255 channels in or out. + * Additionally, the total cell count must be <= 65004 octets in order + * for the matrix to be stored in an OGG header. + */ + if (rows > 255 || cols > 255) + return 0; + size = rows * (opus_int32)cols * sizeof(opus_int16); + if (size > 65004) + return 0; + + return align(sizeof(MappingMatrix)) + align(size); +} + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (opus_int16*)(void*)((char*)matrix + align(sizeof(MappingMatrix))); +} + +void mapping_matrix_init(MappingMatrix * const matrix, + int rows, int cols, int gain, const opus_int16 *data, opus_int32 data_size) +{ + int i; + opus_int16 *ptr; + +#if !defined(ENABLE_ASSERTIONS) + (void)data_size; +#endif + celt_assert(align(data_size) == align(rows * cols * sizeof(opus_int16))); + + matrix->rows = rows; + matrix->cols = cols; + matrix->gain = gain; + ptr = mapping_matrix_get_data(matrix); + for (i = 0; i < rows * cols; i++) + { + ptr[i] = data[i]; + } +} + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + float tmp = 0; + for (col = 0; col < input_rows; col++) + { + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; + } +#if defined(FIXED_POINT) + output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp); +#else + output[output_rows * i] = (1/32768.f)*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + float input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (1/32768.f)*input[input_rows * i]; +#else + input_sample = input[input_rows * i]; +#endif + for (row = 0; row < output_rows; row++) + { + float tmp = + (1/32768.f)*matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += tmp; + } + } +} +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, col; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { + opus_val32 tmp = 0; + for (col = 0; col < input_rows; col++) + { +#if defined(FIXED_POINT) + tmp += + ((opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + (opus_int32)input[MATRIX_INDEX(input_rows, col, i)]) >> 8; +#else + tmp += + matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] * + input[MATRIX_INDEX(input_rows, col, i)]; +#endif + } +#if defined(FIXED_POINT) + output[output_rows * i] = (opus_int16)((tmp + 64) >> 7); +#else + output[output_rows * i] = (1/(32768.f*32768.f))*tmp; +#endif + } +} + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size) +{ + /* Matrix data is ordered col-wise. */ + opus_int16* matrix_data; + int i, row; + opus_int32 input_sample; + + celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows); + + matrix_data = mapping_matrix_get_data(matrix); + + for (i = 0; i < frame_size; i++) + { +#if defined(FIXED_POINT) + input_sample = (opus_int32)input[input_rows * i]; +#else + input_sample = (opus_int32)FLOAT2INT16(input[input_rows * i]); +#endif + for (row = 0; row < output_rows; row++) + { + opus_int32 tmp = + (opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] * + input_sample; + output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15; + } + } +} + +const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_mixing_data[36] = { + 16384, 0, -16384, 23170, 0, 0, 16384, 23170, + 16384, 0, 0, 0, 16384, 0, -16384, -23170, + 0, 0, 16384, -23170, 16384, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_mixing = { 11, 11, 0 }; +const opus_int16 mapping_matrix_soa_mixing_data[121] = { + 10923, 7723, 13377, -13377, 11585, 9459, 7723, -16384, + -6689, 0, 0, 10923, 7723, 13377, 13377, -11585, + 9459, 7723, 16384, -6689, 0, 0, 10923, -15447, + 13377, 0, 0, -18919, 7723, 0, 13377, 0, + 0, 10923, 7723, -13377, -13377, 11585, -9459, 7723, + 16384, -6689, 0, 0, 10923, -7723, 0, 13377, + -16384, 0, -15447, 0, 9459, 0, 0, 10923, + -7723, 0, -13377, 16384, 0, -15447, 0, 9459, + 0, 0, 10923, 15447, 0, 0, 0, 0, + -15447, 0, -18919, 0, 0, 10923, 7723, -13377, + 13377, -11585, -9459, 7723, -16384, -6689, 0, 0, + 10923, -15447, -13377, 0, 0, 18919, 7723, 0, + 13377, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767 +}; + +const MappingMatrix mapping_matrix_toa_mixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_mixing_data[324] = { + 8208, 0, -881, 14369, 0, 0, -8192, -4163, + 13218, 0, 0, 0, 11095, -8836, -6218, 14833, + 0, 0, 8208, -10161, 881, 10161, -13218, -2944, + -8192, 2944, 0, -10488, -6218, 6248, -11095, -6248, + 0, -10488, 0, 0, 8208, 10161, 881, -10161, + -13218, 2944, -8192, -2944, 0, 10488, -6218, -6248, + -11095, 6248, 0, 10488, 0, 0, 8176, 5566, + -11552, 5566, 9681, -11205, 8192, -11205, 0, 4920, + -15158, 9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 7871, 11552, 0, 0, 15846, 8192, 0, + -9681, -6958, 0, 13797, 3334, 0, -15158, 0, + 0, 0, 8176, 0, 11552, 7871, 0, 0, + 8192, 15846, 9681, 0, 0, 0, 3334, 13797, + 15158, 6958, 0, 0, 8176, 5566, -11552, -5566, + -9681, -11205, 8192, 11205, 0, 4920, 15158, 9756, + -3334, -9756, 0, 4920, 0, 0, 8208, 14369, + -881, 0, 0, -4163, -8192, 0, -13218, -14833, + 0, -8836, 11095, 0, 6218, 0, 0, 0, + 8208, 10161, 881, 10161, 13218, 2944, -8192, 2944, + 0, 10488, 6218, -6248, -11095, -6248, 0, -10488, + 0, 0, 8208, -14369, -881, 0, 0, 4163, + -8192, 0, -13218, 14833, 0, 8836, 11095, 0, + 6218, 0, 0, 0, 8208, 0, -881, -14369, + 0, 0, -8192, 4163, 13218, 0, 0, 0, + 11095, 8836, -6218, -14833, 0, 0, 8176, -5566, + -11552, 5566, -9681, 11205, 8192, -11205, 0, -4920, + 15158, -9756, -3334, 9756, 0, -4920, 0, 0, + 8176, 0, 11552, -7871, 0, 0, 8192, -15846, + 9681, 0, 0, 0, 3334, -13797, 15158, -6958, + 0, 0, 8176, -7871, 11552, 0, 0, -15846, + 8192, 0, -9681, 6958, 0, -13797, 3334, 0, + -15158, 0, 0, 0, 8176, -5566, -11552, -5566, + 9681, 11205, 8192, 11205, 0, -4920, -15158, -9756, + -3334, -9756, 0, 4920, 0, 0, 8208, -10161, + 881, -10161, 13218, -2944, -8192, -2944, 0, -10488, + 6218, 6248, -11095, 6248, 0, 10488, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_foa_demixing = { 6, 6, 0 }; +const opus_int16 mapping_matrix_foa_demixing_data[36] = { + 16384, 16384, 16384, 16384, 0, 0, 0, 23170, + 0, -23170, 0, 0, -16384, 16384, -16384, 16384, + 0, 0, 23170, 0, -23170, 0, 0, 0, + 0, 0, 0, 0, 32767, 0, 0, 0, + 0, 0, 0, 32767 +}; + +const MappingMatrix mapping_matrix_soa_demixing = { 11, 11, 3050 }; +const opus_int16 mapping_matrix_soa_demixing_data[121] = { + 2771, 2771, 2771, 2771, 2771, 2771, 2771, 2771, + 2771, 0, 0, 10033, 10033, -20066, 10033, 14189, + 14189, -28378, 10033, -20066, 0, 0, 3393, 3393, + 3393, -3393, 0, 0, 0, -3393, -3393, 0, + 0, -17378, 17378, 0, -17378, -24576, 24576, 0, + 17378, 0, 0, 0, -14189, 14189, 0, -14189, + -28378, 28378, 0, 14189, 0, 0, 0, 2399, + 2399, -4799, -2399, 0, 0, 0, -2399, 4799, + 0, 0, 1959, 1959, 1959, 1959, -3918, -3918, + -3918, 1959, 1959, 0, 0, -4156, 4156, 0, + 4156, 0, 0, 0, -4156, 0, 0, 0, + 8192, 8192, -16384, 8192, 16384, 16384, -32768, 8192, + -16384, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8312, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8312 +}; + +const MappingMatrix mapping_matrix_toa_demixing = { 18, 18, 0 }; +const opus_int16 mapping_matrix_toa_demixing_data[324] = { + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, + 0, 0, 0, -9779, 9779, 6263, 8857, 0, + 6263, 13829, 9779, -13829, 0, -6263, 0, -8857, + -6263, -9779, 0, 0, -3413, 3413, 3413, -11359, + 11359, 11359, -11359, -3413, 3413, -3413, -3413, -11359, + 11359, 11359, -11359, 3413, 0, 0, 13829, 9779, + -9779, 6263, 0, 8857, -6263, 0, 9779, 0, + -13829, 6263, -8857, 0, -6263, -9779, 0, 0, + 0, -15617, -15617, 6406, 0, 0, -6406, 0, + 15617, 0, 0, -6406, 0, 0, 6406, 15617, + 0, 0, 0, -5003, 5003, -10664, 15081, 0, + -10664, -7075, 5003, 7075, 0, 10664, 0, -15081, + 10664, -5003, 0, 0, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, -8176, -8176, -8176, 8208, + 8208, 8208, 8208, -8176, 0, 0, -7075, 5003, + -5003, -10664, 0, 15081, 10664, 0, 5003, 0, + 7075, -10664, -15081, 0, 10664, -5003, 0, 0, + 15617, 0, 0, 0, -6406, 6406, 0, -15617, + 0, -15617, 15617, 0, 6406, -6406, 0, 0, + 0, 0, 0, -11393, 11393, 2993, -4233, 0, + 2993, -16112, 11393, 16112, 0, -2993, 0, 4233, + -2993, -11393, 0, 0, 0, -9974, -9974, -13617, + 0, 0, 13617, 0, 9974, 0, 0, 13617, + 0, 0, -13617, 9974, 0, 0, 0, 5579, + -5579, 10185, 14403, 0, 10185, -7890, -5579, 7890, + 0, -10185, 0, -14403, -10185, 5579, 0, 0, + 11826, -11826, -11826, -901, 901, 901, -901, 11826, + -11826, 11826, 11826, -901, 901, 901, -901, -11826, + 0, 0, -7890, -5579, 5579, 10185, 0, 14403, + -10185, 0, -5579, 0, 7890, 10185, -14403, 0, + -10185, 5579, 0, 0, -9974, 0, 0, 0, + -13617, 13617, 0, 9974, 0, 9974, -9974, 0, + 13617, -13617, 0, 0, 0, 0, 16112, -11393, + 11393, -2993, 0, 4233, 2993, 0, -11393, 0, + -16112, -2993, -4233, 0, 2993, 11393, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 32767, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 32767 +}; + diff --git a/src/libopus/mapping_matrix.h b/src/libopus/mapping_matrix.h new file mode 100644 index 00000000..98bc82df --- /dev/null +++ b/src/libopus/mapping_matrix.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file mapping_matrix.h + * @brief Opus reference implementation mapping matrix API + */ + +#ifndef MAPPING_MATRIX_H +#define MAPPING_MATRIX_H + +#include "opus_types.h" +#include "opus_projection.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct MappingMatrix +{ + int rows; /* number of channels outputted from matrix. */ + int cols; /* number of channels inputted to matrix. */ + int gain; /* in dB. S7.8-format. */ + /* Matrix cell data goes here using col-wise ordering. */ +} MappingMatrix; + +opus_int32 mapping_matrix_get_size(int rows, int cols); + +opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix); + +void mapping_matrix_init( + MappingMatrix * const matrix, + int rows, + int cols, + int gain, + const opus_int16 *data, + opus_int32 data_size +); + +#ifndef DISABLE_FLOAT_API +void mapping_matrix_multiply_channel_in_float( + const MappingMatrix *matrix, + const float *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_float( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + float *output, + int output_rows, + int frame_size +); +#endif /* DISABLE_FLOAT_API */ + +void mapping_matrix_multiply_channel_in_short( + const MappingMatrix *matrix, + const opus_int16 *input, + int input_rows, + opus_val16 *output, + int output_row, + int output_rows, + int frame_size +); + +void mapping_matrix_multiply_channel_out_short( + const MappingMatrix *matrix, + const opus_val16 *input, + int input_row, + int input_rows, + opus_int16 *output, + int output_rows, + int frame_size +); + +/* Pre-computed mixing and demixing matrices for 1st to 3rd-order ambisonics. + * foa: first-order ambisonics + * soa: second-order ambisonics + * toa: third-order ambisonics + */ +extern const MappingMatrix mapping_matrix_foa_mixing; +extern const opus_int16 mapping_matrix_foa_mixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_mixing; +extern const opus_int16 mapping_matrix_soa_mixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_mixing; +extern const opus_int16 mapping_matrix_toa_mixing_data[324]; + +extern const MappingMatrix mapping_matrix_foa_demixing; +extern const opus_int16 mapping_matrix_foa_demixing_data[36]; + +extern const MappingMatrix mapping_matrix_soa_demixing; +extern const opus_int16 mapping_matrix_soa_demixing_data[121]; + +extern const MappingMatrix mapping_matrix_toa_demixing; +extern const opus_int16 mapping_matrix_toa_demixing_data[324]; + +#ifdef __cplusplus +} +#endif + +#endif /* MAPPING_MATRIX_H */ diff --git a/src/libopus/mlp.h b/src/libopus/mlp.h new file mode 100644 index 00000000..d7670550 --- /dev/null +++ b/src/libopus/mlp.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2017 Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _MLP_H_ +#define _MLP_H_ + +#include "opus_types.h" + +#define WEIGHTS_SCALE (1.f/128) + +#define MAX_NEURONS 32 + +typedef struct { + const opus_int8 *bias; + const opus_int8 *input_weights; + int nb_inputs; + int nb_neurons; + int sigmoid; +} DenseLayer; + +typedef struct { + const opus_int8 *bias; + const opus_int8 *input_weights; + const opus_int8 *recurrent_weights; + int nb_inputs; + int nb_neurons; +} GRULayer; + +extern const DenseLayer layer0; +extern const GRULayer layer1; +extern const DenseLayer layer2; + +void compute_dense(const DenseLayer *layer, float *output, const float *input); + +void compute_gru(const GRULayer *gru, float *state, const float *input); + +#endif /* _MLP_H_ */ diff --git a/src/libopus/opus.c b/src/libopus/opus.c new file mode 100644 index 00000000..5d09056b --- /dev/null +++ b/src/libopus/opus.c @@ -0,0 +1,356 @@ +/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "opus.h" +#include "opus_private.h" + +#ifndef DISABLE_FLOAT_API +OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem) +{ + int c; + int i; + float *x; + + if (C<1 || N<1 || !_x || !declip_mem) return; + + /* First thing: saturate everything to +/- 2 which is the highest level our + non-linearity can handle. At the point where the signal reaches +/-2, + the derivative will be zero anyway, so this doesn't introduce any + discontinuity in the derivative. */ + for (i=0;i=0) + break; + x[i*C] = x[i*C]+a*x[i*C]*x[i*C]; + } + + curr=0; + x0 = x[0]; + while(1) + { + int start, end; + float maxval; + int special=0; + int peak_pos; + for (i=curr;i1 || x[i*C]<-1) + break; + } + if (i==N) + { + a=0; + break; + } + peak_pos = i; + start=end=i; + maxval=ABS16(x[i*C]); + /* Look for first zero crossing before clipping */ + while (start>0 && x[i*C]*x[(start-1)*C]>=0) + start--; + /* Look for first zero crossing after clipping */ + while (end=0) + { + /* Look for other peaks until the next zero-crossing. */ + if (ABS16(x[end*C])>maxval) + { + maxval = ABS16(x[end*C]); + peak_pos = end; + } + end++; + } + /* Detect the special case where we clip before the first zero crossing */ + special = (start==0 && x[i*C]*x[0]>=0); + + /* Compute a such that maxval + a*maxval^2 = 1 */ + a=(maxval-1)/(maxval*maxval); + /* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math + does not cause output values larger than +/-1, but small enough not + to matter even for 24-bit output. */ + a += a*2.4e-7f; + if (x[i*C]>0) + a = -a; + /* Apply soft clipping */ + for (i=start;i=2) + { + /* Add a linear ramp from the first sample to the signal peak. + This avoids a discontinuity at the beginning of the frame. */ + float delta; + float offset = x0-x[0]; + delta = offset / peak_pos; + for (i=curr;i>2; + return 2; + } +} + +static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size) +{ + if (len<1) + { + *size = -1; + return -1; + } else if (data[0]<252) + { + *size = data[0]; + return 1; + } else if (len<2) + { + *size = -1; + return -1; + } else { + *size = 4*data[1] + data[0]; + return 2; + } +} + +int opus_packet_get_samples_per_frame(const unsigned char *data, + opus_int32 Fs) +{ + int audiosize; + if (data[0]&0x80) + { + audiosize = ((data[0]>>3)&0x3); + audiosize = (Fs<>3)&0x3); + if (audiosize == 3) + audiosize = Fs*60/1000; + else + audiosize = (Fs< len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size = len-size[0]; + break; + /* Multiple CBR/VBR frames (from 0 to 120 ms) */ + default: /*case 3:*/ + if (len<1) + return OPUS_INVALID_PACKET; + /* Number of frames encoded in bits 0 to 5 */ + ch = *data++; + count = ch&0x3F; + if (count <= 0 || framesize*(opus_int32)count > 5760) + return OPUS_INVALID_PACKET; + len--; + /* Padding flag is bit 6 */ + if (ch&0x40) + { + int p; + do { + int tmp; + if (len<=0) + return OPUS_INVALID_PACKET; + p = *data++; + len--; + tmp = p==255 ? 254: p; + len -= tmp; + pad += tmp; + } while (p==255); + } + if (len<0) + return OPUS_INVALID_PACKET; + /* VBR flag is bit 7 */ + cbr = !(ch&0x80); + if (!cbr) + { + /* VBR case */ + last_size = len; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + last_size -= bytes+size[i]; + } + if (last_size<0) + return OPUS_INVALID_PACKET; + } else if (!self_delimited) + { + /* CBR case */ + last_size = len/count; + if (last_size*count!=len) + return OPUS_INVALID_PACKET; + for (i=0;i len) + return OPUS_INVALID_PACKET; + data += bytes; + /* For CBR packets, apply the size to all the frames. */ + if (cbr) + { + if (size[count-1]*count > len) + return OPUS_INVALID_PACKET; + for (i=0;i last_size) + return OPUS_INVALID_PACKET; + } else + { + /* Because it's not encoded explicitly, it's possible the size of the + last packet (or all the packets, for the CBR case) is larger than + 1275. Reject them here.*/ + if (last_size > 1275) + return OPUS_INVALID_PACKET; + size[count-1] = (opus_int16)last_size; + } + + if (payload_offset) + *payload_offset = (int)(data-data0); + + for (i=0;i + *
  • audio_frame is the audio data in opus_int16 (or float for opus_encode_float())
  • + *
  • frame_size is the duration of the frame in samples (per channel)
  • + *
  • packet is the byte array to which the compressed data is written
  • + *
  • max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended). + * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.
  • + * + * + * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet. + * The return value can be negative, which indicates that an error has occurred. If the return value + * is 2 bytes or less, then the packet does not need to be transmitted (DTX). + * + * Once the encoder state if no longer needed, it can be destroyed with + * + * @code + * opus_encoder_destroy(enc); + * @endcode + * + * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(), + * then no action is required aside from potentially freeing the memory that was manually + * allocated for it (calling free(enc) for the example above) + * + */ + +/** Opus encoder state. + * This contains the complete state of an Opus encoder. + * It is position independent and can be freely copied. + * @see opus_encoder_create,opus_encoder_init + */ +typedef struct OpusEncoder OpusEncoder; + +/** Gets the size of an OpusEncoder structure. + * @param[in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels); + +/** + */ + +/** Allocates and initializes an encoder state. + * There are three coding modes: + * + * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice + * signals. It enhances the input signal by high-pass filtering and + * emphasizing formants and harmonics. Optionally it includes in-band + * forward error correction to protect against packet loss. Use this + * mode for typical VoIP applications. Because of the enhancement, + * even at high bitrates the output may sound different from the input. + * + * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most + * non-voice signals like music. Use this mode for music and mixed + * (music/voice) content, broadcast, and applications requiring less + * than 15 ms of coding delay. + * + * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that + * disables the speech-optimized mode in exchange for slightly reduced delay. + * This mode can only be set on an newly initialized or freshly reset encoder + * because it changes the codec delay. + * + * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution). + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @param [out] error int*: @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 + * selected is too low. This also means that it is safe to always use 48 kHz stereo input + * and let the encoder optimize the encoding. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create( + opus_int32 Fs, + int channels, + int application, + int *error +); + +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be at least the size returned by opus_encoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_encoder_create(),opus_encoder_get_size() + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] Fs opus_int32: Sampling rate of input signal (Hz) + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) in input signal + * @param [in] application int: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY) + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_encoder_init( + OpusEncoder *st, + opus_int32 Fs, + int channels, + int application +) OPUS_ARG_NONNULL(1); + +/** Encodes an Opus frame. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm opus_int16*: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode( + OpusEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes an Opus frame from floating point input. + * @param [in] st OpusEncoder*: Encoder state + * @param [in] pcm float*: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. + * length is frame_size*channels*sizeof(float) + * @param [in] frame_size int: Number of samples per channel in the + * input signal. + * This must be an Opus frame size for + * the encoder's sampling rate. + * For example, at 48 kHz the permitted + * values are 120, 240, 480, 960, 1920, + * and 2880. + * Passing in a duration of less than + * 10 ms (480 samples at 48 kHz) will + * prevent the encoder from using the LPC + * or hybrid modes. + * @param [out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float( + OpusEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusEncoder allocated by opus_encoder_create(). + * @param[in] st OpusEncoder*: State to be freed. + */ +OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st); + +/** Perform a CTL function on an Opus encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusEncoder*: Encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_encoderctls. + * @see opus_genericctls + * @see opus_encoderctls + */ +OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); +/**@}*/ + +/** @defgroup opus_decoder Opus Decoder + * @{ + * + * @brief This page describes the process and functions used to decode Opus. + * + * The decoding process also starts with creating a decoder + * state. This can be done with: + * @code + * int error; + * OpusDecoder *dec; + * dec = opus_decoder_create(Fs, channels, &error); + * @endcode + * where + * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000 + * @li channels is the number of channels (1 or 2) + * @li error will hold the error code in case of failure (or #OPUS_OK on success) + * @li the return value is a newly created decoder state to be used for decoding + * + * While opus_decoder_create() allocates memory for the state, it's also possible + * to initialize pre-allocated memory: + * @code + * int size; + * int error; + * OpusDecoder *dec; + * size = opus_decoder_get_size(channels); + * dec = malloc(size); + * error = opus_decoder_init(dec, Fs, channels); + * @endcode + * where opus_decoder_get_size() returns the required size for the decoder state. Note that + * future versions of this code may change the size, so no assuptions should be made about it. + * + * The decoder state is always continuous in memory and only a shallow copy is sufficient + * to copy it (e.g. memcpy()) + * + * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data: + * @code + * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0); + * @endcode + * where + * + * @li packet is the byte array containing the compressed data + * @li len is the exact number of bytes contained in the packet + * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float()) + * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array + * + * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet. + * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio + * buffer is too small to hold the decoded audio. + * + * Opus is a stateful codec with overlapping blocks and as a result Opus + * packets are not coded independently of each other. Packets must be + * passed into the decoder serially and in the correct order for a correct + * decode. Lost packets can be replaced with loss concealment by calling + * the decoder with a null pointer and zero length for the missing packet. + * + * A single codec state may only be accessed from a single thread at + * a time and any required locking must be performed by the caller. Separate + * streams must be decoded with separate decoder states and can be decoded + * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK + * defined. + * + */ + +/** Opus decoder state. + * This contains the complete state of an Opus decoder. + * It is position independent and can be freely copied. + * @see opus_decoder_create,opus_decoder_init + */ +typedef struct OpusDecoder OpusDecoder; + +/** Gets the size of an OpusDecoder structure. + * @param [in] channels int: Number of channels. + * This must be 1 or 2. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels); + +/** Allocates and initializes a decoder state. + * @param [in] Fs opus_int32: Sample rate to decode at (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @param [out] error int*: #OPUS_OK Success or @ref opus_errorcodes + * + * Internally Opus stores data at 48000 Hz, so that should be the default + * value for Fs. However, the decoder can efficiently decode to buffers + * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use + * data at the full sample rate, or knows the compressed data doesn't + * use the full frequency range, it can request decoding at a reduced + * rate. Likewise, the decoder is capable of filling in either mono or + * interleaved stereo pcm buffers, at the caller's request. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create( + opus_int32 Fs, + int channels, + int *error +); + +/** Initializes a previously allocated decoder state. + * The state must be at least the size returned by opus_decoder_get_size(). + * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @param [in] st OpusDecoder*: Decoder state. + * @param [in] Fs opus_int32: Sampling rate to decode to (Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param [in] channels int: Number of channels (1 or 2) to decode + * @retval #OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_EXPORT int opus_decoder_init( + OpusDecoder *st, + opus_int32 Fs, + int channels +) OPUS_ARG_NONNULL(1); + +/** Decode an Opus packet. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload* + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available, the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an Opus packet with floating point output. + * @param [in] st OpusDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len opus_int32: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in \a pcm. + * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will + * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1), + * then frame_size needs to be exactly the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and + * FEC cases, frame_size must be a multiple of 2.5 ms. + * @param [in] decode_fec int: Flag (0 or 1) to request that any in-band forward error correction data be + * decoded. If no such data is available the frame is decoded as if it were lost. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float( + OpusDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @param st OpusDecoder*: Decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls or + * @ref opus_decoderctls. + * @see opus_genericctls + * @see opus_decoderctls + */ +OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusDecoder allocated by opus_decoder_create(). + * @param[in] st OpusDecoder*: State to be freed. + */ +OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st); + +/** Parse an opus packet into one or more frames. + * Opus_decode will perform this operation internally so most applications do + * not need to use this function. + * This function does not copy the frames, the returned pointers are pointers into + * the input packet. + * @param [in] data char*: Opus packet to be parsed + * @param [in] len opus_int32: size of data + * @param [out] out_toc char*: TOC pointer + * @param [out] frames char*[48] encapsulated frames + * @param [out] size opus_int16[48] sizes of the encapsulated frames + * @param [out] payload_offset int*: returns the position of the payload within the packet (in bytes) + * @returns number of frames + */ +OPUS_EXPORT int opus_packet_parse( + const unsigned char *data, + opus_int32 len, + unsigned char *out_toc, + const unsigned char *frames[48], + opus_int16 size[48], + int *payload_offset +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5); + +/** Gets the bandwidth of an Opus packet. + * @param [in] data char*: Opus packet + * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass) + * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass) + * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass) + * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass) + * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass) + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples per frame from an Opus packet. + * @param [in] data char*: Opus packet. + * This must contain at least one byte of + * data. + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples per frame. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of channels from an Opus packet. + * @param [in] data char*: Opus packet + * @returns Number of channels + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1); + +/** Gets the number of frames in an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of frames + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @param [in] Fs opus_int32: Sampling rate in Hz. + * This must be a multiple of 400, or + * inaccurate results will be returned. + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1); + +/** Gets the number of samples of an Opus packet. + * @param [in] dec OpusDecoder*: Decoder state + * @param [in] packet char*: Opus packet + * @param [in] len opus_int32: Length of packet + * @returns Number of samples + * @retval OPUS_BAD_ARG Insufficient data was passed to the function + * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +/** Applies soft-clipping to bring a float signal within the [-1,1] range. If + * the signal is already in that range, nothing is done. If there are values + * outside of [-1,1], then the signal is clipped as smoothly as possible to + * both fit in the range and avoid creating excessive distortion in the + * process. + * @param [in,out] pcm float*: Input PCM and modified PCM + * @param [in] frame_size int Number of samples per channel to process + * @param [in] channels int: Number of channels + * @param [in,out] softclip_mem float*: State memory for the soft clipping process (one float per channel, initialized to zero) + */ +OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem); + + +/**@}*/ + +/** @defgroup opus_repacketizer Repacketizer + * @{ + * + * The repacketizer can be used to merge multiple Opus packets into a single + * packet or alternatively to split Opus packets that have previously been + * merged. Splitting valid Opus packets is always guaranteed to succeed, + * whereas merging valid packets only succeeds if all frames have the same + * mode, bandwidth, and frame size, and when the total duration of the merged + * packet is no more than 120 ms. The 120 ms limit comes from the + * specification and limits decoder memory requirements at a point where + * framing overhead becomes negligible. + * + * The repacketizer currently only operates on elementary Opus + * streams. It will not manipualte multistream packets successfully, except in + * the degenerate case where they consist of data from a single stream. + * + * The repacketizing process starts with creating a repacketizer state, either + * by calling opus_repacketizer_create() or by allocating the memory yourself, + * e.g., + * @code + * OpusRepacketizer *rp; + * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size()); + * if (rp != NULL) + * opus_repacketizer_init(rp); + * @endcode + * + * Then the application should submit packets with opus_repacketizer_cat(), + * extract new packets with opus_repacketizer_out() or + * opus_repacketizer_out_range(), and then reset the state for the next set of + * input packets via opus_repacketizer_init(). + * + * For example, to split a sequence of packets into individual frames: + * @code + * unsigned char *data; + * int len; + * while (get_next_packet(&data, &len)) + * { + * unsigned char out[1276]; + * opus_int32 out_len; + * int nb_frames; + * int err; + * int i; + * err = opus_repacketizer_cat(rp, data, len); + * if (err != OPUS_OK) + * { + * release_packet(data); + * return err; + * } + * nb_frames = opus_repacketizer_get_nb_frames(rp); + * for (i = 0; i < nb_frames; i++) + * { + * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packet(data); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * } + * opus_repacketizer_init(rp); + * release_packet(data); + * } + * @endcode + * + * Alternatively, to combine a sequence of frames into packets that each + * contain up to TARGET_DURATION_MS milliseconds of data: + * @code + * // The maximum number of packets with duration TARGET_DURATION_MS occurs + * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5) + * // packets. + * unsigned char *data[(TARGET_DURATION_MS*2/5)+1]; + * opus_int32 len[(TARGET_DURATION_MS*2/5)+1]; + * int nb_packets; + * unsigned char out[1277*(TARGET_DURATION_MS*2/2)]; + * opus_int32 out_len; + * int prev_toc; + * nb_packets = 0; + * while (get_next_packet(data+nb_packets, len+nb_packets)) + * { + * int nb_frames; + * int err; + * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]); + * if (nb_frames < 1) + * { + * release_packets(data, nb_packets+1); + * return nb_frames; + * } + * nb_frames += opus_repacketizer_get_nb_frames(rp); + * // If adding the next packet would exceed our target, or it has an + * // incompatible TOC sequence, output the packets we already have before + * // submitting it. + * // N.B., The nb_packets > 0 check ensures we've submitted at least one + * // packet since the last call to opus_repacketizer_init(). Otherwise a + * // single packet longer than TARGET_DURATION_MS would cause us to try to + * // output an (invalid) empty packet. It also ensures that prev_toc has + * // been set to a valid value. Additionally, len[nb_packets] > 0 is + * // guaranteed by the call to opus_packet_get_nb_frames() above, so the + * // reference to data[nb_packets][0] should be valid. + * if (nb_packets > 0 && ( + * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) || + * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames > + * TARGET_DURATION_MS*48)) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * if (out_len < 0) + * { + * release_packets(data, nb_packets+1); + * return (int)out_len; + * } + * output_next_packet(out, out_len); + * opus_repacketizer_init(rp); + * release_packets(data, nb_packets); + * data[0] = data[nb_packets]; + * len[0] = len[nb_packets]; + * nb_packets = 0; + * } + * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]); + * if (err != OPUS_OK) + * { + * release_packets(data, nb_packets+1); + * return err; + * } + * prev_toc = data[nb_packets][0]; + * nb_packets++; + * } + * // Output the final, partial packet. + * if (nb_packets > 0) + * { + * out_len = opus_repacketizer_out(rp, out, sizeof(out)); + * release_packets(data, nb_packets); + * if (out_len < 0) + * return (int)out_len; + * output_next_packet(out, out_len); + * } + * @endcode + * + * An alternate way of merging packets is to simply call opus_repacketizer_cat() + * unconditionally until it fails. At that point, the merged packet can be + * obtained with opus_repacketizer_out() and the input packet for which + * opus_repacketizer_cat() needs to be re-added to a newly reinitialized + * repacketizer state. + */ + +typedef struct OpusRepacketizer OpusRepacketizer; + +/** Gets the size of an OpusRepacketizer structure. + * @returns The size in bytes. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void); + +/** (Re)initializes a previously allocated repacketizer state. + * The state must be at least the size returned by opus_repacketizer_get_size(). + * This can be used for applications which use their own allocator instead of + * malloc(). + * It must also be called to reset the queue of packets waiting to be + * repacketized, which is necessary if the maximum packet duration of 120 ms + * is reached or if you wish to submit packets with a different Opus + * configuration (coding mode, audio bandwidth, frame size, or channel count). + * Failure to do so will prevent a new packet from being added with + * opus_repacketizer_cat(). + * @see opus_repacketizer_create + * @see opus_repacketizer_get_size + * @see opus_repacketizer_cat + * @param rp OpusRepacketizer*: The repacketizer state to + * (re)initialize. + * @returns A pointer to the same repacketizer state that was passed in. + */ +OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Allocates memory and initializes the new repacketizer with + * opus_repacketizer_init(). + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void); + +/** Frees an OpusRepacketizer allocated by + * opus_repacketizer_create(). + * @param[in] rp OpusRepacketizer*: State to be freed. + */ +OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp); + +/** Add a packet to the current repacketizer state. + * This packet must match the configuration of any packets already submitted + * for repacketization since the last call to opus_repacketizer_init(). + * This means that it must have the same coding mode, audio bandwidth, frame + * size, and channel count. + * This can be checked in advance by examining the top 6 bits of the first + * byte of the packet, and ensuring they match the top 6 bits of the first + * byte of any previously submitted packet. + * The total duration of audio in the repacketizer state also must not exceed + * 120 ms, the maximum duration of a single packet, after adding this packet. + * + * The contents of the current repacketizer state can be extracted into new + * packets using opus_repacketizer_out() or opus_repacketizer_out_range(). + * + * In order to add a packet with a different configuration or to add more + * audio beyond 120 ms, you must clear the repacketizer state by calling + * opus_repacketizer_init(). + * If a packet is too large to add to the current repacketizer state, no part + * of it is added, even if it contains multiple frames, some of which might + * fit. + * If you wish to be able to add parts of such packets, you should first use + * another repacketizer to split the packet into pieces and add them + * individually. + * @see opus_repacketizer_out_range + * @see opus_repacketizer_out + * @see opus_repacketizer_init + * @param rp OpusRepacketizer*: The repacketizer state to which to + * add the packet. + * @param[in] data const unsigned char*: The packet data. + * The application must ensure + * this pointer remains valid + * until the next call to + * opus_repacketizer_init() or + * opus_repacketizer_destroy(). + * @param len opus_int32: The number of bytes in the packet data. + * @returns An error code indicating whether or not the operation succeeded. + * @retval #OPUS_OK The packet's contents have been added to the repacketizer + * state. + * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence, + * the packet's TOC sequence was not compatible + * with previously submitted packets (because + * the coding mode, audio bandwidth, frame size, + * or channel count did not match), or adding + * this packet would increase the total amount of + * audio stored in the repacketizer state to more + * than 120 ms. + */ +OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param begin int: The index of the first frame in the current + * repacketizer state to include in the output. + * @param end int: One past the index of the last frame in the + * current repacketizer state to include in the + * output. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1276 for a single frame, + * or for multiple frames, + * 1277*(end-begin). + * However, 1*(end-begin) plus + * the size of all packet data submitted to + * the repacketizer since the last call to + * opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG [begin,end) was an invalid range of + * frames (begin < 0, begin >= end, or end > + * opus_repacketizer_get_nb_frames()). + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Return the total number of frames contained in packet data submitted to + * the repacketizer state so far via opus_repacketizer_cat() since the last + * call to opus_repacketizer_init() or opus_repacketizer_create(). + * This defines the valid range of packets that can be extracted with + * opus_repacketizer_out_range() or opus_repacketizer_out(). + * @param rp OpusRepacketizer*: The repacketizer state containing the + * frames. + * @returns The total number of frames contained in the packet data submitted + * to the repacketizer state. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1); + +/** Construct a new packet from data previously submitted to the repacketizer + * state via opus_repacketizer_cat(). + * This is a convenience routine that returns all the data submitted so far + * in a single packet. + * It is equivalent to calling + * @code + * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp), + * data, maxlen) + * @endcode + * @param rp OpusRepacketizer*: The repacketizer state from which to + * construct the new packet. + * @param[out] data const unsigned char*: The buffer in which to + * store the output packet. + * @param maxlen opus_int32: The maximum number of bytes to store in + * the output buffer. In order to guarantee + * success, this should be at least + * 1277*opus_repacketizer_get_nb_frames(rp). + * However, + * 1*opus_repacketizer_get_nb_frames(rp) + * plus the size of all packet data + * submitted to the repacketizer since the + * last call to opus_repacketizer_init() or + * opus_repacketizer_create() is also + * sufficient, and possibly much smaller. + * @returns The total size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the + * complete output packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1); + +/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len); + +/** Remove all padding from a given Opus packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len); + +/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence). + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to pad. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param new_len opus_int32: The desired size of the packet after padding. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least as large as len. + * @returns an error code + * @retval #OPUS_OK \a on success. + * @retval #OPUS_BAD_ARG \a len was less than 1. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams); + +/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to + * minimize space usage. + * @param[in,out] data const unsigned char*: The buffer containing the + * packet to strip. + * @param len opus_int32: The size of the packet. + * This must be at least 1. + * @param nb_streams opus_int32: The number of streams (not channels) in the packet. + * This must be at least 1. + * @returns The new size of the output packet on success, or an error code + * on failure. + * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len. + * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_H */ diff --git a/src/libopus/opus.pc b/src/libopus/opus.pc new file mode 100644 index 00000000..da284cf9 --- /dev/null +++ b/src/libopus/opus.pc @@ -0,0 +1,16 @@ +# Opus codec reference implementation pkg-config file + +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: Opus +Description: Opus IETF audio codec (fixed-point build) +URL: https://opus-codec.org/ +Version: 1.3.1 +Requires: +Conflicts: +Libs: -L${libdir} -lopus +Libs.private: -lm +Cflags: -I${includedir}/opus diff --git a/src/libopus/opus_custom.h b/src/libopus/opus_custom.h new file mode 100644 index 00000000..41f36bf2 --- /dev/null +++ b/src/libopus/opus_custom.h @@ -0,0 +1,342 @@ +/* Copyright (c) 2007-2008 CSIRO + Copyright (c) 2007-2009 Xiph.Org Foundation + Copyright (c) 2008-2012 Gregory Maxwell + Written by Jean-Marc Valin and Gregory Maxwell */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + @file opus_custom.h + @brief Opus-Custom reference implementation API + */ + +#ifndef OPUS_CUSTOM_H +#define OPUS_CUSTOM_H + +#include "opus_defines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CUSTOM_MODES +# define OPUS_CUSTOM_EXPORT OPUS_EXPORT +# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT +#else +# define OPUS_CUSTOM_EXPORT +# ifdef OPUS_BUILD +# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE +# else +# define OPUS_CUSTOM_EXPORT_STATIC +# endif +#endif + +/** @defgroup opus_custom Opus Custom + * @{ + * Opus Custom is an optional part of the Opus specification and + * reference implementation which uses a distinct API from the regular + * API and supports frame sizes that are not normally supported.\ Use + * of Opus Custom is discouraged for all but very special applications + * for which a frame size different from 2.5, 5, 10, or 20 ms is needed + * (for either complexity or latency reasons) and where interoperability + * is less important. + * + * In addition to the interoperability limitations the use of Opus custom + * disables a substantial chunk of the codec and generally lowers the + * quality available at a given bitrate. Normally when an application needs + * a different frame size from the codec it should buffer to match the + * sizes but this adds a small amount of delay which may be important + * in some very low latency applications. Some transports (especially + * constant rate RF transports) may also work best with frames of + * particular durations. + * + * Libopus only supports custom modes if they are enabled at compile time. + * + * The Opus Custom API is similar to the regular API but the + * @ref opus_encoder_create and @ref opus_decoder_create calls take + * an additional mode parameter which is a structure produced by + * a call to @ref opus_custom_mode_create. Both the encoder and decoder + * must create a mode using the same sample rate (fs) and frame size + * (frame size) so these parameters must either be signaled out of band + * or fixed in a particular implementation. + * + * Similar to regular Opus the custom modes support on the fly frame size + * switching, but the sizes available depend on the particular frame size in + * use. For some initial frame sizes on a single on the fly size is available. + */ + +/** Contains the state of an encoder. One encoder state is needed + for each stream. It is initialized once at the beginning of the + stream. Do *not* re-initialize the state for every frame. + @brief Encoder state + */ +typedef struct OpusCustomEncoder OpusCustomEncoder; + +/** State of the decoder. One decoder state is needed for each stream. + It is initialized once at the beginning of the stream. Do *not* + re-initialize the state for every frame. + @brief Decoder state + */ +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. + @brief Mode configuration + */ +typedef struct OpusCustomMode OpusCustomMode; + +/** Creates a new mode struct. This will be passed to an encoder or + * decoder. The mode MUST NOT BE DESTROYED until the encoders and + * decoders that use it are destroyed as well. + * @param [in] Fs int: Sampling rate (8000 to 96000 Hz) + * @param [in] frame_size int: Number of samples (per channel) to encode in each + * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes) + * @param [out] error int*: Returned error code (if NULL, no error will be returned) + * @return A newly created mode + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error); + +/** Destroys a mode struct. Only call this after all encoders and + * decoders using this mode are destroyed as well. + * @param [in] mode OpusCustomMode*: Mode to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode); + + +#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C) + +/* Encoder */ +/** Gets the size of an OpusCustomEncoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +# ifdef CUSTOM_MODES +/** Initializes a previously allocated encoder state + * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_encoder_create(),opus_custom_encoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_init( + OpusCustomEncoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); +# endif +#endif + + +/** Creates a new encoder state. Each stream needs its own encoder + * state (can't be shared across simultaneous streams). + * @param [in] mode OpusCustomMode*: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * decoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created encoder state. +*/ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + + +/** Destroys a an encoder state. + * @param[in] st OpusCustomEncoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm float*: PCM audio in float format, with a normal range of +/-1.0. + * Samples with a range beyond +/-1.0 are supported but will + * be clipped by decoders using the integer API and should + * only be used if it is known that the far end supports + * extended dynamic range. There must be exactly + * frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float( + OpusCustomEncoder *st, + const float *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a frame of audio. + * @param [in] st OpusCustomEncoder*: Encoder state + * @param [in] pcm opus_int16*: PCM audio in signed 16-bit format (native endian). + * There must be exactly frame_size samples per channel. + * @param [in] frame_size int: Number of samples per frame of input signal + * @param [out] compressed char *: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long. + * @param [in] maxCompressedBytes int: Maximum number of bytes to use for compressing the frame + * (can change from one frame to another) + * @return Number of bytes written to "compressed". + * If negative, an error has occurred (see error codes). It is IMPORTANT that + * the length returned be somehow transmitted to the decoder. Otherwise, no + * decoding is possible. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode( + OpusCustomEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *compressed, + int maxCompressedBytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom encoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_encoderctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + + +#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C) +/* Decoder */ + +/** Gets the size of an OpusCustomDecoder structure. + * @param [in] mode OpusCustomMode *: Mode configuration + * @param [in] channels int: Number of channels + * @returns size + */ +OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size( + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1); + +/** Initializes a previously allocated decoder state + * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size. + * This is intended for applications which use their own allocator instead of malloc. + * @see opus_custom_decoder_create(),opus_custom_decoder_get_size() + * To reset a previously initialized state use the OPUS_RESET_STATE CTL. + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] mode OpusCustomMode *: Contains all the information about the characteristics of + * the stream (must be the same characteristics as used for the + * encoder) + * @param [in] channels int: Number of channels + * @return OPUS_OK Success or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init( + OpusCustomDecoder *st, + const OpusCustomMode *mode, + int channels +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2); + +#endif + + +/** Creates a new decoder state. Each stream needs its own decoder state (can't + * be shared across simultaneous streams). + * @param [in] mode OpusCustomMode: Contains all the information about the characteristics of the + * stream (must be the same characteristics as used for the encoder) + * @param [in] channels int: Number of channels + * @param [out] error int*: Returns an error code + * @return Newly created decoder state. + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create( + const OpusCustomMode *mode, + int channels, + int *error +) OPUS_ARG_NONNULL(1); + +/** Destroys a an decoder state. + * @param[in] st OpusCustomDecoder*: State to be freed. + */ +OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st); + +/** Decode an opus custom frame with floating point output + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm float*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(float) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + float *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode an opus custom frame + * @param [in] st OpusCustomDecoder*: Decoder state + * @param [in] data char*: Input payload. Use a NULL pointer to indicate packet loss + * @param [in] len int: Number of bytes in payload + * @param [out] pcm opus_int16*: Output signal (interleaved if 2 channels). length + * is frame_size*channels*sizeof(opus_int16) + * @param [in] frame_size Number of samples per channel of available space in *pcm. + * @returns Number of decoded samples or @ref opus_errorcodes + */ +OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode( + OpusCustomDecoder *st, + const unsigned char *data, + int len, + opus_int16 *pcm, + int frame_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on an Opus custom decoder. + * + * Generally the request and subsequent arguments are generated + * by a convenience macro. + * @see opus_genericctls + */ +OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_CUSTOM_H */ diff --git a/src/libopus/opus_decoder.c b/src/libopus/opus_decoder.c new file mode 100644 index 00000000..23f9a01e --- /dev/null +++ b/src/libopus/opus_decoder.c @@ -0,0 +1,1033 @@ +/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +# include "config.h" +//#endif + +#ifndef OPUS_BUILD +# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details." +#endif + +#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__) && !defined(OPUS_WILL_BE_SLOW) +// Yes, I know... +// # pragma message "You appear to be compiling without optimization, if so opus will be very slow." +#endif + +#include +#include "celt/celt.h" +#include "opus.h" +#include "celt/entdec.h" +#include "celt/modes.h" +#include "silk/API.h" +#include "celt/stack_alloc.h" +#include "celt/float_cast.h" +#include "opus_private.h" +#include "celt/os_support.h" +#include "silk/structs.h" +#include "silk/define.h" +#include "celt/mathops.h" +#include "celt/cpu_support.h" + +struct OpusDecoder { + int celt_dec_offset; + int silk_dec_offset; + int channels; + opus_int32 Fs; /** Sampling rate (at the API level) */ + silk_DecControlStruct DecControl; + int decode_gain; + int arch; + + /* Everything beyond this point gets cleared on a reset */ +#define OPUS_DECODER_RESET_START stream_channels + int stream_channels; + + int bandwidth; + int mode; + int prev_mode; + int frame_size; + int prev_redundancy; + int last_packet_duration; +#ifndef FIXED_POINT + opus_val16 softclip_mem[2]; +#endif + + opus_uint32 rangeFinal; +}; + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_opus_decoder(OpusDecoder *st) +{ + celt_assert(st->channels == 1 || st->channels == 2); + celt_assert(st->Fs == 48000 || st->Fs == 24000 || st->Fs == 16000 || st->Fs == 12000 || st->Fs == 8000); + celt_assert(st->DecControl.API_sampleRate == st->Fs); + celt_assert(st->DecControl.internalSampleRate == 0 || st->DecControl.internalSampleRate == 16000 || st->DecControl.internalSampleRate == 12000 || st->DecControl.internalSampleRate == 8000); + celt_assert(st->DecControl.nChannelsAPI == st->channels); + celt_assert(st->DecControl.nChannelsInternal == 0 || st->DecControl.nChannelsInternal == 1 || st->DecControl.nChannelsInternal == 2); + celt_assert(st->DecControl.payloadSize_ms == 0 || st->DecControl.payloadSize_ms == 10 || st->DecControl.payloadSize_ms == 20 || st->DecControl.payloadSize_ms == 40 || st->DecControl.payloadSize_ms == 60); +#ifdef OPUS_ARCHMASK + celt_assert(st->arch >= 0); + celt_assert(st->arch <= OPUS_ARCHMASK); +#endif + celt_assert(st->stream_channels == 1 || st->stream_channels == 2); +} +#define VALIDATE_OPUS_DECODER(st) validate_opus_decoder(st) +#else +#define VALIDATE_OPUS_DECODER(st) +#endif + +int opus_decoder_get_size(int channels) +{ + int silkDecSizeBytes, celtDecSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Decoder_Size( &silkDecSizeBytes ); + if(ret) + return 0; + silkDecSizeBytes = align(silkDecSizeBytes); + celtDecSizeBytes = celt_decoder_get_size(channels); + return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes; +} + +int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels) +{ + void *silk_dec; + CELTDecoder *celt_dec; + int ret, silkDecSizeBytes; + + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_decoder_get_size(channels)); + /* Initialize SILK decoder */ + ret = silk_Get_Decoder_Size(&silkDecSizeBytes); + if (ret) + return OPUS_INTERNAL_ERROR; + + silkDecSizeBytes = align(silkDecSizeBytes); + st->silk_dec_offset = align(sizeof(OpusDecoder)); + st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes; + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + st->DecControl.API_sampleRate = st->Fs; + st->DecControl.nChannelsAPI = st->channels; + + /* Reset decoder */ + ret = silk_InitDecoder( silk_dec ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* Initialize CELT decoder */ + ret = celt_decoder_init(celt_dec, Fs, channels); + if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0)); + + st->prev_mode = 0; + st->frame_size = Fs/400; + st->arch = opus_select_arch(); + return OPUS_OK; +} + +OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error) +{ + int ret; + OpusDecoder *st; + if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000) + || (channels!=1&&channels!=2)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels)); + if (st == NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_decoder_init(st, Fs, channels); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, + opus_val16 *out, int overlap, int channels, + const opus_val16 *window, opus_int32 Fs) +{ + int i, c; + int inc = 48000/Fs; + for (c=0;csilk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + F20 = st->Fs/50; + F10 = F20>>1; + F5 = F10>>1; + F2_5 = F5>>1; + if (frame_size < F2_5) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + /* Limit frame_size to avoid excessive stack allocations. */ + frame_size = IMIN(frame_size, st->Fs/25*3); + /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */ + if (len<=1) + { + data = NULL; + /* In that case, don't conceal more than what the ToC says */ + frame_size = IMIN(frame_size, st->frame_size); + } + if (data != NULL) + { + audiosize = st->frame_size; + mode = st->mode; + bandwidth = st->bandwidth; + ec_dec_init(&dec,(unsigned char*)data,len); + } else { + audiosize = frame_size; + mode = st->prev_mode; + bandwidth = 0; + + if (mode == 0) + { + /* If we haven't got any packet yet, all we can do is return zeros */ + for (i=0;ichannels;i++) + pcm[i] = 0; + RESTORE_STACK; + return audiosize; + } + + /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT), + 10, or 20 (e.g. 12.5 or 30 ms). */ + if (audiosize > F20) + { + do { + int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0); + if (ret<0) + { + RESTORE_STACK; + return ret; + } + pcm += ret*st->channels; + audiosize -= ret; + } while (audiosize > 0); + RESTORE_STACK; + return frame_size; + } else if (audiosize < F20) + { + if (audiosize > F10) + audiosize = F10; + else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10) + audiosize = F5; + } + } + + /* In fixed-point, we can tell CELT to do the accumulation on top of the + SILK PCM buffer. This saves some stack space. */ +#ifdef FIXED_POINT + celt_accum = (mode != MODE_CELT_ONLY) && (frame_size >= F10); +#else + celt_accum = 0; +#endif + + pcm_transition_silk_size = ALLOC_NONE; + pcm_transition_celt_size = ALLOC_NONE; + if (data!=NULL && st->prev_mode > 0 && ( + (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy) + || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ) + ) + { + transition = 1; + /* Decide where to allocate the stack memory for pcm_transition */ + if (mode == MODE_CELT_ONLY) + pcm_transition_celt_size = F5*st->channels; + else + pcm_transition_silk_size = F5*st->channels; + } + ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16); + if (transition && mode == MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_celt; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + if (audiosize > frame_size) + { + /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/ + RESTORE_STACK; + return OPUS_BAD_ARG; + } else { + frame_size = audiosize; + } + + /* Don't allocate any memory when in CELT-only mode */ + pcm_silk_size = (mode != MODE_CELT_ONLY && !celt_accum) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE; + ALLOC(pcm_silk, pcm_silk_size, opus_int16); + + /* SILK processing */ + if (mode != MODE_CELT_ONLY) + { + int lost_flag, decoded_samples; + opus_int16 *pcm_ptr; +#ifdef FIXED_POINT + if (celt_accum) + pcm_ptr = pcm; + else +#endif + pcm_ptr = pcm_silk; + + if (st->prev_mode==MODE_CELT_ONLY) + silk_InitDecoder( silk_dec ); + + /* The SILK PLC cannot produce frames of less than 10 ms */ + st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs); + + if (data != NULL) + { + st->DecControl.nChannelsInternal = st->stream_channels; + if( mode == MODE_SILK_ONLY ) { + if( bandwidth == OPUS_BANDWIDTH_NARROWBAND ) { + st->DecControl.internalSampleRate = 8000; + } else if( bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) { + st->DecControl.internalSampleRate = 12000; + } else if( bandwidth == OPUS_BANDWIDTH_WIDEBAND ) { + st->DecControl.internalSampleRate = 16000; + } else { + st->DecControl.internalSampleRate = 16000; + celt_assert( 0 ); + } + } else { + /* Hybrid mode */ + st->DecControl.internalSampleRate = 16000; + } + } + + lost_flag = data == NULL ? 1 : 2 * decode_fec; + decoded_samples = 0; + do { + /* Call SILK decoder */ + int first_frame = decoded_samples == 0; + silk_ret = silk_Decode( silk_dec, &st->DecControl, + lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size, st->arch ); + if( silk_ret ) { + if (lost_flag) { + /* PLC failure should not be fatal */ + silk_frame_size = frame_size; + for (i=0;ichannels;i++) + pcm_ptr[i] = 0; + } else { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + pcm_ptr += silk_frame_size * st->channels; + decoded_samples += silk_frame_size; + } while( decoded_samples < frame_size ); + } + + start_band = 0; + if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL + && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len) + { + /* Check if we have a redundant 0-8 kHz band */ + if (mode == MODE_HYBRID) + redundancy = ec_dec_bit_logp(&dec, 12); + else + redundancy = 1; + if (redundancy) + { + celt_to_silk = ec_dec_bit_logp(&dec, 1); + /* redundancy_bytes will be at least two, in the non-hybrid + case due to the ec_tell() check above */ + redundancy_bytes = mode==MODE_HYBRID ? + (opus_int32)ec_dec_uint(&dec, 256)+2 : + len-((ec_tell(&dec)+7)>>3); + len -= redundancy_bytes; + /* This is a sanity check. It should never happen for a valid + packet, so the exact behaviour is not normative. */ + if (len*8 < ec_tell(&dec)) + { + len = 0; + redundancy_bytes = 0; + redundancy = 0; + } + /* Shrink decoder because of raw bits */ + dec.storage -= redundancy_bytes; + } + } + if (mode != MODE_CELT_ONLY) + start_band = 17; + + if (redundancy) + { + transition = 0; + pcm_transition_silk_size=ALLOC_NONE; + } + + ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16); + + if (transition && mode != MODE_CELT_ONLY) + { + pcm_transition = pcm_transition_silk; + opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0); + } + + + if (bandwidth) + { + int endband=21; + + switch(bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + default: + celt_assert(0); + break; + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband))); + } + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels))); + + /* Only allocation memory for redundancy if/when needed */ + redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE; + ALLOC(redundant_audio, redundant_audio_size, opus_val16); + + /* 5 ms redundant frame for CELT->SILK*/ + if (redundancy && celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, + redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + } + + /* MUST be after PLC */ + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band))); + + if (mode != MODE_SILK_ONLY) + { + int celt_frame_size = IMIN(F20, frame_size); + /* Make sure to discard any previous CELT state */ + if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy) + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + /* Decode CELT */ + celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data, + len, pcm, celt_frame_size, &dec, celt_accum); + } else { + unsigned char silence[2] = {0xFF, 0xFF}; + if (!celt_accum) + { + for (i=0;ichannels;i++) + pcm[i] = 0; + } + /* For hybrid -> SILK transitions, we let the CELT MDCT + do a fade-out by decoding a silence frame */ + if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) ) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum); + } + } + + if (mode != MODE_CELT_ONLY && !celt_accum) + { +#ifdef FIXED_POINT + for (i=0;ichannels;i++) + pcm[i] = SAT16(ADD32(pcm[i], pcm_silk[i])); +#else + for (i=0;ichannels;i++) + pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]); +#endif + } + + { + const CELTMode *celt_mode; + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode))); + window = celt_mode->window; + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE)); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0))); + + celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0); + MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng))); + smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, + pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); + } + if (redundancy && celt_to_silk) + { + for (c=0;cchannels;c++) + { + for (i=0;ichannels*i+c] = redundant_audio[st->channels*i+c]; + } + smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs); + } + if (transition) + { + if (audiosize >= F5) + { + for (i=0;ichannels*F2_5;i++) + pcm[i] = pcm_transition[i]; + smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5, + pcm+st->channels*F2_5, F2_5, + st->channels, window, st->Fs); + } else { + /* Not enough time to do a clean transition, but we do it anyway + This will not preserve amplitude perfectly and may introduce + a bit of temporal aliasing, but it shouldn't be too bad and + that's pretty much the best we can do. In any case, generating this + transition it pretty silly in the first place */ + smooth_fade(pcm_transition, pcm, + pcm, F2_5, + st->channels, window, st->Fs); + } + } + + if(st->decode_gain) + { + opus_val32 gain; + gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain)); + for (i=0;ichannels;i++) + { + opus_val32 x; + x = MULT16_32_P16(pcm[i],gain); + pcm[i] = SATURATE(x, 32767); + } + } + + if (len <= 1) + st->rangeFinal = 0; + else + st->rangeFinal = dec.rng ^ redundant_rng; + + st->prev_mode = mode; + st->prev_redundancy = redundancy && !celt_to_silk; + + if (celt_ret>=0) + { + if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels)) + OPUS_PRINT_INT(audiosize); + } + + RESTORE_STACK; + return celt_ret < 0 ? celt_ret : audiosize; + +} + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec, + int self_delimited, opus_int32 *packet_offset, int soft_clip) +{ + int i, nb_samples; + int count, offset; + unsigned char toc; + int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels; + /* 48 x 2.5 ms = 120 ms */ + opus_int16 size[48]; + VALIDATE_OPUS_DECODER(st); + if (decode_fec<0 || decode_fec>1) + return OPUS_BAD_ARG; + /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */ + if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0) + return OPUS_BAD_ARG; + if (len==0 || data==NULL) + { + int pcm_count=0; + do { + int ret; + ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0); + if (ret<0) + return ret; + pcm_count += ret; + } while (pcm_count < frame_size); + celt_assert(pcm_count == frame_size); + if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels)) + OPUS_PRINT_INT(pcm_count); + st->last_packet_duration = pcm_count; + return pcm_count; + } else if (len<0) + return OPUS_BAD_ARG; + + packet_mode = opus_packet_get_mode(data); + packet_bandwidth = opus_packet_get_bandwidth(data); + packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs); + packet_stream_channels = opus_packet_get_nb_channels(data); + + count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, + size, &offset, packet_offset); + if (count<0) + return count; + + data += offset; + + if (decode_fec) + { + int duration_copy; + int ret; + /* If no FEC can be present, run the PLC (recursive call) */ + if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY) + return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip); + /* Otherwise, run the PLC on everything except the size for which we might have FEC */ + duration_copy = st->last_packet_duration; + if (frame_size-packet_frame_size!=0) + { + ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip); + if (ret<0) + { + st->last_packet_duration = duration_copy; + return ret; + } + celt_assert(ret==frame_size-packet_frame_size); + } + /* Complete with FEC */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size), + packet_frame_size, 1); + if (ret<0) + return ret; + else { + if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels)) + OPUS_PRINT_INT(frame_size); + st->last_packet_duration = frame_size; + return frame_size; + } + } + + if (count*packet_frame_size > frame_size) + return OPUS_BUFFER_TOO_SMALL; + + /* Update the state as the last step to avoid updating it on an invalid packet */ + st->mode = packet_mode; + st->bandwidth = packet_bandwidth; + st->frame_size = packet_frame_size; + st->stream_channels = packet_stream_channels; + + nb_samples=0; + for (i=0;ichannels, frame_size-nb_samples, 0); + if (ret<0) + return ret; + celt_assert(ret==packet_frame_size); + data += size[i]; + nb_samples += ret; + } + st->last_packet_duration = nb_samples; + if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels)) + OPUS_PRINT_INT(nb_samples); +#ifndef FIXED_POINT + if (soft_clip) + opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem); + else + st->softclip_mem[0]=st->softclip_mem[1]=0; +#endif + return nb_samples; +} + +#ifdef FIXED_POINT + +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#ifndef DISABLE_FLOAT_API +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + VARDECL(opus_int16, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, opus_int16); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = (1.f/32768.f)*(out[i]); + } + RESTORE_STACK; + return ret; +} +#endif + + +#else +int opus_decode(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec) +{ + VARDECL(float, out); + int ret, i; + int nb_samples; + ALLOC_STACK; + + if(frame_size<=0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + if (data != NULL && len > 0 && !decode_fec) + { + nb_samples = opus_decoder_get_nb_samples(st, data, len); + if (nb_samples>0) + frame_size = IMIN(frame_size, nb_samples); + else + return OPUS_INVALID_PACKET; + } + celt_assert(st->channels == 1 || st->channels == 2); + ALLOC(out, frame_size*st->channels, float); + + ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1); + if (ret > 0) + { + for (i=0;ichannels;i++) + pcm[i] = FLOAT2INT16(out[i]); + } + RESTORE_STACK; + return ret; +} + +int opus_decode_float(OpusDecoder *st, const unsigned char *data, + opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec) +{ + if(frame_size<=0) + return OPUS_BAD_ARG; + return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0); +} + +#endif + +int opus_decoder_ctl(OpusDecoder *st, int request, ...) +{ + int ret = OPUS_OK; + va_list ap; + void *silk_dec; + CELTDecoder *celt_dec; + + silk_dec = (char*)st+st->silk_dec_offset; + celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); + + + va_start(ap, request); + + switch (request) + { + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_RESET_STATE: + { + OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START, + sizeof(OpusDecoder)- + ((char*)&st->OPUS_DECODER_RESET_START - (char*)st)); + + celt_decoder_ctl(celt_dec, OPUS_RESET_STATE); + silk_InitDecoder( silk_dec ); + st->stream_channels = st->channels; + st->frame_size = st->Fs/400; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_PITCH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->prev_mode == MODE_CELT_ONLY) + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value)); + else + *value = st->DecControl.prevPitchLag; + } + break; + case OPUS_GET_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->decode_gain; + } + break; + case OPUS_SET_GAIN_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-32768 || value>32767) + { + goto bad_arg; + } + st->decode_gain = value; + } + break; + case OPUS_GET_LAST_PACKET_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->last_packet_duration; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + ret = celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + default: + /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_decoder_destroy(OpusDecoder *st) +{ + opus_free(st); +} + + +int opus_packet_get_bandwidth(const unsigned char *data) +{ + int bandwidth; + if (data[0]&0x80) + { + bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3); + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if ((data[0]&0x60) == 0x60) + { + bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND : + OPUS_BANDWIDTH_SUPERWIDEBAND; + } else { + bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3); + } + return bandwidth; +} + +int opus_packet_get_nb_channels(const unsigned char *data) +{ + return (data[0]&0x4) ? 2 : 1; +} + +int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) +{ + int count; + if (len<1) + return OPUS_BAD_ARG; + count = packet[0]&0x3; + if (count==0) + return 1; + else if (count!=3) + return 2; + else if (len<2) + return OPUS_INVALID_PACKET; + else + return packet[1]&0x3F; +} + +int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, + opus_int32 Fs) +{ + int samples; + int count = opus_packet_get_nb_frames(packet, len); + + if (count<0) + return count; + + samples = count*opus_packet_get_samples_per_frame(packet, Fs); + /* Can't have more than 120 ms */ + if (samples*25 > Fs*3) + return OPUS_INVALID_PACKET; + else + return samples; +} + +int opus_decoder_get_nb_samples(const OpusDecoder *dec, + const unsigned char packet[], opus_int32 len) +{ + return opus_packet_get_nb_samples(packet, len, dec->Fs); +} diff --git a/src/libopus/opus_defines.h b/src/libopus/opus_defines.h new file mode 100644 index 00000000..d141418b --- /dev/null +++ b/src/libopus/opus_defines.h @@ -0,0 +1,799 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_defines.h + * @brief Opus reference implementation constants + */ + +#ifndef OPUS_DEFINES_H +#define OPUS_DEFINES_H + +#include "opus_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @defgroup opus_errorcodes Error codes + * @{ + */ +/** No error @hideinitializer*/ +#define OPUS_OK 0 +/** One or more invalid/out of range arguments @hideinitializer*/ +#define OPUS_BAD_ARG -1 +/** Not enough bytes allocated in the buffer @hideinitializer*/ +#define OPUS_BUFFER_TOO_SMALL -2 +/** An internal error was detected @hideinitializer*/ +#define OPUS_INTERNAL_ERROR -3 +/** The compressed data passed is corrupted @hideinitializer*/ +#define OPUS_INVALID_PACKET -4 +/** Invalid/unsupported request number @hideinitializer*/ +#define OPUS_UNIMPLEMENTED -5 +/** An encoder or decoder structure is invalid or already freed @hideinitializer*/ +#define OPUS_INVALID_STATE -6 +/** Memory allocation has failed @hideinitializer*/ +#define OPUS_ALLOC_FAIL -7 +/**@}*/ + +/** @cond OPUS_INTERNAL_DOC */ +/**Export control for opus functions */ + +#ifndef OPUS_EXPORT +# if defined(WIN32) +# if defined(OPUS_BUILD) && defined(DLL_EXPORT) +# define OPUS_EXPORT __declspec(dllexport) +# else +# define OPUS_EXPORT +# endif +# elif defined(__GNUC__) && defined(OPUS_BUILD) +# define OPUS_EXPORT __attribute__ ((visibility ("default"))) +# else +# define OPUS_EXPORT +# endif +#endif + +# if !defined(OPUS_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OPUS_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OPUS_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(3,0) +# define OPUS_RESTRICT __restrict__ +# elif (defined(_MSC_VER) && _MSC_VER >= 1400) +# define OPUS_RESTRICT __restrict +# else +# define OPUS_RESTRICT +# endif +#else +# define OPUS_RESTRICT restrict +#endif + +#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) ) +# if OPUS_GNUC_PREREQ(2,7) +# define OPUS_INLINE __inline__ +# elif (defined(_MSC_VER)) +# define OPUS_INLINE __inline +# else +# define OPUS_INLINE +# endif +#else +# define OPUS_INLINE inline +#endif + +/**Warning attributes for opus functions + * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out + * some paranoid null checks. */ +#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__)) +#else +# define OPUS_WARN_UNUSED_RESULT +#endif +#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4) +# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x))) +#else +# define OPUS_ARG_NONNULL(_x) +#endif + +/** These are the actual Encoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +#define OPUS_SET_APPLICATION_REQUEST 4000 +#define OPUS_GET_APPLICATION_REQUEST 4001 +#define OPUS_SET_BITRATE_REQUEST 4002 +#define OPUS_GET_BITRATE_REQUEST 4003 +#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004 +#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005 +#define OPUS_SET_VBR_REQUEST 4006 +#define OPUS_GET_VBR_REQUEST 4007 +#define OPUS_SET_BANDWIDTH_REQUEST 4008 +#define OPUS_GET_BANDWIDTH_REQUEST 4009 +#define OPUS_SET_COMPLEXITY_REQUEST 4010 +#define OPUS_GET_COMPLEXITY_REQUEST 4011 +#define OPUS_SET_INBAND_FEC_REQUEST 4012 +#define OPUS_GET_INBAND_FEC_REQUEST 4013 +#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014 +#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015 +#define OPUS_SET_DTX_REQUEST 4016 +#define OPUS_GET_DTX_REQUEST 4017 +#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020 +#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021 +#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022 +#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023 +#define OPUS_SET_SIGNAL_REQUEST 4024 +#define OPUS_GET_SIGNAL_REQUEST 4025 +#define OPUS_GET_LOOKAHEAD_REQUEST 4027 +/* #define OPUS_RESET_STATE 4028 */ +#define OPUS_GET_SAMPLE_RATE_REQUEST 4029 +#define OPUS_GET_FINAL_RANGE_REQUEST 4031 +#define OPUS_GET_PITCH_REQUEST 4033 +#define OPUS_SET_GAIN_REQUEST 4034 +#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */ +#define OPUS_SET_LSB_DEPTH_REQUEST 4036 +#define OPUS_GET_LSB_DEPTH_REQUEST 4037 +#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039 +#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040 +#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041 +#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042 +#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043 +/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */ +#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046 +#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047 +#define OPUS_GET_IN_DTX_REQUEST 4049 + +/** Defines for the presence of extended APIs. */ +#define OPUS_HAVE_OPUS_PROJECTION_H + +/* Macros to trigger compilation errors when the wrong types are provided to a CTL */ +#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x)) +#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr))) +#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr))) +#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr))) +/** @endcond */ + +/** @defgroup opus_ctlvalues Pre-defined values for CTL interface + * @see opus_genericctls, opus_encoderctls + * @{ + */ +/* Values for the various encoder CTLs */ +#define OPUS_AUTO -1000 /**opus_int32: Allowed values: 0-10, inclusive. + * + * @hideinitializer */ +#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x) +/** Gets the encoder's complexity configuration. + * @see OPUS_SET_COMPLEXITY + * @param[out] x opus_int32 *: Returns a value in the range 0-10, + * inclusive. + * @hideinitializer */ +#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x) + +/** Configures the bitrate in the encoder. + * Rates from 500 to 512000 bits per second are meaningful, as well as the + * special values #OPUS_AUTO and #OPUS_BITRATE_MAX. + * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much + * rate as it can, which is useful for controlling the rate by adjusting the + * output buffer size. + * @see OPUS_GET_BITRATE + * @param[in] x opus_int32: Bitrate in bits per second. The default + * is determined based on the number of + * channels and the input sampling rate. + * @hideinitializer */ +#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x) +/** Gets the encoder's bitrate configuration. + * @see OPUS_SET_BITRATE + * @param[out] x opus_int32 *: Returns the bitrate in bits per second. + * The default is determined based on the + * number of channels and the input + * sampling rate. + * @hideinitializer */ +#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables variable bitrate (VBR) in the encoder. + * The configured bitrate may not be met exactly because frames must + * be an integer number of bytes in length. + * @see OPUS_GET_VBR + * @see OPUS_SET_VBR_CONSTRAINT + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Hard CBR. For LPC/hybrid modes at very low bit-rate, this can + * cause noticeable quality degradation.
    + *
    1
    VBR (default). The exact type of VBR is controlled by + * #OPUS_SET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x) +/** Determine if variable bitrate (VBR) is enabled in the encoder. + * @see OPUS_SET_VBR + * @see OPUS_GET_VBR_CONSTRAINT + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Hard CBR.
    + *
    1
    VBR (default). The exact type of VBR may be retrieved via + * #OPUS_GET_VBR_CONSTRAINT.
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x) + +/** Enables or disables constrained VBR in the encoder. + * This setting is ignored when the encoder is in CBR mode. + * @warning Only the MDCT mode of Opus currently heeds the constraint. + * Speech mode ignores it completely, hybrid mode may fail to obey it + * if the LPC layer uses more bitrate than the constraint would have + * permitted. + * @see OPUS_GET_VBR_CONSTRAINT + * @see OPUS_SET_VBR + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default). This creates a maximum of one + * frame of buffering delay assuming a transport with a + * serialization speed of the nominal bitrate.
    + *
    + * @hideinitializer */ +#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x) +/** Determine if constrained VBR is enabled in the encoder. + * @see OPUS_SET_VBR_CONSTRAINT + * @see OPUS_GET_VBR + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Unconstrained VBR.
    + *
    1
    Constrained VBR (default).
    + *
    + * @hideinitializer */ +#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x) + +/** Configures mono/stereo forcing in the encoder. + * This can force the encoder to produce packets encoded as either mono or + * stereo, regardless of the format of the input audio. This is useful when + * the caller knows that the input signal is currently a mono source embedded + * in a stereo stream. + * @see OPUS_GET_FORCE_CHANNELS + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x) +/** Gets the encoder's forced channel configuration. + * @see OPUS_SET_FORCE_CHANNELS + * @param[out] x opus_int32 *: + *
    + *
    #OPUS_AUTO
    Not forced (default)
    + *
    1
    Forced mono
    + *
    2
    Forced stereo
    + *
    + * @hideinitializer */ +#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x) + +/** Configures the maximum bandpass that the encoder will select automatically. + * Applications should normally use this instead of #OPUS_SET_BANDWIDTH + * (leaving that set to the default, #OPUS_AUTO). This allows the + * application to set an upper bound based on the type of input it is + * providing, but still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_MAX_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Gets the encoder's configured maximum allowed bandpass. + * @see OPUS_SET_MAX_BANDWIDTH + * @param[out] x opus_int32 *: Allowed values: + *
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband (default)
    + *
    + * @hideinitializer */ +#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Sets the encoder's bandpass to a specific value. + * This prevents the encoder from automatically selecting the bandpass based + * on the available bitrate. If an application knows the bandpass of the input + * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH + * instead, which still gives the encoder the freedom to reduce the bandpass + * when the bitrate becomes too low, for better overall quality. + * @see OPUS_GET_BANDWIDTH + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x) + +/** Configures the type of signal being encoded. + * This is a hint which helps the encoder's mode selection. + * @see OPUS_GET_SIGNAL + * @param[in] x opus_int32: Allowed values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal type. + * @see OPUS_SET_SIGNAL + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_SIGNAL_VOICE
    Bias thresholds towards choosing LPC or Hybrid modes.
    + *
    #OPUS_SIGNAL_MUSIC
    Bias thresholds towards choosing MDCT modes.
    + *
    + * @hideinitializer */ +#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x) + + +/** Configures the encoder's intended application. + * The initial value is a mandatory argument to the encoder_create function. + * @see OPUS_GET_APPLICATION + * @param[in] x opus_int32: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured application. + * @see OPUS_SET_APPLICATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @hideinitializer */ +#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the total samples of delay added by the entire codec. + * This can be queried by the encoder and then the provided number of samples can be + * skipped on from the start of the decoder's output to provide time aligned input + * and output. From the perspective of a decoding application the real data begins this many + * samples late. + * + * The decoder contribution to this delay is identical for all decoders, but the + * encoder portion of the delay may vary from implementation to implementation, + * version to version, or even depend on the encoder's initial configuration. + * Applications needing delay compensation should call this CTL rather than + * hard-coding a value. + * @param[out] x opus_int32 *: Number of lookahead samples + * @hideinitializer */ +#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of inband forward error correction (FEC). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_INBAND_FEC + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable inband FEC (default).
    + *
    1
    Enable inband FEC.
    + *
    + * @hideinitializer */ +#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of inband forward error correction. + * @see OPUS_SET_INBAND_FEC + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Inband FEC disabled (default).
    + *
    1
    Inband FEC enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's expected packet loss percentage. + * Higher values trigger progressively more loss resistant behavior in the encoder + * at the expense of quality at a given bitrate in the absence of packet loss, but + * greater quality under loss. + * @see OPUS_GET_PACKET_LOSS_PERC + * @param[in] x opus_int32: Loss percentage in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured packet loss percentage. + * @see OPUS_SET_PACKET_LOSS_PERC + * @param[out] x opus_int32 *: Returns the configured loss percentage + * in the range 0-100, inclusive (default: 0). + * @hideinitializer */ +#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of discontinuous transmission (DTX). + * @note This is only applicable to the LPC layer + * @see OPUS_GET_DTX + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Disable DTX (default).
    + *
    1
    Enabled DTX.
    + *
    + * @hideinitializer */ +#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x) +/** Gets encoder's configured use of discontinuous transmission. + * @see OPUS_SET_DTX + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    DTX disabled (default).
    + *
    1
    DTX enabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x) +/** Configures the depth of signal being encoded. + * + * This is a hint which helps the encoder identify silence and near-silence. + * It represents the number of significant bits of linear intensity below + * which the signal contains ignorable quantization or other noise. + * + * For example, OPUS_SET_LSB_DEPTH(14) would be an appropriate setting + * for G.711 u-law input. OPUS_SET_LSB_DEPTH(16) would be appropriate + * for 16-bit linear pcm input with opus_encode_float(). + * + * When using opus_encode() instead of opus_encode_float(), or when libopus + * is compiled for fixed-point, the encoder uses the minimum of the value + * set here and the value 16. + * + * @see OPUS_GET_LSB_DEPTH + * @param[in] x opus_int32: Input precision in bits, between 8 and 24 + * (default: 24). + * @hideinitializer */ +#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured signal depth. + * @see OPUS_SET_LSB_DEPTH + * @param[out] x opus_int32 *: Input precision in bits, between 8 and + * 24 (default: 24). + * @hideinitializer */ +#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x) + +/** Configures the encoder's use of variable duration frames. + * When variable duration is enabled, the encoder is free to use a shorter frame + * size than the one requested in the opus_encode*() call. + * It is then the user's responsibility + * to verify how much audio was encoded by checking the ToC byte of the encoded + * packet. The part of the audio that was not encoded needs to be resent to the + * encoder for the next call. Do not use this option unless you really + * know what you are doing. + * @see OPUS_GET_EXPERT_FRAME_DURATION + * @param[in] x opus_int32: Allowed values: + *
    + *
    OPUS_FRAMESIZE_ARG
    Select frame size from the argument (default).
    + *
    OPUS_FRAMESIZE_2_5_MS
    Use 2.5 ms frames.
    + *
    OPUS_FRAMESIZE_5_MS
    Use 5 ms frames.
    + *
    OPUS_FRAMESIZE_10_MS
    Use 10 ms frames.
    + *
    OPUS_FRAMESIZE_20_MS
    Use 20 ms frames.
    + *
    OPUS_FRAMESIZE_40_MS
    Use 40 ms frames.
    + *
    OPUS_FRAMESIZE_60_MS
    Use 60 ms frames.
    + *
    OPUS_FRAMESIZE_80_MS
    Use 80 ms frames.
    + *
    OPUS_FRAMESIZE_100_MS
    Use 100 ms frames.
    + *
    OPUS_FRAMESIZE_120_MS
    Use 120 ms frames.
    + *
    + * @hideinitializer */ +#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured use of variable duration frames. + * @see OPUS_SET_EXPERT_FRAME_DURATION + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    OPUS_FRAMESIZE_ARG
    Select frame size from the argument (default).
    + *
    OPUS_FRAMESIZE_2_5_MS
    Use 2.5 ms frames.
    + *
    OPUS_FRAMESIZE_5_MS
    Use 5 ms frames.
    + *
    OPUS_FRAMESIZE_10_MS
    Use 10 ms frames.
    + *
    OPUS_FRAMESIZE_20_MS
    Use 20 ms frames.
    + *
    OPUS_FRAMESIZE_40_MS
    Use 40 ms frames.
    + *
    OPUS_FRAMESIZE_60_MS
    Use 60 ms frames.
    + *
    OPUS_FRAMESIZE_80_MS
    Use 80 ms frames.
    + *
    OPUS_FRAMESIZE_100_MS
    Use 100 ms frames.
    + *
    OPUS_FRAMESIZE_120_MS
    Use 120 ms frames.
    + *
    + * @hideinitializer */ +#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables almost all use of prediction, making frames almost + * completely independent. This reduces quality. + * @see OPUS_GET_PREDICTION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Enable prediction (default).
    + *
    1
    Disable prediction.
    + *
    + * @hideinitializer */ +#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured prediction status. + * @see OPUS_SET_PREDICTION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Prediction enabled (default).
    + *
    1
    Prediction disabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_genericctls Generic CTLs + * + * These macros are used with the \c opus_decoder_ctl and + * \c opus_encoder_ctl calls to generate a particular + * request. + * + * When called on an \c OpusDecoder they apply to that + * particular decoder instance. When called on an + * \c OpusEncoder they apply to the corresponding setting + * on that encoder instance, if present. + * + * Some usage examples: + * + * @code + * int ret; + * opus_int32 pitch; + * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch)); + * if (ret == OPUS_OK) return ret; + * + * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE); + * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE); + * + * opus_int32 enc_bw, dec_bw; + * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw)); + * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw)); + * if (enc_bw != dec_bw) { + * printf("packet bandwidth mismatch!\n"); + * } + * @endcode + * + * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls + * @{ + */ + +/** Resets the codec state to be equivalent to a freshly initialized state. + * This should be called when switching streams in order to prevent + * the back to back decoding from giving different results from + * one at a time decoding. + * @hideinitializer */ +#define OPUS_RESET_STATE 4028 + +/** Gets the final state of the codec's entropy coder. + * This is used for testing purposes, + * The encoder and decoder state should be identical after coding a payload + * (assuming no data corruption or software bugs) + * + * @param[out] x opus_uint32 *: Entropy coder state + * + * @hideinitializer */ +#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x) + +/** Gets the encoder's configured bandpass or the decoder's last bandpass. + * @see OPUS_SET_BANDWIDTH + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    #OPUS_AUTO
    (default)
    + *
    #OPUS_BANDWIDTH_NARROWBAND
    4 kHz passband
    + *
    #OPUS_BANDWIDTH_MEDIUMBAND
    6 kHz passband
    + *
    #OPUS_BANDWIDTH_WIDEBAND
    8 kHz passband
    + *
    #OPUS_BANDWIDTH_SUPERWIDEBAND
    12 kHz passband
    + *
    #OPUS_BANDWIDTH_FULLBAND
    20 kHz passband
    + *
    + * @hideinitializer */ +#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x) + +/** Gets the sampling rate the encoder or decoder was initialized with. + * This simply returns the Fs value passed to opus_encoder_init() + * or opus_decoder_init(). + * @param[out] x opus_int32 *: Sampling rate of encoder or decoder. + * @hideinitializer + */ +#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x) + +/** If set to 1, disables the use of phase inversion for intensity stereo, + * improving the quality of mono downmixes, but slightly reducing normal + * stereo quality. Disabling phase inversion in the decoder does not comply + * with RFC 6716, although it does not cause any interoperability issue and + * is expected to become part of the Opus standard once RFC 6716 is updated + * by draft-ietf-codec-opus-update. + * @see OPUS_GET_PHASE_INVERSION_DISABLED + * @param[in] x opus_int32: Allowed values: + *
    + *
    0
    Enable phase inversion (default).
    + *
    1
    Disable phase inversion.
    + *
    + * @hideinitializer */ +#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured phase inversion status. + * @see OPUS_SET_PHASE_INVERSION_DISABLED + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    Stereo phase inversion enabled (default).
    + *
    1
    Stereo phase inversion disabled.
    + *
    + * @hideinitializer */ +#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x) +/** Gets the DTX state of the encoder. + * Returns whether the last encoded frame was either a comfort noise update + * during DTX or not encoded because of DTX. + * @param[out] x opus_int32 *: Returns one of the following values: + *
    + *
    0
    The encoder is not in DTX.
    + *
    1
    The encoder is in DTX.
    + *
    + * @hideinitializer */ +#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_decoderctls Decoder related CTLs + * @see opus_genericctls, opus_encoderctls, opus_decoder + * @{ + */ + +/** Configures decoder gain adjustment. + * Scales the decoded output by a factor specified in Q8 dB units. + * This has a maximum range of -32768 to 32767 inclusive, and returns + * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment. + * This setting survives decoder reset. + * + * gain = pow(10, x/(20.0*256)) + * + * @param[in] x opus_int32: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x) +/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN + * + * @param[out] x opus_int32 *: Amount to scale PCM signal by in Q8 dB units. + * @hideinitializer */ +#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x) + +/** Gets the duration (in samples) of the last packet successfully decoded or concealed. + * @param[out] x opus_int32 *: Number of samples (at current sampling rate). + * @hideinitializer */ +#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x) + +/** Gets the pitch of the last decoded frame, if available. + * This can be used for any post-processing algorithm requiring the use of pitch, + * e.g. time stretching/shortening. If the last frame was not voiced, or if the + * pitch was not coded in the frame, then zero is returned. + * + * This CTL is only implemented for decoder instances. + * + * @param[out] x opus_int32 *: pitch period at 48 kHz (or 0 if not available) + * + * @hideinitializer */ +#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x) + +/**@}*/ + +/** @defgroup opus_libinfo Opus library information functions + * @{ + */ + +/** Converts an opus error code into a human readable string. + * + * @param[in] error int: Error number + * @returns Error string + */ +OPUS_EXPORT const char *opus_strerror(int error); + +/** Gets the libopus version string. + * + * Applications may look for the substring "-fixed" in the version string to + * determine whether they have a fixed-point or floating-point build at + * runtime. + * + * @returns Version string + */ +OPUS_EXPORT const char *opus_get_version_string(void); +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_DEFINES_H */ diff --git a/src/libopus/opus_encoder.c b/src/libopus/opus_encoder.c new file mode 100644 index 00000000..fda4fd15 --- /dev/null +++ b/src/libopus/opus_encoder.c @@ -0,0 +1,2783 @@ +/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited + Written by Jean-Marc Valin and Koen Vos */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include +#include "celt/celt.h" +#include "celt/entenc.h" +#include "celt/modes.h" +#include "silk/API.h" +#include "celt/stack_alloc.h" +#include "celt/float_cast.h" +#include "opus.h" +#include "celt/arch.h" +#include "celt/pitch.h" +#include "opus_private.h" +#include "celt/os_support.h" +#include "celt/cpu_support.h" +#include "analysis.h" +#include "celt/mathops.h" +#include "silk/tuning_parameters.h" +#ifdef FIXED_POINT +#include "silk/fixed/structs_FIX.h" +#else +#include "silk/float/structs_FLP.h" +#endif + +#define MAX_ENCODER_BUFFER 480 + +#ifndef DISABLE_FLOAT_API +#define PSEUDO_SNR_THRESHOLD 316.23f /* 10^(25/10) */ +#endif + +typedef struct { + opus_val32 XX, XY, YY; + opus_val16 smoothed_width; + opus_val16 max_follower; +} StereoWidthState; + +struct OpusEncoder { + int celt_enc_offset; + int silk_enc_offset; + silk_EncControlStruct silk_mode; + int application; + int channels; + int delay_compensation; + int force_channels; + int signal_type; + int user_bandwidth; + int max_bandwidth; + int user_forced_mode; + int voice_ratio; + opus_int32 Fs; + int use_vbr; + int vbr_constraint; + int variable_duration; + opus_int32 bitrate_bps; + opus_int32 user_bitrate_bps; + int lsb_depth; + int encoder_buffer; + int lfe; + int arch; + int use_dtx; /* general DTX for both SILK and CELT */ +#ifndef DISABLE_FLOAT_API + TonalityAnalysisState analysis; +#endif + +#define OPUS_ENCODER_RESET_START stream_channels + int stream_channels; + opus_int16 hybrid_stereo_width_Q14; + opus_int32 variable_HP_smth2_Q15; + opus_val16 prev_HB_gain; + opus_val32 hp_mem[4]; + int mode; + int prev_mode; + int prev_channels; + int prev_framesize; + int bandwidth; + /* Bandwidth determined automatically from the rate (before any other adjustment) */ + int auto_bandwidth; + int silk_bw_switch; + /* Sampling rate (at the API level) */ + int first; + opus_val16 * energy_masking; + StereoWidthState width_mem; + opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2]; +#ifndef DISABLE_FLOAT_API + int detected_bandwidth; + int nb_no_activity_frames; + opus_val32 peak_signal_energy; +#endif + int nonfinal_frame; /* current frame is not the final in a packet */ + opus_uint32 rangeFinal; +}; + +/* Transition tables for the voice and music. First column is the + middle (memoriless) threshold. The second column is the hysteresis + (difference with the middle) */ +static const opus_int32 mono_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 mono_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_voice_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 13500, 1000, /* WB<->SWB */ + 14000, 2000, /* SWB<->FB */ +}; +static const opus_int32 stereo_music_bandwidth_thresholds[8] = { + 9000, 700, /* NB<->MB */ + 9000, 700, /* MB<->WB */ + 11000, 1000, /* WB<->SWB */ + 12000, 2000, /* SWB<->FB */ +}; +/* Threshold bit-rates for switching between mono and stereo */ +static const opus_int32 stereo_voice_threshold = 19000; +static const opus_int32 stereo_music_threshold = 17000; + +/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */ +static const opus_int32 mode_thresholds[2][2] = { + /* voice */ /* music */ + { 64000, 10000}, /* mono */ + { 44000, 10000}, /* stereo */ +}; + +static const opus_int32 fec_thresholds[] = { + 12000, 1000, /* NB */ + 14000, 1000, /* MB */ + 16000, 1000, /* WB */ + 20000, 1000, /* SWB */ + 22000, 1000, /* FB */ +}; + +int opus_encoder_get_size(int channels) +{ + int silkEncSizeBytes, celtEncSizeBytes; + int ret; + if (channels<1 || channels > 2) + return 0; + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return 0; + silkEncSizeBytes = align(silkEncSizeBytes); + celtEncSizeBytes = celt_encoder_get_size(channels); + return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes; +} + +int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int err; + int ret, silkEncSizeBytes; + + if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)|| + (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO + && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)) + return OPUS_BAD_ARG; + + OPUS_CLEAR((char*)st, opus_encoder_get_size(channels)); + /* Create SILK encoder */ + ret = silk_Get_Encoder_Size( &silkEncSizeBytes ); + if (ret) + return OPUS_BAD_ARG; + silkEncSizeBytes = align(silkEncSizeBytes); + st->silk_enc_offset = align(sizeof(OpusEncoder)); + st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes; + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + st->stream_channels = st->channels = channels; + + st->Fs = Fs; + + st->arch = opus_select_arch(); + + ret = silk_InitEncoder( silk_enc, st->arch, &st->silk_mode ); + if(ret)return OPUS_INTERNAL_ERROR; + + /* default SILK parameters */ + st->silk_mode.nChannelsAPI = channels; + st->silk_mode.nChannelsInternal = channels; + st->silk_mode.API_sampleRate = st->Fs; + st->silk_mode.maxInternalSampleRate = 16000; + st->silk_mode.minInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = 16000; + st->silk_mode.payloadSize_ms = 20; + st->silk_mode.bitRate = 25000; + st->silk_mode.packetLossPercentage = 0; + st->silk_mode.complexity = 9; + st->silk_mode.useInBandFEC = 0; + st->silk_mode.useDTX = 0; + st->silk_mode.useCBR = 0; + st->silk_mode.reducedDependency = 0; + + /* Create CELT encoder */ + /* Initialize CELT encoder */ + err = celt_encoder_init(celt_enc, Fs, channels, st->arch); + if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR; + + celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity)); + + st->use_vbr = 1; + /* Makes constrained VBR the default (safer for real-time use) */ + st->vbr_constraint = 1; + st->user_bitrate_bps = OPUS_AUTO; + st->bitrate_bps = 3000+Fs*channels; + st->application = application; + st->signal_type = OPUS_AUTO; + st->user_bandwidth = OPUS_AUTO; + st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->force_channels = OPUS_AUTO; + st->user_forced_mode = OPUS_AUTO; + st->voice_ratio = -1; + st->encoder_buffer = st->Fs/100; + st->lsb_depth = 24; + st->variable_duration = OPUS_FRAMESIZE_ARG; + + /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead + + 1.5 ms for SILK resamplers and stereo prediction) */ + st->delay_compensation = st->Fs/250; + + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + +#ifndef DISABLE_FLOAT_API + tonality_analysis_init(&st->analysis, st->Fs); + st->analysis.application = st->application; +#endif + + return OPUS_OK; +} + +static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels) +{ + int period; + unsigned char toc; + period = 0; + while (framerate < 400) + { + framerate <<= 1; + period++; + } + if (mode == MODE_SILK_ONLY) + { + toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5; + toc |= (period-2)<<3; + } else if (mode == MODE_CELT_ONLY) + { + int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND; + if (tmp < 0) + tmp = 0; + toc = 0x80; + toc |= tmp << 5; + toc |= period<<3; + } else /* Hybrid */ + { + toc = 0x60; + toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4; + toc |= (period-2)<<3; + } + toc |= (channels==2)<<2; + return toc; +} + +#ifndef FIXED_POINT +static void silk_biquad_float( + const opus_val16 *in, /* I: Input signal */ + const opus_int32 *B_Q28, /* I: MA coefficients [3] */ + const opus_int32 *A_Q28, /* I: AR coefficients [2] */ + opus_val32 *S, /* I/O: State vector [2] */ + opus_val16 *out, /* O: Output signal */ + const opus_int32 len, /* I: Signal length (must be even) */ + int stride +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_val32 vout; + opus_val32 inval; + opus_val32 A[2], B[3]; + + A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28))); + A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28))); + B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28))); + B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28))); + B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28))); + + /* Negate A_Q28 values and split in two parts */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k*stride ]; + vout = S[ 0 ] + B[0]*inval; + + S[ 0 ] = S[1] - vout*A[0] + B[1]*inval; + + S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL; + + /* Scale back to Q0 and saturate */ + out[ k*stride ] = vout; + } +} +#endif + +static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs, int arch) +{ + opus_int32 B_Q28[ 3 ], A_Q28[ 2 ]; + opus_int32 Fc_Q19, r_Q28, r_Q22; + (void)arch; + + silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) ); + Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 ); + silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 ); + + r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 ); + + /* b = r * [ 1; -2; 1 ]; */ + /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */ + B_Q28[ 0 ] = r_Q28; + B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 ); + B_Q28[ 2 ] = r_Q28; + + /* -r * ( 2 - Fc * Fc ); */ + r_Q22 = silk_RSHIFT( r_Q28, 6 ); + A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) ); + A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 ); + +#ifdef FIXED_POINT + if( channels == 1 ) { + silk_biquad_alt_stride1( in, B_Q28, A_Q28, hp_mem, out, len ); + } else { + silk_biquad_alt_stride2( in, B_Q28, A_Q28, hp_mem, out, len, arch ); + } +#else + silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels ); + if( channels == 2 ) { + silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels ); + } +#endif +} + +#ifdef FIXED_POINT +static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs) +{ + int c, i; + int shift; + + /* Approximates -round(log2(6.3*cutoff_Hz/Fs)) */ + shift=celt_ilog2(Fs/(cutoff_Hz*4)); + for (c=0;cFs/400; + if (st->user_bitrate_bps==OPUS_AUTO) + return 60*st->Fs/frame_size + st->Fs*st->channels; + else if (st->user_bitrate_bps==OPUS_BITRATE_MAX) + return max_data_bytes*8*st->Fs/frame_size; + else + return st->user_bitrate_bps; +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +#define PCM2VAL(x) FLOAT2INT16(x) +#else +#define PCM2VAL(x) SCALEIN(x) +#endif + +void downmix_float(const void *_x, opus_val32 *y, int subframe, int offset, int c1, int c2, int C) +{ + const float *x; + int j; + + x = (const float *)_x; + for (j=0;j-1) + { + for (j=0;j-1) + { + for (j=0;j= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_120_MS) + { + if (variable_duration <= OPUS_FRAMESIZE_40_MS) + new_size = (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS); + else + new_size = (variable_duration-OPUS_FRAMESIZE_2_5_MS-2)*Fs/50; + } + else + return -1; + if (new_size>frame_size) + return -1; + if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs && + 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs && + 50*new_size!=4*Fs && 50*new_size!=5*Fs && 50*new_size!=6*Fs) + return -1; + return new_size; +} + +opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem) +{ + opus_val32 xx, xy, yy; + opus_val16 sqrt_xx, sqrt_yy; + opus_val16 qrrt_xx, qrrt_yy; + int frame_rate; + int i; + opus_val16 short_alpha; + + frame_rate = Fs/frame_size; + short_alpha = Q15ONE - MULT16_16(25, Q15ONE)/IMAX(50,frame_rate); + xx=xy=yy=0; + /* Unroll by 4. The frame size is always a multiple of 4 *except* for + 2.5 ms frames at 12 kHz. Since this setting is very rare (and very + stupid), we just discard the last two samples. */ + for (i=0;iXX += MULT16_32_Q15(short_alpha, xx-mem->XX); + mem->XY += MULT16_32_Q15(short_alpha, xy-mem->XY); + mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY); + mem->XX = MAX32(0, mem->XX); + mem->XY = MAX32(0, mem->XY); + mem->YY = MAX32(0, mem->YY); + if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18)) + { + opus_val16 corr; + opus_val16 ldiff; + opus_val16 width; + sqrt_xx = celt_sqrt(mem->XX); + sqrt_yy = celt_sqrt(mem->YY); + qrrt_xx = celt_sqrt(sqrt_xx); + qrrt_yy = celt_sqrt(sqrt_yy); + /* Inter-channel correlation */ + mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy); + corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16); + /* Approximate loudness difference */ + ldiff = MULT16_16(Q15ONE, ABS16(qrrt_xx-qrrt_yy))/(EPSILON+qrrt_xx+qrrt_yy); + width = MULT16_16_Q15(celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr)), ldiff); + /* Smoothing over one second */ + mem->smoothed_width += (width-mem->smoothed_width)/frame_rate; + /* Peak follower */ + mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width); + } + /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/ + return EXTRACT16(MIN32(Q15ONE, MULT16_16(20, mem->max_follower))); +} + +static int decide_fec(int useInBandFEC, int PacketLoss_perc, int last_fec, int mode, int *bandwidth, opus_int32 rate) +{ + int orig_bandwidth; + if (!useInBandFEC || PacketLoss_perc == 0 || mode == MODE_CELT_ONLY) + return 0; + orig_bandwidth = *bandwidth; + for (;;) + { + opus_int32 hysteresis; + opus_int32 LBRR_rate_thres_bps; + /* Compute threshold for using FEC at the current bandwidth setting */ + LBRR_rate_thres_bps = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND)]; + hysteresis = fec_thresholds[2*(*bandwidth - OPUS_BANDWIDTH_NARROWBAND) + 1]; + if (last_fec == 1) LBRR_rate_thres_bps -= hysteresis; + if (last_fec == 0) LBRR_rate_thres_bps += hysteresis; + LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, + 125 - silk_min( PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) ); + /* If loss <= 5%, we look at whether we have enough rate to enable FEC. + If loss > 5%, we decrease the bandwidth until we can enable FEC. */ + if (rate > LBRR_rate_thres_bps) + return 1; + else if (PacketLoss_perc <= 5) + return 0; + else if (*bandwidth > OPUS_BANDWIDTH_NARROWBAND) + (*bandwidth)--; + else + break; + } + /* Couldn't find any bandwidth to enable FEC, keep original bandwidth. */ + *bandwidth = orig_bandwidth; + return 0; +} + +static int compute_silk_rate_for_hybrid(int rate, int bandwidth, int frame20ms, int vbr, int fec, int channels) { + int entry; + int i; + int N; + int silk_rate; + static int rate_table[][5] = { + /* |total| |-------- SILK------------| + |-- No FEC -| |--- FEC ---| + 10ms 20ms 10ms 20ms */ + { 0, 0, 0, 0, 0}, + {12000, 10000, 10000, 11000, 11000}, + {16000, 13500, 13500, 15000, 15000}, + {20000, 16000, 16000, 18000, 18000}, + {24000, 18000, 18000, 21000, 21000}, + {32000, 22000, 22000, 28000, 28000}, + {64000, 38000, 38000, 50000, 50000} + }; + /* Do the allocation per-channel. */ + rate /= channels; + entry = 1 + frame20ms + 2*fec; + N = sizeof(rate_table)/sizeof(rate_table[0]); + for (i=1;i rate) break; + } + if (i == N) + { + silk_rate = rate_table[i-1][entry]; + /* For now, just give 50% of the extra bits to SILK. */ + silk_rate += (rate-rate_table[i-1][0])/2; + } else { + opus_int32 lo, hi, x0, x1; + lo = rate_table[i-1][entry]; + hi = rate_table[i][entry]; + x0 = rate_table[i-1][0]; + x1 = rate_table[i][0]; + silk_rate = (lo*(x1-rate) + hi*(rate-x0))/(x1-x0); + } + if (!vbr) + { + /* Tiny boost to SILK for CBR. We should probably tune this better. */ + silk_rate += 100; + } + if (bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND) + silk_rate += 300; + silk_rate *= channels; + /* Small adjustment for stereo (calibrated for 32 kb/s, haven't tried other bitrates). */ + if (channels == 2 && rate >= 12000) + silk_rate -= 1000; + return silk_rate; +} + +/* Returns the equivalent bitrate corresponding to 20 ms frames, + complexity 10 VBR operation. */ +static opus_int32 compute_equiv_rate(opus_int32 bitrate, int channels, + int frame_rate, int vbr, int mode, int complexity, int loss) +{ + opus_int32 equiv; + equiv = bitrate; + /* Take into account overhead from smaller frames. */ + if (frame_rate > 50) + equiv -= (40*channels+20)*(frame_rate - 50); + /* CBR is about a 8% penalty for both SILK and CELT. */ + if (!vbr) + equiv -= equiv/12; + /* Complexity makes about 10% difference (from 0 to 10) in general. */ + equiv = equiv * (90+complexity)/100; + if (mode == MODE_SILK_ONLY || mode == MODE_HYBRID) + { + /* SILK complexity 0-1 uses the non-delayed-decision NSQ, which + costs about 20%. */ + if (complexity<2) + equiv = equiv*4/5; + equiv -= equiv*loss/(6*loss + 10); + } else if (mode == MODE_CELT_ONLY) { + /* CELT complexity 0-4 doesn't have the pitch filter, which costs + about 10%. */ + if (complexity<5) + equiv = equiv*9/10; + } else { + /* Mode not known yet */ + /* Half the SILK loss*/ + equiv -= equiv*loss/(12*loss + 20); + } + return equiv; +} + +#ifndef DISABLE_FLOAT_API + +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth) +{ + int silence = 0; + opus_val32 sample_max = 0; +#ifdef MLP_TRAINING + return 0; +#endif + sample_max = celt_maxabs16(pcm, frame_size*channels); + +#ifdef FIXED_POINT + silence = (sample_max == 0); + (void)lsb_depth; +#else + silence = (sample_max <= (opus_val16) 1 / (1 << lsb_depth)); +#endif + + return silence; +} + +#ifdef FIXED_POINT +static opus_val32 compute_frame_energy(const opus_val16 *pcm, int frame_size, int channels, int arch) +{ + int i; + opus_val32 sample_max; + int max_shift; + int shift; + opus_val32 energy = 0; + int len = frame_size*channels; + (void)arch; + /* Max amplitude in the signal */ + sample_max = celt_maxabs16(pcm, len); + + /* Compute the right shift required in the MAC to avoid an overflow */ + max_shift = celt_ilog2(len); + shift = IMAX(0, (celt_ilog2(sample_max) << 1) + max_shift - 28); + + /* Compute the energy */ + for (i=0; i= (PSEUDO_SNR_THRESHOLD * noise_energy); + } + } + + if (is_silence) + { + /* The number of consecutive DTX frames should be within the allowed bounds */ + (*nb_no_activity_frames)++; + + if (*nb_no_activity_frames > NB_SPEECH_FRAMES_BEFORE_DTX) + { + if (*nb_no_activity_frames <= (NB_SPEECH_FRAMES_BEFORE_DTX + MAX_CONSECUTIVE_DTX)) + /* Valid frame for DTX! */ + return 1; + else + (*nb_no_activity_frames) = NB_SPEECH_FRAMES_BEFORE_DTX; + } + } else + (*nb_no_activity_frames) = 0; + + return 0; +} + +#endif + +static opus_int32 encode_multiframe_packet(OpusEncoder *st, + const opus_val16 *pcm, + int nb_frames, + int frame_size, + unsigned char *data, + opus_int32 out_data_bytes, + int to_celt, + int lsb_depth, + int float_api) +{ + int i; + int ret = 0; + VARDECL(unsigned char, tmp_data); + int bak_mode, bak_bandwidth, bak_channels, bak_to_mono; + VARDECL(OpusRepacketizer, rp); + int max_header_bytes; + opus_int32 bytes_per_frame; + opus_int32 cbr_bytes; + opus_int32 repacketize_len; + int tmp_len; + ALLOC_STACK; + + /* Worst cases: + * 2 frames: Code 2 with different compressed sizes + * >2 frames: Code 3 VBR */ + max_header_bytes = nb_frames == 2 ? 3 : (2+(nb_frames-1)*2); + + if (st->use_vbr || st->user_bitrate_bps==OPUS_BITRATE_MAX) + repacketize_len = out_data_bytes; + else { + cbr_bytes = 3*st->bitrate_bps/(3*8*st->Fs/(frame_size*nb_frames)); + repacketize_len = IMIN(cbr_bytes, out_data_bytes); + } + bytes_per_frame = IMIN(1276, 1+(repacketize_len-max_header_bytes)/nb_frames); + + ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char); + ALLOC(rp, 1, OpusRepacketizer); + opus_repacketizer_init(rp); + + bak_mode = st->user_forced_mode; + bak_bandwidth = st->user_bandwidth; + bak_channels = st->force_channels; + + st->user_forced_mode = st->mode; + st->user_bandwidth = st->bandwidth; + st->force_channels = st->stream_channels; + + bak_to_mono = st->silk_mode.toMono; + if (bak_to_mono) + st->force_channels = 1; + else + st->prev_channels = st->stream_channels; + + for (i=0;isilk_mode.toMono = 0; + st->nonfinal_frame = i<(nb_frames-1); + + /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */ + if (to_celt && i==nb_frames-1) + st->user_forced_mode = MODE_CELT_ONLY; + + tmp_len = opus_encode_native(st, pcm+i*(st->channels*frame_size), frame_size, + tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth, NULL, 0, 0, 0, 0, + NULL, float_api); + + if (tmp_len<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + } + + ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr); + + if (ret<0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Discard configs that were forced locally for the purpose of repacketization */ + st->user_forced_mode = bak_mode; + st->user_bandwidth = bak_bandwidth; + st->force_channels = bak_channels; + st->silk_mode.toMono = bak_to_mono; + + RESTORE_STACK; + return ret; +} + +static int compute_redundancy_bytes(opus_int32 max_data_bytes, opus_int32 bitrate_bps, int frame_rate, int channels) +{ + int redundancy_bytes_cap; + int redundancy_bytes; + opus_int32 redundancy_rate; + int base_bits; + opus_int32 available_bits; + base_bits = (40*channels+20); + + /* Equivalent rate for 5 ms frames. */ + redundancy_rate = bitrate_bps + base_bits*(200 - frame_rate); + /* For VBR, further increase the bitrate if we can afford it. It's pretty short + and we'll avoid artefacts. */ + redundancy_rate = 3*redundancy_rate/2; + redundancy_bytes = redundancy_rate/1600; + + /* Compute the max rate we can use given CBR or VBR with cap. */ + available_bits = max_data_bytes*8 - 2*base_bits; + redundancy_bytes_cap = (available_bits*240/(240+48000/frame_rate) + base_bits)/8; + redundancy_bytes = IMIN(redundancy_bytes, redundancy_bytes_cap); + /* It we can't get enough bits for redundancy to be worth it, rely on the decoder PLC. */ + if (redundancy_bytes > 4 + 8*channels) + redundancy_bytes = IMIN(257, redundancy_bytes); + else + redundancy_bytes = 0; + return redundancy_bytes; +} + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api) +{ + void *silk_enc; + CELTEncoder *celt_enc; + int i; + int ret=0; + opus_int32 nBytes; + ec_enc enc; + int bytes_target; + int prefill=0; + int start_band = 0; + int redundancy = 0; + int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */ + int celt_to_silk = 0; + VARDECL(opus_val16, pcm_buf); + int nb_compr_bytes; + int to_celt = 0; + opus_uint32 redundant_rng = 0; + int cutoff_Hz, hp_freq_smth1; + int voice_est; /* Probability of voice in Q7 */ + opus_int32 equiv_rate; + int delay_compensation; + int frame_rate; + opus_int32 max_rate; /* Max bitrate we're allowed to use */ + int curr_bandwidth; + opus_val16 HB_gain; + opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */ + int total_buffer; + opus_val16 stereo_width; + const CELTMode *celt_mode; +#ifndef DISABLE_FLOAT_API + AnalysisInfo analysis_info; + int analysis_read_pos_bak=-1; + int analysis_read_subframe_bak=-1; + int is_silence = 0; +#endif + VARDECL(opus_val16, tmp_prefill); + + ALLOC_STACK; + + max_data_bytes = IMIN(1276, out_data_bytes); + + st->rangeFinal = 0; + if (frame_size <= 0 || max_data_bytes <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Cannot encode 100 ms in 1 byte */ + if (max_data_bytes==1 && st->Fs==(frame_size*10)) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + + silk_enc = (char*)st+st->silk_enc_offset; + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + delay_compensation = 0; + else + delay_compensation = st->delay_compensation; + + lsb_depth = IMIN(lsb_depth, st->lsb_depth); + + celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode)); +#ifndef DISABLE_FLOAT_API + analysis_info.valid = 0; +#ifdef FIXED_POINT + if (st->silk_mode.complexity >= 10 && st->Fs>=16000) +#else + if (st->silk_mode.complexity >= 7 && st->Fs>=16000) +#endif + { + is_silence = is_digital_silence(pcm, frame_size, st->channels, lsb_depth); + analysis_read_pos_bak = st->analysis.read_pos; + analysis_read_subframe_bak = st->analysis.read_subframe; + run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size, + c1, c2, analysis_channels, st->Fs, + lsb_depth, downmix, &analysis_info); + + /* Track the peak signal energy */ + if (!is_silence && analysis_info.activity_probability > DTX_ACTIVITY_THRESHOLD) + st->peak_signal_energy = MAX32(MULT16_32_Q15(QCONST16(0.999f, 15), st->peak_signal_energy), + compute_frame_energy(pcm, frame_size, st->channels, st->arch)); + } else if (st->analysis.initialized) { + tonality_analysis_reset(&st->analysis); + } +#else + (void)analysis_pcm; + (void)analysis_size; + (void)c1; + (void)c2; + (void)analysis_channels; + (void)downmix; +#endif + +#ifndef DISABLE_FLOAT_API + /* Reset voice_ratio if this frame is not silent or if analysis is disabled. + * Otherwise, preserve voice_ratio from the last non-silent frame */ + if (!is_silence) + st->voice_ratio = -1; + + st->detected_bandwidth = 0; + if (analysis_info.valid) + { + int analysis_bandwidth; + if (st->signal_type == OPUS_AUTO) + { + float prob; + if (st->prev_mode == 0) + prob = analysis_info.music_prob; + else if (st->prev_mode == MODE_CELT_ONLY) + prob = analysis_info.music_prob_max; + else + prob = analysis_info.music_prob_min; + st->voice_ratio = (int)floor(.5+100*(1-prob)); + } + + analysis_bandwidth = analysis_info.bandwidth; + if (analysis_bandwidth<=12) + st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (analysis_bandwidth<=14) + st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (analysis_bandwidth<=16) + st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (analysis_bandwidth<=18) + st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + } +#else + st->voice_ratio = -1; +#endif + + if (st->channels==2 && st->force_channels!=1) + stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem); + else + stereo_width = 0; + total_buffer = delay_compensation; + st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes); + + frame_rate = st->Fs/frame_size; + if (!st->use_vbr) + { + int cbrBytes; + /* Multiply by 12 to make sure the division is exact. */ + int frame_rate12 = 12*st->Fs/frame_size; + /* We need to make sure that "int" values always fit in 16 bits. */ + cbrBytes = IMIN( (12*st->bitrate_bps/8 + frame_rate12/2)/frame_rate12, max_data_bytes); + st->bitrate_bps = cbrBytes*(opus_int32)frame_rate12*8/12; + /* Make sure we provide at least one byte to avoid failing. */ + max_data_bytes = IMAX(1, cbrBytes); + } + if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8 + || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400))) + { + /*If the space is too low to do something useful, emit 'PLC' frames.*/ + int tocmode = st->mode; + int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth; + int packet_code = 0; + int num_multiframes = 0; + + if (tocmode==0) + tocmode = MODE_SILK_ONLY; + if (frame_rate>100) + tocmode = MODE_CELT_ONLY; + /* 40 ms -> 2 x 20 ms if in CELT_ONLY or HYBRID mode */ + if (frame_rate==25 && tocmode!=MODE_SILK_ONLY) + { + frame_rate = 50; + packet_code = 1; + } + + /* >= 60 ms frames */ + if (frame_rate<=16) + { + /* 1 x 60 ms, 2 x 40 ms, 2 x 60 ms */ + if (out_data_bytes==1 || (tocmode==MODE_SILK_ONLY && frame_rate!=10)) + { + tocmode = MODE_SILK_ONLY; + + packet_code = frame_rate <= 12; + frame_rate = frame_rate == 12 ? 25 : 16; + } + else + { + num_multiframes = 50/frame_rate; + frame_rate = 50; + packet_code = 3; + } + } + + if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND) + bw=OPUS_BANDWIDTH_WIDEBAND; + else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND) + bw=OPUS_BANDWIDTH_NARROWBAND; + else if (tocmode==MODE_HYBRID&&bw<=OPUS_BANDWIDTH_SUPERWIDEBAND) + bw=OPUS_BANDWIDTH_SUPERWIDEBAND; + + data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels); + data[0] |= packet_code; + + ret = packet_code <= 1 ? 1 : 2; + + max_data_bytes = IMAX(max_data_bytes, ret); + + if (packet_code==3) + data[1] = num_multiframes; + + if (!st->use_vbr) + { + ret = opus_packet_pad(data, ret, max_data_bytes); + if (ret == OPUS_OK) + ret = max_data_bytes; + else + ret = OPUS_INTERNAL_ERROR; + } + RESTORE_STACK; + return ret; + } + max_rate = frame_rate*max_data_bytes*8; + + /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->signal_type == OPUS_SIGNAL_VOICE) + voice_est = 127; + else if (st->signal_type == OPUS_SIGNAL_MUSIC) + voice_est = 0; + else if (st->voice_ratio >= 0) + { + voice_est = st->voice_ratio*327>>8; + /* For AUDIO, never be more than 90% confident of having speech */ + if (st->application == OPUS_APPLICATION_AUDIO) + voice_est = IMIN(voice_est, 115); + } else if (st->application == OPUS_APPLICATION_VOIP) + voice_est = 115; + else + voice_est = 48; + + if (st->force_channels!=OPUS_AUTO && st->channels == 2) + { + st->stream_channels = st->force_channels; + } else { +#ifdef FUZZING + /* Random mono/stereo decision */ + if (st->channels == 2 && (rand()&0x1F)==0) + st->stream_channels = 3-st->stream_channels; +#else + /* Rate-dependent mono-stereo decision */ + if (st->channels == 2) + { + opus_int32 stereo_threshold; + stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14); + if (st->stream_channels == 2) + stereo_threshold -= 1000; + else + stereo_threshold += 1000; + st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1; + } else { + st->stream_channels = st->channels; + } +#endif + } + /* Update equivalent rate for channels decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, 0, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + /* Allow SILK DTX if DTX is enabled but the generalized DTX cannot be used, + e.g. because of the complexity setting or sample rate. */ +#ifndef DISABLE_FLOAT_API + st->silk_mode.useDTX = st->use_dtx && !(analysis_info.valid || is_silence); +#else + st->silk_mode.useDTX = st->use_dtx; +#endif + + /* Mode selection depending on application and signal type */ + if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY) + { + st->mode = MODE_CELT_ONLY; + } else if (st->user_forced_mode == OPUS_AUTO) + { +#ifdef FUZZING + /* Random mode switching */ + if ((rand()&0xF)==0) + { + if ((rand()&0x1)==0) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } else { + if (st->prev_mode==MODE_CELT_ONLY) + st->mode = MODE_CELT_ONLY; + else + st->mode = MODE_SILK_ONLY; + } +#else + opus_int32 mode_voice, mode_music; + opus_int32 threshold; + + /* Interpolate based on stereo width */ + mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][0])); + mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1]) + + MULT16_32_Q15(stereo_width,mode_thresholds[1][1])); + /* Interpolate based on speech/music probability */ + threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14); + /* Bias towards SILK for VoIP because of some useful features */ + if (st->application == OPUS_APPLICATION_VOIP) + threshold += 8000; + + /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/ + /* Hysteresis */ + if (st->prev_mode == MODE_CELT_ONLY) + threshold -= 4000; + else if (st->prev_mode>0) + threshold += 4000; + + st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY; + + /* When FEC is enabled and there's enough packet loss, use SILK */ + if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4) + st->mode = MODE_SILK_ONLY; + /* When encoding voice and DTX is enabled but the generalized DTX cannot be used, + use SILK in order to make use of its DTX. */ + if (st->silk_mode.useDTX && voice_est > 100) + st->mode = MODE_SILK_ONLY; +#endif + + /* If max_data_bytes represents less than 6 kb/s, switch to CELT-only mode */ + if (max_data_bytes < (frame_rate > 50 ? 9000 : 6000)*frame_size / (st->Fs * 8)) + st->mode = MODE_CELT_ONLY; + } else { + st->mode = st->user_forced_mode; + } + + /* Override the chosen mode to make sure we meet the requested frame size */ + if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100) + st->mode = MODE_CELT_ONLY; + if (st->lfe) + st->mode = MODE_CELT_ONLY; + + if (st->prev_mode > 0 && + ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) || + (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY))) + { + redundancy = 1; + celt_to_silk = (st->mode != MODE_CELT_ONLY); + if (!celt_to_silk) + { + /* Switch to SILK/hybrid if frame size is 10 ms or more*/ + if (frame_size >= st->Fs/100) + { + st->mode = st->prev_mode; + to_celt = 1; + } else { + redundancy=0; + } + } + } + + /* When encoding multiframes, we can ask for a switch to CELT only in the last frame. This switch + * is processed above as the requested mode shouldn't interrupt stereo->mono transition. */ + if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0 + && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY) + { + /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */ + st->silk_mode.toMono = 1; + st->stream_channels = 2; + } else { + st->silk_mode.toMono = 0; + } + + /* Update equivalent rate with mode decision. */ + equiv_rate = compute_equiv_rate(st->bitrate_bps, st->stream_channels, st->Fs/frame_size, + st->use_vbr, st->mode, st->silk_mode.complexity, st->silk_mode.packetLossPercentage); + + if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) + { + silk_EncControlStruct dummy; + silk_InitEncoder( silk_enc, st->arch, &dummy); + prefill=1; + } + + /* Automatic (rate-dependent) bandwidth selection */ + if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch) + { + const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds; + opus_int32 bandwidth_thresholds[8]; + int bandwidth = OPUS_BANDWIDTH_FULLBAND; + + if (st->channels==2 && st->force_channels!=1) + { + voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds; + music_bandwidth_thresholds = stereo_music_bandwidth_thresholds; + } else { + voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds; + music_bandwidth_thresholds = mono_music_bandwidth_thresholds; + } + /* Interpolate bandwidth thresholds depending on voice estimation */ + for (i=0;i<8;i++) + { + bandwidth_thresholds[i] = music_bandwidth_thresholds[i] + + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14); + } + do { + int threshold, hysteresis; + threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)]; + hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1]; + if (!st->first) + { + if (st->auto_bandwidth >= bandwidth) + threshold -= hysteresis; + else + threshold += hysteresis; + } + if (equiv_rate >= threshold) + break; + } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND); + /* We don't use mediumband anymore, except when explicitly requested or during + mode transitions. */ + if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + bandwidth = OPUS_BANDWIDTH_WIDEBAND; + st->bandwidth = st->auto_bandwidth = bandwidth; + /* Prevents any transition to SWB/FB until the SILK layer has fully + switched to WB mode and turned the variable LP filter off */ + if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + + if (st->bandwidth>st->max_bandwidth) + st->bandwidth = st->max_bandwidth; + + if (st->user_bandwidth != OPUS_AUTO) + st->bandwidth = st->user_bandwidth; + + /* This prevents us from using hybrid at unsafe CBR/max rates */ + if (st->mode != MODE_CELT_ONLY && max_rate < 15000) + { + st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND); + } + + /* Prevents Opus from wasting bits on frequencies that are above + the Nyquist rate of the input signal */ + if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; +#ifndef DISABLE_FLOAT_API + /* Use detected bandwidth to reduce the encoded bandwidth. */ + if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO) + { + int min_detected_bandwidth; + /* Makes bandwidth detection more conservative just in case the detector + gets it wrong when we could have coded a high bandwidth transparently. + When operating in SILK/hybrid mode, we don't go below wideband to avoid + more complicated switches that require redundancy. */ + if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY) + min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + else if (equiv_rate <= 30000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + else if (equiv_rate <= 44000*st->stream_channels) + min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND; + else + min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND; + + st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth); + st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth); + } +#endif + st->silk_mode.LBRR_coded = decide_fec(st->silk_mode.useInBandFEC, st->silk_mode.packetLossPercentage, + st->silk_mode.LBRR_coded, st->mode, &st->bandwidth, equiv_rate); + celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth)); + + /* CELT mode doesn't support mediumband, use wideband instead */ + if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + st->bandwidth = OPUS_BANDWIDTH_WIDEBAND; + if (st->lfe) + st->bandwidth = OPUS_BANDWIDTH_NARROWBAND; + + curr_bandwidth = st->bandwidth; + + /* Chooses the appropriate mode for speech + *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */ + if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_HYBRID; + if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND) + st->mode = MODE_SILK_ONLY; + + /* Can't support higher than >60 ms frames, and >20 ms when in Hybrid or CELT-only modes */ + if ((frame_size > st->Fs/50 && (st->mode != MODE_SILK_ONLY)) || frame_size > 3*st->Fs/50) + { + int enc_frame_size; + int nb_frames; + + if (st->mode == MODE_SILK_ONLY) + { + if (frame_size == 2*st->Fs/25) /* 80 ms -> 2x 40 ms */ + enc_frame_size = st->Fs/25; + else if (frame_size == 3*st->Fs/25) /* 120 ms -> 2x 60 ms */ + enc_frame_size = 3*st->Fs/50; + else /* 100 ms -> 5x 20 ms */ + enc_frame_size = st->Fs/50; + } + else + enc_frame_size = st->Fs/50; + + nb_frames = frame_size/enc_frame_size; + +#ifndef DISABLE_FLOAT_API + if (analysis_read_pos_bak!= -1) + { + st->analysis.read_pos = analysis_read_pos_bak; + st->analysis.read_subframe = analysis_read_subframe_bak; + } +#endif + + ret = encode_multiframe_packet(st, pcm, nb_frames, enc_frame_size, data, + out_data_bytes, to_celt, lsb_depth, float_api); + + RESTORE_STACK; + return ret; + } + + /* For the first frame at a new SILK bandwidth */ + if (st->silk_bw_switch) + { + redundancy = 1; + celt_to_silk = 1; + st->silk_bw_switch = 0; + /* Do a prefill without reseting the sampling rate control. */ + prefill=2; + } + + /* If we decided to go with CELT, make sure redundancy is off, no matter what + we decided earlier. */ + if (st->mode == MODE_CELT_ONLY) + redundancy = 0; + + if (redundancy) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + if (redundancy_bytes == 0) + redundancy = 0; + } + + /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */ + bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1; + + data += 1; + + ec_enc_init(&enc, data, max_data_bytes-1); + + ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_val16); + OPUS_COPY(pcm_buf, &st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels], total_buffer*st->channels); + + if (st->mode == MODE_CELT_ONLY) + hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + else + hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15; + + st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15, + hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) ); + + /* convert from log scale to Hertz */ + cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) ); + + if (st->application == OPUS_APPLICATION_VOIP) + { + hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs, st->arch); + } else { + dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs); + } +#ifndef FIXED_POINT + if (float_api) + { + opus_val32 sum; + sum = celt_inner_prod(&pcm_buf[total_buffer*st->channels], &pcm_buf[total_buffer*st->channels], frame_size*st->channels, st->arch); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e9f) || celt_isnan(sum)) + { + OPUS_CLEAR(&pcm_buf[total_buffer*st->channels], frame_size*st->channels); + st->hp_mem[0] = st->hp_mem[1] = st->hp_mem[2] = st->hp_mem[3] = 0; + } + } +#endif + + + /* SILK processing */ + HB_gain = Q15ONE; + if (st->mode != MODE_CELT_ONLY) + { + opus_int32 total_bitRate, celt_rate; + opus_int activity; +#ifdef FIXED_POINT + const opus_int16 *pcm_silk; +#else + VARDECL(opus_int16, pcm_silk); + ALLOC(pcm_silk, st->channels*frame_size, opus_int16); +#endif + + activity = VAD_NO_DECISION; +#ifndef DISABLE_FLOAT_API + if( analysis_info.valid ) { + /* Inform SILK about the Opus VAD decision */ + activity = ( analysis_info.activity_probability >= DTX_ACTIVITY_THRESHOLD ); + } +#endif + + /* Distribute bits between SILK and CELT */ + total_bitRate = 8 * bytes_target * frame_rate; + if( st->mode == MODE_HYBRID ) { + /* Base rate for SILK */ + st->silk_mode.bitRate = compute_silk_rate_for_hybrid(total_bitRate, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + if (!st->energy_masking) + { + /* Increasingly attenuate high band when it gets allocated fewer bits */ + celt_rate = total_bitRate - st->silk_mode.bitRate; + HB_gain = Q15ONE - SHR32(celt_exp2(-celt_rate * QCONST16(1.f/1024, 10)), 1); + } + } else { + /* SILK gets all bits */ + st->silk_mode.bitRate = total_bitRate; + } + + /* Surround masking for SILK */ + if (st->energy_masking && st->use_vbr && !st->lfe) + { + opus_val32 mask_sum=0; + opus_val16 masking_depth; + opus_int32 rate_offset; + int c; + int end = 17; + opus_int16 srate = 16000; + if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND) + { + end = 13; + srate = 8000; + } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) + { + end = 15; + srate = 12000; + } + for (c=0;cchannels;c++) + { + for(i=0;ienergy_masking[21*c+i], + QCONST16(.5f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT)); + if (mask > 0) + mask = HALF16(mask); + mask_sum += mask; + } + } + /* Conservative rate reduction, we cut the masking in half */ + masking_depth = mask_sum / end*st->channels; + masking_depth += QCONST16(.2f, DB_SHIFT); + rate_offset = (opus_int32)PSHR32(MULT16_16(srate, masking_depth), DB_SHIFT); + rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3); + /* Split the rate change between the SILK and CELT part for hybrid. */ + if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND) + st->silk_mode.bitRate += 3*rate_offset/5; + else + st->silk_mode.bitRate += rate_offset; + } + + st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs; + st->silk_mode.nChannelsAPI = st->channels; + st->silk_mode.nChannelsInternal = st->stream_channels; + if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.desiredInternalSampleRate = 8000; + } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.desiredInternalSampleRate = 12000; + } else { + celt_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND ); + st->silk_mode.desiredInternalSampleRate = 16000; + } + if( st->mode == MODE_HYBRID ) { + /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */ + st->silk_mode.minInternalSampleRate = 16000; + } else { + st->silk_mode.minInternalSampleRate = 8000; + } + + st->silk_mode.maxInternalSampleRate = 16000; + if (st->mode == MODE_SILK_ONLY) + { + opus_int32 effective_max_rate = max_rate; + if (frame_rate > 50) + effective_max_rate = effective_max_rate*2/3; + if (effective_max_rate < 8000) + { + st->silk_mode.maxInternalSampleRate = 12000; + st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate); + } + if (effective_max_rate < 7000) + { + st->silk_mode.maxInternalSampleRate = 8000; + st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate); + } + } + + st->silk_mode.useCBR = !st->use_vbr; + + /* Call SILK encoder for the low band */ + + /* Max bits for SILK, counting ToC, redundancy bytes, and optionally redundancy. */ + st->silk_mode.maxBits = (max_data_bytes-1)*8; + if (redundancy && redundancy_bytes >= 2) + { + /* Counting 1 bit for redundancy position and 20 bits for flag+size (only for hybrid). */ + st->silk_mode.maxBits -= redundancy_bytes*8 + 1; + if (st->mode == MODE_HYBRID) + st->silk_mode.maxBits -= 20; + } + if (st->silk_mode.useCBR) + { + if (st->mode == MODE_HYBRID) + { + st->silk_mode.maxBits = IMIN(st->silk_mode.maxBits, st->silk_mode.bitRate * frame_size / st->Fs); + } + } else { + /* Constrained VBR. */ + if (st->mode == MODE_HYBRID) + { + /* Compute SILK bitrate corresponding to the max total bits available */ + opus_int32 maxBitRate = compute_silk_rate_for_hybrid(st->silk_mode.maxBits*st->Fs / frame_size, + curr_bandwidth, st->Fs == 50 * frame_size, st->use_vbr, st->silk_mode.LBRR_coded, + st->stream_channels); + st->silk_mode.maxBits = maxBitRate * frame_size / st->Fs; + } + } + + if (prefill) + { + opus_int32 zero=0; + int prefill_offset; + /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode + a discontinuity. The exact location is what we need to avoid leaving any "gap" + in the audio when mixing with the redundant CELT frame. Here we can afford to + overwrite st->delay_buffer because the only thing that uses it before it gets + rewritten is tmp_prefill[] and even then only the part after the ramp really + gets used (rather than sent to the encoder and discarded) */ + prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400); + gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset, + 0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs); + OPUS_CLEAR(st->delay_buffer, prefill_offset); +#ifdef FIXED_POINT + pcm_silk = st->delay_buffer; +#else + for (i=0;iencoder_buffer*st->channels;i++) + pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]); +#endif + silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, prefill, activity ); + /* Prevent a second switch in the real encode call. */ + st->silk_mode.opusCanSwitch = 0; + } + +#ifdef FIXED_POINT + pcm_silk = pcm_buf+total_buffer*st->channels; +#else + for (i=0;ichannels;i++) + pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]); +#endif + ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0, activity ); + if( ret ) { + /*fprintf (stderr, "SILK encode error: %d\n", ret);*/ + /* Handle error */ + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + + /* Extract SILK internal bandwidth for signaling in first byte */ + if( st->mode == MODE_SILK_ONLY ) { + if( st->silk_mode.internalSampleRate == 8000 ) { + curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND; + } else if( st->silk_mode.internalSampleRate == 12000 ) { + curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND; + } else if( st->silk_mode.internalSampleRate == 16000 ) { + curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND; + } + } else { + celt_assert( st->silk_mode.internalSampleRate == 16000 ); + } + + st->silk_mode.opusCanSwitch = st->silk_mode.switchReady && !st->nonfinal_frame; + + if (nBytes==0) + { + st->rangeFinal = 0; + data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + + /* FIXME: How do we allocate the redundancy for CBR? */ + if (st->silk_mode.opusCanSwitch) + { + redundancy_bytes = compute_redundancy_bytes(max_data_bytes, st->bitrate_bps, frame_rate, st->stream_channels); + redundancy = (redundancy_bytes != 0); + celt_to_silk = 0; + st->silk_bw_switch = 1; + } + } + + /* CELT processing */ + { + int endband=21; + + switch(curr_bandwidth) + { + case OPUS_BANDWIDTH_NARROWBAND: + endband = 13; + break; + case OPUS_BANDWIDTH_MEDIUMBAND: + case OPUS_BANDWIDTH_WIDEBAND: + endband = 17; + break; + case OPUS_BANDWIDTH_SUPERWIDEBAND: + endband = 19; + break; + case OPUS_BANDWIDTH_FULLBAND: + endband = 21; + break; + } + celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband)); + celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels)); + } + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + if (st->mode != MODE_SILK_ONLY) + { + opus_val32 celt_pred=2; + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + /* We may still decide to disable prediction later */ + if (st->silk_mode.reducedDependency) + celt_pred = 0; + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred)); + + if (st->mode == MODE_HYBRID) + { + if( st->use_vbr ) { + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(0)); + } + } else { + if (st->use_vbr) + { + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps)); + } + } + } + + ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16); + if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0) + { + OPUS_COPY(tmp_prefill, &st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels], st->channels*st->Fs/400); + } + + if (st->channels*(st->encoder_buffer-(frame_size+total_buffer)) > 0) + { + OPUS_MOVE(st->delay_buffer, &st->delay_buffer[st->channels*frame_size], st->channels*(st->encoder_buffer-frame_size-total_buffer)); + OPUS_COPY(&st->delay_buffer[st->channels*(st->encoder_buffer-frame_size-total_buffer)], + &pcm_buf[0], + (frame_size+total_buffer)*st->channels); + } else { + OPUS_COPY(st->delay_buffer, &pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels], st->encoder_buffer*st->channels); + } + /* gain_fade() and stereo_fade() need to be after the buffer copying + because we don't want any of this to affect the SILK part */ + if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) { + gain_fade(pcm_buf, pcm_buf, + st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs); + } + st->prev_HB_gain = HB_gain; + if (st->mode != MODE_HYBRID || st->stream_channels==1) + { + if (equiv_rate > 32000) + st->silk_mode.stereoWidth_Q14 = 16384; + else if (equiv_rate < 16000) + st->silk_mode.stereoWidth_Q14 = 0; + else + st->silk_mode.stereoWidth_Q14 = 16384 - 2048*(opus_int32)(32000-equiv_rate)/(equiv_rate-14000); + } + if( !st->energy_masking && st->channels == 2 ) { + /* Apply stereo width reduction (at low bitrates) */ + if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) { + opus_val16 g1, g2; + g1 = st->hybrid_stereo_width_Q14; + g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14); +#ifdef FIXED_POINT + g1 = g1==16384 ? Q15ONE : SHL16(g1,1); + g2 = g2==16384 ? Q15ONE : SHL16(g2,1); +#else + g1 *= (1.f/16384); + g2 *= (1.f/16384); +#endif + stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap, + frame_size, st->channels, celt_mode->window, st->Fs); + st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14; + } + } + + if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1)) + { + /* For SILK mode, the redundancy is inferred from the length */ + if (st->mode == MODE_HYBRID) + ec_enc_bit_logp(&enc, redundancy, 12); + if (redundancy) + { + int max_redundancy; + ec_enc_bit_logp(&enc, celt_to_silk, 1); + if (st->mode == MODE_HYBRID) + { + /* Reserve the 8 bits needed for the redundancy length, + and at least a few bits for CELT if possible */ + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+8+3+7)>>3); + } + else + max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3); + /* Target the same bit-rate for redundancy as for the rest, + up to a max of 257 bytes */ + redundancy_bytes = IMIN(max_redundancy, redundancy_bytes); + redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes)); + if (st->mode == MODE_HYBRID) + ec_enc_uint(&enc, redundancy_bytes-2, 256); + } + } else { + redundancy = 0; + } + + if (!redundancy) + { + st->silk_bw_switch = 0; + redundancy_bytes = 0; + } + if (st->mode != MODE_CELT_ONLY)start_band=17; + + if (st->mode == MODE_SILK_ONLY) + { + ret = (ec_tell(&enc)+7)>>3; + ec_enc_done(&enc); + nb_compr_bytes = ret; + } else { + nb_compr_bytes = (max_data_bytes-1)-redundancy_bytes; + ec_enc_shrink(&enc, nb_compr_bytes); + } + +#ifndef DISABLE_FLOAT_API + if (redundancy || st->mode != MODE_SILK_ONLY) + celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info)); +#endif + if (st->mode == MODE_HYBRID) { + SILKInfo info; + info.signalType = st->silk_mode.signalType; + info.offset = st->silk_mode.offset; + celt_encoder_ctl(celt_enc, CELT_SET_SILK_INFO(&info)); + } + + /* 5 ms redundant frame for CELT->SILK */ + if (redundancy && celt_to_silk) + { + int err; + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + } + + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band)); + + if (st->mode != MODE_SILK_ONLY) + { + if (st->mode != st->prev_mode && st->prev_mode > 0) + { + unsigned char dummy[2]; + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + + /* Prefilling */ + celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + } + /* If false, we already busted the budget and we'll end up with a "PLC frame" */ + if (ec_tell(&enc) <= 8*nb_compr_bytes) + { + /* Set the bitrate again if it was overridden in the redundancy code above*/ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps-st->silk_mode.bitRate)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(st->use_vbr)); + ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc); + if (ret < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + /* Put CELT->SILK redundancy data in the right place. */ + if (redundancy && celt_to_silk && st->mode==MODE_HYBRID && st->use_vbr) + { + OPUS_MOVE(data+ret, data+nb_compr_bytes, redundancy_bytes); + nb_compr_bytes = nb_compr_bytes+redundancy_bytes; + } + } + } + + /* 5 ms redundant frame for SILK->CELT */ + if (redundancy && !celt_to_silk) + { + int err; + unsigned char dummy[2]; + int N2, N4; + N2 = st->Fs/200; + N4 = st->Fs/400; + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); + celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0)); + celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX)); + + if (st->mode == MODE_HYBRID) + { + /* Shrink packet to what the encoder actually used. */ + nb_compr_bytes = ret; + ec_enc_shrink(&enc, nb_compr_bytes); + } + /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */ + celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL); + + err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL); + if (err < 0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng)); + } + + + + /* Signalling the mode in the first byte */ + data--; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + + st->rangeFinal = enc.rng ^ redundant_rng; + + if (to_celt) + st->prev_mode = MODE_CELT_ONLY; + else + st->prev_mode = st->mode; + st->prev_channels = st->stream_channels; + st->prev_framesize = frame_size; + + st->first = 0; + + /* DTX decision */ +#ifndef DISABLE_FLOAT_API + if (st->use_dtx && (analysis_info.valid || is_silence)) + { + if (decide_dtx_mode(analysis_info.activity_probability, &st->nb_no_activity_frames, + st->peak_signal_energy, pcm, frame_size, st->channels, is_silence, st->arch)) + { + st->rangeFinal = 0; + data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels); + RESTORE_STACK; + return 1; + } + } else { + st->nb_no_activity_frames = 0; + } +#endif + + /* In the unlikely case that the SILK encoder busted its target, tell + the decoder to call the PLC */ + if (ec_tell(&enc) > (max_data_bytes-1)*8) + { + if (max_data_bytes < 2) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + data[1] = 0; + ret = 1; + st->rangeFinal = 0; + } else if (st->mode==MODE_SILK_ONLY&&!redundancy) + { + /*When in LPC only mode it's perfectly + reasonable to strip off trailing zero bytes as + the required range decoder behavior is to + fill these in. This can't be done when the MDCT + modes are used because the decoder needs to know + the actual length for allocation purposes.*/ + while(ret>2&&data[ret]==0)ret--; + } + /* Count ToC and redundancy */ + ret += 1+redundancy_bytes; + if (!st->use_vbr) + { + if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + ret = max_data_bytes; + } + RESTORE_STACK; + return ret; +} + +#ifdef FIXED_POINT + +#ifndef DISABLE_FLOAT_API +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(opus_int16, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, opus_int16); + + for (i=0;ichannels;i++) + in[i] = FLOAT2INT16(pcm[i]); + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); + RESTORE_STACK; + return ret; +} +#endif + +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); +} + +#else +opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 max_data_bytes) +{ + int i, ret; + int frame_size; + VARDECL(float, in); + ALLOC_STACK; + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + ALLOC(in, frame_size*st->channels, float); + + for (i=0;ichannels;i++) + in[i] = (1.0f/32768)*pcm[i]; + ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_int, 0); + RESTORE_STACK; + return ret; +} +opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size, + unsigned char *data, opus_int32 out_data_bytes) +{ + int frame_size; + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, st->Fs); + return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, + pcm, analysis_frame_size, 0, -2, st->channels, downmix_float, 1); +} +#endif + + +int opus_encoder_ctl(OpusEncoder *st, int request, ...) +{ + int ret; + CELTEncoder *celt_enc; + va_list ap; + + ret = OPUS_OK; + va_start(ap, request); + + celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset); + + switch (request) + { + case OPUS_SET_APPLICATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO + && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + || (!st->first && st->application != value)) + { + ret = OPUS_BAD_ARG; + break; + } + st->application = value; +#ifndef DISABLE_FLOAT_API + st->analysis.application = value; +#endif + } + break; + case OPUS_GET_APPLICATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->application; + } + break; + case OPUS_SET_BITRATE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX) + { + if (value <= 0) + goto bad_arg; + else if (value <= 500) + value = 500; + else if (value > (opus_int32)300000*st->channels) + value = (opus_int32)300000*st->channels; + } + st->user_bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276); + } + break; + case OPUS_SET_FORCE_CHANNELS_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if((value<1 || value>st->channels) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->force_channels = value; + } + break; + case OPUS_GET_FORCE_CHANNELS_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->force_channels; + } + break; + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) + { + goto bad_arg; + } + st->max_bandwidth = value; + if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_MAX_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->max_bandwidth; + } + break; + case OPUS_SET_BANDWIDTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_bandwidth = value; + if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) { + st->silk_mode.maxInternalSampleRate = 8000; + } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) { + st->silk_mode.maxInternalSampleRate = 12000; + } else { + st->silk_mode.maxInternalSampleRate = 16000; + } + } + break; + case OPUS_GET_BANDWIDTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->bandwidth; + } + break; + case OPUS_SET_DTX_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_dtx = value; + } + break; + case OPUS_GET_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_dtx; + } + break; + case OPUS_SET_COMPLEXITY_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>10) + { + goto bad_arg; + } + st->silk_mode.complexity = value; + celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value)); + } + break; + case OPUS_GET_COMPLEXITY_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.complexity; + } + break; + case OPUS_SET_INBAND_FEC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->silk_mode.useInBandFEC = value; + } + break; + case OPUS_GET_INBAND_FEC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.useInBandFEC; + } + break; + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value < 0 || value > 100) + { + goto bad_arg; + } + st->silk_mode.packetLossPercentage = value; + celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value)); + } + break; + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->silk_mode.packetLossPercentage; + } + break; + case OPUS_SET_VBR_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->use_vbr = value; + st->silk_mode.useCBR = 1-value; + } + break; + case OPUS_GET_VBR_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->use_vbr; + } + break; + case OPUS_SET_VOICE_RATIO_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<-1 || value>100) + { + goto bad_arg; + } + st->voice_ratio = value; + } + break; + case OPUS_GET_VOICE_RATIO_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->voice_ratio; + } + break; + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + st->vbr_constraint = value; + } + break; + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->vbr_constraint; + } + break; + case OPUS_SET_SIGNAL_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC) + { + goto bad_arg; + } + st->signal_type = value; + } + break; + case OPUS_GET_SIGNAL_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->signal_type; + } + break; + case OPUS_GET_LOOKAHEAD_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs/400; + if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY) + *value += st->delay_compensation; + } + break; + case OPUS_GET_SAMPLE_RATE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->Fs; + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + opus_uint32 *value = va_arg(ap, opus_uint32*); + if (!value) + { + goto bad_arg; + } + *value = st->rangeFinal; + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value<8 || value>24) + { + goto bad_arg; + } + st->lsb_depth=value; + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->lsb_depth; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value != OPUS_FRAMESIZE_ARG && value != OPUS_FRAMESIZE_2_5_MS && + value != OPUS_FRAMESIZE_5_MS && value != OPUS_FRAMESIZE_10_MS && + value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS && + value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_80_MS && + value != OPUS_FRAMESIZE_100_MS && value != OPUS_FRAMESIZE_120_MS) + { + goto bad_arg; + } + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if (value > 1 || value < 0) + goto bad_arg; + st->silk_mode.reducedDependency = value; + } + break; + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + goto bad_arg; + *value = st->silk_mode.reducedDependency; + } + break; + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if(value<0 || value>1) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_SET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + celt_encoder_ctl(celt_enc, OPUS_GET_PHASE_INVERSION_DISABLED(value)); + } + break; + case OPUS_RESET_STATE: + { + void *silk_enc; + silk_EncControlStruct dummy; + char *start; + silk_enc = (char*)st+st->silk_enc_offset; +#ifndef DISABLE_FLOAT_API + tonality_analysis_reset(&st->analysis); +#endif + + start = (char*)&st->OPUS_ENCODER_RESET_START; + OPUS_CLEAR(start, sizeof(OpusEncoder) - (start - (char*)st)); + + celt_encoder_ctl(celt_enc, OPUS_RESET_STATE); + silk_InitEncoder( silk_enc, st->arch, &dummy ); + st->stream_channels = st->channels; + st->hybrid_stereo_width_Q14 = 1 << 14; + st->prev_HB_gain = Q15ONE; + st->first = 1; + st->mode = MODE_HYBRID; + st->bandwidth = OPUS_BANDWIDTH_FULLBAND; + st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ); + } + break; + case OPUS_SET_FORCE_MODE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO) + { + goto bad_arg; + } + st->user_forced_mode = value; + } + break; + case OPUS_SET_LFE_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->lfe = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value)); + } + break; + case OPUS_SET_ENERGY_MASK_REQUEST: + { + opus_val16 *value = va_arg(ap, opus_val16*); + st->energy_masking = value; + ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value)); + } + break; + case OPUS_GET_IN_DTX_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + if (st->silk_mode.useDTX && (st->prev_mode == MODE_SILK_ONLY || st->prev_mode == MODE_HYBRID)) { + /* DTX determined by Silk. */ + int n; + void *silk_enc = (char*)st+st->silk_enc_offset; + *value = 1; + for (n=0;nsilk_mode.nChannelsInternal;n++) { + *value = *value && ((silk_encoder*)silk_enc)->state_Fxx[n].sCmn.noSpeechCounter >= NB_SPEECH_FRAMES_BEFORE_DTX; + } + } +#ifndef DISABLE_FLOAT_API + else if (st->use_dtx) { + /* DTX determined by Opus. */ + *value = st->nb_no_activity_frames >= NB_SPEECH_FRAMES_BEFORE_DTX; + } +#endif + else { + *value = 0; + } + } + break; + + case CELT_GET_MODE_REQUEST: + { + const CELTMode ** value = va_arg(ap, const CELTMode**); + if (!value) + { + goto bad_arg; + } + ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value)); + } + break; + default: + /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/ + ret = OPUS_UNIMPLEMENTED; + break; + } + va_end(ap); + return ret; +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + +void opus_encoder_destroy(OpusEncoder *st) +{ + opus_free(st); +} diff --git a/src/libopus/opus_multistream.c b/src/libopus/opus_multistream.c new file mode 100644 index 00000000..1c1abffe --- /dev/null +++ b/src/libopus/opus_multistream.c @@ -0,0 +1,92 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "celt/stack_alloc.h" +#include +#include "celt/float_cast.h" +#include "celt/os_support.h" + + +int validate_layout(const ChannelLayout *layout) +{ + int i, max_channel; + + max_channel = layout->nb_streams+layout->nb_coupled_streams; + if (max_channel>255) + return 0; + for (i=0;inb_channels;i++) + { + if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255) + return 0; + } + return 1; +} + + +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2) + return i; + } + return -1; +} + +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id*2+1) + return i; + } + return -1; +} + +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev) +{ + int i; + i = (prev<0) ? 0 : prev+1; + for (;inb_channels;i++) + { + if (layout->mapping[i]==stream_id+layout->nb_coupled_streams) + return i; + } + return -1; +} + diff --git a/src/libopus/opus_multistream.h b/src/libopus/opus_multistream.h new file mode 100644 index 00000000..babcee69 --- /dev/null +++ b/src/libopus/opus_multistream.h @@ -0,0 +1,660 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_multistream.h + * @brief Opus reference implementation multistream API + */ + +#ifndef OPUS_MULTISTREAM_H +#define OPUS_MULTISTREAM_H + +#include "opus.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** Macros to trigger compilation errors when the wrong types are provided to a + * CTL. */ +/**@{*/ +#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr))) +#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr))) +/**@}*/ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications. + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120 +#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122 +/**@}*/ + +/** @endcond */ + +/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and + * @ref opus_decoderctls may be applied to a multistream encoder or decoder as + * well. + * In addition, you may retrieve the encoder or decoder state for an specific + * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or + * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually. + */ +/**@{*/ + +/** Gets the encoder state for an individual stream of a multistream encoder. + * @param[in] x opus_int32: The index of the stream whose encoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the encoder. + * @param[out] y OpusEncoder**: Returns a pointer to the given + * encoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y) + +/** Gets the decoder state for an individual stream of a multistream decoder. + * @param[in] x opus_int32: The index of the stream whose decoder you + * wish to retrieve. + * This must be non-negative and less than + * the streams parameter used + * to initialize the decoder. + * @param[out] y OpusDecoder**: Returns a pointer to the given + * decoder state. + * @retval OPUS_BAD_ARG The index of the requested stream was out of range. + * @hideinitializer + */ +#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y) + +/**@}*/ + +/** @defgroup opus_multistream Opus Multistream API + * @{ + * + * The multistream API allows individual Opus streams to be combined into a + * single packet, enabling support for up to 255 channels. Unlike an + * elementary Opus stream, the encoder and decoder must negotiate the channel + * configuration before the decoder can successfully interpret the data in the + * packets produced by the encoder. Some basic information, such as packet + * duration, can be computed without any special negotiation. + * + * The format for multistream Opus packets is defined in + *
    RFC 7845 + * and is based on the self-delimited Opus framing described in Appendix B of + * RFC 6716. + * Normal Opus packets are just a degenerate case of multistream Opus packets, + * and can be encoded or decoded with the multistream API by setting + * streams to 1 when initializing the encoder or + * decoder. + * + * Multistream Opus streams can contain up to 255 elementary Opus streams. + * These may be either "uncoupled" or "coupled", indicating that the decoder + * is configured to decode them to either 1 or 2 channels, respectively. + * The streams are ordered so that all coupled streams appear at the + * beginning. + * + * A mapping table defines which decoded channel i + * should be used for each input/output (I/O) channel j. This table is + * typically provided as an unsigned char array. + * Let i = mapping[j] be the index for I/O channel j. + * If i < 2*coupled_streams, then I/O channel j is + * encoded as the left channel of stream (i/2) if i + * is even, or as the right channel of stream (i/2) if + * i is odd. Otherwise, I/O channel j is encoded as + * mono in stream (i - coupled_streams), unless it has the special + * value 255, in which case it is omitted from the encoding entirely (the + * decoder will reproduce it as silence). Each value i must either + * be the special value 255 or be less than streams + coupled_streams. + * + * The output channels specified by the encoder + * should use the + * Vorbis + * channel ordering. A decoder may wish to apply an additional permutation + * to the mapping the encoder used to achieve a different output channel + * order (e.g. for outputing in WAV order). + * + * Each multistream packet contains an Opus packet for each stream, and all of + * the Opus packets in a single multistream packet must have the same + * duration. Therefore the duration of a multistream packet can be extracted + * from the TOC sequence of the first stream, which is located at the + * beginning of the packet, just like an elementary Opus stream: + * + * @code + * int nb_samples; + * int nb_frames; + * nb_frames = opus_packet_get_nb_frames(data, len); + * if (nb_frames < 1) + * return nb_frames; + * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames; + * @endcode + * + * The general encoding and decoding process proceeds exactly the same as in + * the normal @ref opus_encoder and @ref opus_decoder APIs. + * See their documentation for an overview of how to use the corresponding + * multistream functions. + */ + +/** Opus multistream encoder state. + * This contains the complete state of a multistream Opus encoder. + * It is position independent and can be freely copied. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_init + */ +typedef struct OpusMSEncoder OpusMSEncoder; + +/** Opus multistream decoder state. + * This contains the complete state of a multistream Opus decoder. + * It is position independent and can be freely copied. + * @see opus_multistream_decoder_create + * @see opus_multistream_decoder_init + */ +typedef struct OpusMSDecoder OpusMSDecoder; + +/**\name Multistream encoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSEncoder structure. + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size( + int streams, + int coupled_streams +); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a multistream encoder state. + * Call opus_multistream_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(5); + +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + +/** Initialize a previously allocated multistream encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_encoder_create + * @see opus_multistream_encoder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param[in] mapping const unsigned char[channels]: Mapping from + * encoded channels to input channels, as described in + * @ref opus_multistream. As an extra constraint, the + * multistream encoder does not allow encoding coupled + * streams for which one channel is unused since this + * is never a good idea. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +OPUS_EXPORT int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7); + +/** Encodes a multistream Opus frame. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode( + OpusMSEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Encodes a multistream Opus frame from floating point input. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float( + OpusMSEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + +/** Frees an OpusMSEncoder allocated by + * opus_multistream_encoder_create(). + * @param st OpusMSEncoder*: Multistream encoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st); + +/** Perform a CTL function on a multistream Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSEncoder*: Multistream encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/**@}*/ + +/**\name Multistream decoder functions */ +/**@{*/ + +/** Gets the size of an OpusMSDecoder structure. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size( + int streams, + int coupled_streams +); + +/** Allocates and initializes a multistream decoder state. + * Call opus_multistream_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) OPUS_ARG_NONNULL(5); + +/** Intialize a previously allocated decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_multistream_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_multistream_decoder_create + * @see opus_multistream_deocder_get_size + * @param st OpusMSEncoder*: Multistream encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] mapping const unsigned char[channels]: Mapping from + * coded channels to output channels, as described in + * @ref opus_multistream. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + +/** Decode a multistream Opus packet. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Decode a multistream Opus packet with floating point output. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float( + OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + +/** Perform a CTL function on a multistream Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusMSDecoder*: Multistream decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, or @ref opus_multistream_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + */ +OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + +/** Frees an OpusMSDecoder allocated by + * opus_multistream_decoder_create(). + * @param st OpusMSDecoder: Multistream decoder state to be freed. + */ +OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st); + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_MULTISTREAM_H */ diff --git a/src/libopus/opus_multistream_decoder.c b/src/libopus/opus_multistream_decoder.c new file mode 100644 index 00000000..a9684a84 --- /dev/null +++ b/src/libopus/opus_multistream_decoder.c @@ -0,0 +1,549 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "celt/stack_alloc.h" +#include +#include "celt/float_cast.h" +#include "celt/os_support.h" + +/* DECODER */ + +#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS) +static void validate_ms_decoder(OpusMSDecoder *st) +{ + validate_layout(&st->layout); +} +#define VALIDATE_MS_DECODER(st) validate_ms_decoder(st) +#else +#define VALIDATE_MS_DECODER(st) +#endif + + +opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams) +{ + int coupled_size; + int mono_size; + + if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + return align(sizeof(OpusMSDecoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +int opus_multistream_decoder_init( + OpusMSDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + + ptr = (char*)st + align(sizeof(OpusMSDecoder)); + coupled_size = opus_decoder_get_size(2); + mono_size = opus_decoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2); + if(ret!=OPUS_OK)return ret; + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + return OPUS_OK; +} + + +OpusMSDecoder *opus_multistream_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int *error +) +{ + int ret; + OpusMSDecoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping); + if (error) + *error = ret; + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + return st; +} + +static int opus_multistream_packet_validate(const unsigned char *data, + opus_int32 len, int nb_streams, opus_int32 Fs) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + int samples=0; + opus_int32 packet_offset; + + for (s=0;slayout.nb_streams-1) + { + RESTORE_STACK; + return OPUS_INVALID_PACKET; + } + if (!do_plc) + { + int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs); + if (ret < 0) + { + RESTORE_STACK; + return ret; + } else if (ret > frame_size) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + } + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + opus_int32 packet_offset; + int ret; + + dec = (OpusDecoder*)ptr; + ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size); + + if (!do_plc && len<=0) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + packet_offset = 0; + ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip); + data += packet_offset; + len -= packet_offset; + if (ret <= 0) + { + RESTORE_STACK; + return ret; + } + frame_size = ret; + if (s < st->layout.nb_coupled_streams) + { + int chan, prev; + prev = -1; + /* Copy "left" audio to the channel(s) where it belongs */ + while ( (chan = get_left_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 2, frame_size, user_data); + prev = chan; + } + prev = -1; + /* Copy "right" audio to the channel(s) where it belongs */ + while ( (chan = get_right_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf+1, 2, frame_size, user_data); + prev = chan; + } + } else { + int chan, prev; + prev = -1; + /* Copy audio to the channel(s) where it belongs */ + while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, chan, + buf, 1, frame_size, user_data); + prev = chan; + } + } + } + /* Handle muted channels */ + for (c=0;clayout.nb_channels;c++) + { + if (st->layout.mapping[c] == 255) + { + (*copy_channel_out)(pcm, st->layout.nb_channels, c, + NULL, 0, frame_size, user_data); + } + } + RESTORE_STACK; + return frame_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +) +{ + float *float_dst; + opus_int32 i; + (void)user_data; + float_dst = (float*)dst; + if (src != NULL) + { + for (i=0;ilayout.nb_streams;s++) + { + OpusDecoder *dec; + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_RESET_STATE: + { + int s; + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusDecoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusDecoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusDecoder*)ptr; + } + break; + case OPUS_SET_GAIN_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusDecoder *dec; + + dec = (OpusDecoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_decoder_ctl(dec, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_decoder_destroy(OpusMSDecoder *st) +{ + opus_free(st); +} diff --git a/src/libopus/opus_multistream_encoder.c b/src/libopus/opus_multistream_encoder.c new file mode 100644 index 00000000..5b6576a9 --- /dev/null +++ b/src/libopus/opus_multistream_encoder.c @@ -0,0 +1,1328 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "opus_multistream.h" +#include "opus.h" +#include "opus_private.h" +#include "celt/stack_alloc.h" +#include +#include "celt/float_cast.h" +#include "celt/os_support.h" +#include "celt/mathops.h" +#include "celt/mdct.h" +#include "celt/modes.h" +#include "celt/bands.h" +#include "celt/quant_bands.h" +#include "celt/pitch.h" + +typedef struct { + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[8]; +} VorbisLayout; + +/* Index is nb_channel-1*/ +static const VorbisLayout vorbis_mappings[8] = { + {1, 0, {0}}, /* 1: mono */ + {1, 1, {0, 1}}, /* 2: stereo */ + {2, 1, {0, 2, 1}}, /* 3: 1-d surround */ + {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */ + {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */ + {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */ + {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */ + {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */ +}; + +static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32)); +} + +static opus_val32 *ms_get_window_mem(OpusMSEncoder *st) +{ + int s; + char *ptr; + int coupled_size, mono_size; + + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + /* void* cast avoids clang -Wcast-align warning */ + return (opus_val32*)(void*)ptr; +} + +static int validate_ambisonics(int nb_channels, int *nb_streams, int *nb_coupled_streams) +{ + int order_plus_one; + int acn_channels; + int nondiegetic_channels; + + if (nb_channels < 1 || nb_channels > 227) + return 0; + + order_plus_one = isqrt32(nb_channels); + acn_channels = order_plus_one * order_plus_one; + nondiegetic_channels = nb_channels - acn_channels; + + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return 0; + + if (nb_streams) + *nb_streams = acn_channels + (nondiegetic_channels != 0); + if (nb_coupled_streams) + *nb_coupled_streams = nondiegetic_channels != 0; + return 1; +} + +static int validate_encoder_layout(const ChannelLayout *layout) +{ + int s; + for (s=0;snb_streams;s++) + { + if (s < layout->nb_coupled_streams) + { + if (get_left_channel(layout, s, -1)==-1) + return 0; + if (get_right_channel(layout, s, -1)==-1) + return 0; + } else { + if (get_mono_channel(layout, s, -1)==-1) + return 0; + } + } + return 1; +} + +static void channel_pos(int channels, int pos[8]) +{ + /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */ + if (channels==4) + { + pos[0]=1; + pos[1]=3; + pos[2]=1; + pos[3]=3; + } else if (channels==3||channels==5||channels==6) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=0; + } else if (channels==7) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=2; + pos[6]=0; + } else if (channels==8) + { + pos[0]=1; + pos[1]=2; + pos[2]=3; + pos[3]=1; + pos[4]=3; + pos[5]=1; + pos[6]=3; + pos[7]=0; + } +} + +#if 1 +/* Computes a rough approximation of log2(2^a + 2^b) */ +static opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + opus_val16 max; + opus_val32 diff; + opus_val16 frac; + static const opus_val16 diff_table[17] = { + QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT), + QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT), + QCONST16(0.0028123f, DB_SHIFT) + }; + int low; + if (a>b) + { + max = a; + diff = SUB32(EXTEND32(a),EXTEND32(b)); + } else { + max = b; + diff = SUB32(EXTEND32(b),EXTEND32(a)); + } + if (!(diff < QCONST16(8.f, DB_SHIFT))) /* inverted to catch NaNs */ + return max; +#ifdef FIXED_POINT + low = SHR32(diff, DB_SHIFT-1); + frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT); +#else + low = (int)floor(2*diff); + frac = 2*diff - low; +#endif + return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low])); +} +#else +opus_val16 logSum(opus_val16 a, opus_val16 b) +{ + return log2(pow(4, a)+ pow(4, b))/2; +} +#endif + +void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem, + int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in, int arch +) +{ + int c; + int i; + int LM; + int pos[8] = {0}; + int upsample; + int frame_size; + int freq_size; + opus_val16 channel_offset; + opus_val32 bandE[21]; + opus_val16 maskLogE[3][21]; + VARDECL(opus_val32, in); + VARDECL(opus_val16, x); + VARDECL(opus_val32, freq); + SAVE_STACK; + + upsample = resampling_factor(rate); + frame_size = len*upsample; + freq_size = IMIN(960, frame_size); + + /* LM = log2(frame_size / 120) */ + for (LM=0;LMmaxLM;LM++) + if (celt_mode->shortMdctSize<preemph, preemph_mem+c, 0); +#ifndef FIXED_POINT + { + opus_val32 sum; + sum = celt_inner_prod(in, in, frame_size+overlap, 0); + /* This should filter out both NaNs and ridiculous signals that could + cause NaNs further down. */ + if (!(sum < 1e18f) || celt_isnan(sum)) + { + OPUS_CLEAR(in, frame_size+overlap); + preemph_mem[c] = 0; + } + } +#endif + OPUS_CLEAR(bandE, 21); + for (frame=0;framemdct, in+960*frame, freq, celt_mode->window, + overlap, celt_mode->maxLM-LM, 1, arch); + if (upsample != 1) + { + int bound = freq_size/upsample; + for (i=0;i=0;i--) + bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT)); + if (pos[c]==1) + { + for (i=0;i<21;i++) + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]); + } else if (pos[c]==3) + { + for (i=0;i<21;i++) + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]); + } else if (pos[c]==2) + { + for (i=0;i<21;i++) + { + maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT)); + } + } +#if 0 + for (i=0;i<21;i++) + printf("%f ", bandLogE[21*c+i]); + float sum=0; + for (i=0;i<21;i++) + sum += bandLogE[21*c+i]; + printf("%f ", sum/21); +#endif + OPUS_COPY(mem+c*overlap, in+frame_size, overlap); + } + for (i=0;i<21;i++) + maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]); + channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1))); + for (c=0;c<3;c++) + for (i=0;i<21;i++) + maskLogE[c][i] += channel_offset; +#if 0 + for (c=0;c<3;c++) + { + for (i=0;i<21;i++) + printf("%f ", maskLogE[c][i]); + } +#endif + for (c=0;cnb_streams||nb_coupled_streams<0)return 0; + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + return align(sizeof(OpusMSEncoder)) + + nb_coupled_streams * align(coupled_size) + + (nb_streams-nb_coupled_streams) * align(mono_size); +} + +opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + opus_int32 size; + + if (mapping_family==0) + { + if (channels==1) + { + nb_streams=1; + nb_coupled_streams=0; + } else if (channels==2) + { + nb_streams=1; + nb_coupled_streams=1; + } else + return 0; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + nb_streams=vorbis_mappings[channels-1].nb_streams; + nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + } else if (mapping_family==255) + { + nb_streams=channels; + nb_coupled_streams=0; + } else if (mapping_family==2) + { + if (!validate_ambisonics(channels, &nb_streams, &nb_coupled_streams)) + return 0; + } else + return 0; + size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (channels>2) + { + size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32)); + } + return size; +} + +static int opus_multistream_encoder_init_impl( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + MappingType mapping_type +) +{ + int coupled_size; + int mono_size; + int i, ret; + char *ptr; + + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + return OPUS_BAD_ARG; + + st->arch = opus_select_arch(); + st->layout.nb_channels = channels; + st->layout.nb_streams = streams; + st->layout.nb_coupled_streams = coupled_streams; + if (mapping_type != MAPPING_TYPE_SURROUND) + st->lfe_stream = -1; + st->bitrate_bps = OPUS_AUTO; + st->application = application; + st->variable_duration = OPUS_FRAMESIZE_ARG; + for (i=0;ilayout.nb_channels;i++) + st->layout.mapping[i] = mapping[i]; + if (!validate_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_SURROUND && + !validate_encoder_layout(&st->layout)) + return OPUS_BAD_ARG; + if (mapping_type == MAPPING_TYPE_AMBISONICS && + !validate_ambisonics(st->layout.nb_channels, NULL, NULL)) + return OPUS_BAD_ARG; + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + for (i=0;ilayout.nb_coupled_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application); + if(ret!=OPUS_OK)return ret; + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + ptr += align(coupled_size); + } + for (;ilayout.nb_streams;i++) + { + ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application); + if (i==st->lfe_stream) + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1)); + if(ret!=OPUS_OK)return ret; + ptr += align(mono_size); + } + if (mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), channels); + OPUS_CLEAR(ms_get_window_mem(st), channels*120); + } + st->mapping_type = mapping_type; + return OPUS_OK; +} + +int opus_multistream_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application +) +{ + return opus_multistream_encoder_init_impl(st, Fs, channels, streams, + coupled_streams, mapping, + application, MAPPING_TYPE_NONE); +} + +int opus_multistream_surround_encoder_init( + OpusMSEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application +) +{ + MappingType mapping_type; + + if ((channels>255) || (channels<1)) + return OPUS_BAD_ARG; + st->lfe_stream = -1; + if (mapping_family==0) + { + if (channels==1) + { + *streams=1; + *coupled_streams=0; + mapping[0]=0; + } else if (channels==2) + { + *streams=1; + *coupled_streams=1; + mapping[0]=0; + mapping[1]=1; + } else + return OPUS_UNIMPLEMENTED; + } else if (mapping_family==1 && channels<=8 && channels>=1) + { + int i; + *streams=vorbis_mappings[channels-1].nb_streams; + *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams; + for (i=0;i=6) + st->lfe_stream = *streams-1; + } else if (mapping_family==255) + { + int i; + *streams=channels; + *coupled_streams=0; + for(i=0;i2 && mapping_family==1) { + mapping_type = MAPPING_TYPE_SURROUND; + } else if (mapping_family==2) + { + mapping_type = MAPPING_TYPE_AMBISONICS; + } else + { + mapping_type = MAPPING_TYPE_NONE; + } + return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, + *coupled_streams, mapping, + application, mapping_type); +} + +OpusMSEncoder *opus_multistream_encoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + const unsigned char *mapping, + int application, + int *error +) +{ + int ret; + OpusMSEncoder *st; + if ((channels>255) || (channels<1) || (coupled_streams>streams) || + (streams<1) || (coupled_streams<0) || (streams>255-coupled_streams)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams)); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +OpusMSEncoder *opus_multistream_surround_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + unsigned char *mapping, + int application, + int *error +) +{ + int ret; + opus_int32 size; + OpusMSEncoder *st; + if ((channels>255) || (channels<1)) + { + if (error) + *error = OPUS_BAD_ARG; + return NULL; + } + size = opus_multistream_surround_encoder_get_size(channels, mapping_family); + if (!size) + { + if (error) + *error = OPUS_UNIMPLEMENTED; + return NULL; + } + st = (OpusMSEncoder *)opus_alloc(size); + if (st==NULL) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +static void surround_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 channel_rate; + int stream_offset; + int lfe_offset; + int coupled_ratio; /* Q8 */ + int lfe_ratio; /* Q8 */ + int nb_lfe; + int nb_uncoupled; + int nb_coupled; + int nb_normal; + opus_int32 channel_offset; + opus_int32 bitrate; + int total; + + nb_lfe = (st->lfe_stream!=-1); + nb_coupled = st->layout.nb_coupled_streams; + nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe; + nb_normal = 2*nb_coupled + nb_uncoupled; + + /* Give each non-LFE channel enough bits per channel for coding band energy. */ + channel_offset = 40*IMAX(50, Fs/frame_size); + + if (st->bitrate_bps==OPUS_AUTO) + { + bitrate = nb_normal*(channel_offset + Fs + 10000) + 8000*nb_lfe; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + bitrate = nb_normal*300000 + nb_lfe*128000; + } else { + bitrate = st->bitrate_bps; + } + + /* Give LFE some basic stream_channel allocation but never exceed 1/20 of the + total rate for the non-energy part to avoid problems at really low rate. */ + lfe_offset = IMIN(bitrate/20, 3000) + 15*IMAX(50, Fs/frame_size); + + /* We give each stream (coupled or uncoupled) a starting bitrate. + This models the main saving of coupled channels over uncoupled. */ + stream_offset = (bitrate - channel_offset*nb_normal - lfe_offset*nb_lfe)/nb_normal/2; + stream_offset = IMAX(0, IMIN(20000, stream_offset)); + + /* Coupled streams get twice the mono rate after the offset is allocated. */ + coupled_ratio = 512; + /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */ + lfe_ratio = 32; + + total = (nb_uncoupled<<8) /* mono */ + + coupled_ratio*nb_coupled /* stereo */ + + nb_lfe*lfe_ratio; + channel_rate = 256*(opus_int64)(bitrate - lfe_offset*nb_lfe - stream_offset*(nb_coupled+nb_uncoupled) - channel_offset*nb_normal)/total; + + for (i=0;ilayout.nb_streams;i++) + { + if (ilayout.nb_coupled_streams) + rate[i] = 2*channel_offset + IMAX(0, stream_offset+(channel_rate*coupled_ratio>>8)); + else if (i!=st->lfe_stream) + rate[i] = channel_offset + IMAX(0, stream_offset + channel_rate); + else + rate[i] = IMAX(0, lfe_offset+(channel_rate*lfe_ratio>>8)); + } +} + +static void ambisonics_rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size, + opus_int32 Fs + ) +{ + int i; + opus_int32 total_rate; + opus_int32 per_stream_rate; + + const int nb_channels = st->layout.nb_streams + st->layout.nb_coupled_streams; + + if (st->bitrate_bps==OPUS_AUTO) + { + total_rate = (st->layout.nb_coupled_streams + st->layout.nb_streams) * + (Fs+60*Fs/frame_size) + st->layout.nb_streams * (opus_int32)15000; + } else if (st->bitrate_bps==OPUS_BITRATE_MAX) + { + total_rate = nb_channels * 320000; + } else + { + total_rate = st->bitrate_bps; + } + + /* Allocate equal number of bits to Ambisonic (uncoupled) and non-diegetic + * (coupled) streams */ + per_stream_rate = total_rate / st->layout.nb_streams; + for (i = 0; i < st->layout.nb_streams; i++) + { + rate[i] = per_stream_rate; + } +} + +static opus_int32 rate_allocation( + OpusMSEncoder *st, + opus_int32 *rate, + int frame_size + ) +{ + int i; + opus_int32 rate_sum=0; + opus_int32 Fs; + char *ptr; + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + + if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + ambisonics_rate_allocation(st, rate, frame_size, Fs); + } else + { + surround_rate_allocation(st, rate, frame_size, Fs); + } + + for (i=0;ilayout.nb_streams;i++) + { + rate[i] = IMAX(rate[i], 500); + rate_sum += rate[i]; + } + return rate_sum; +} + +/* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */ +#define MS_FRAME_TMP (6*1275+12) +int opus_multistream_encode_native +( + OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +) +{ + opus_int32 Fs; + int coupled_size; + int mono_size; + int s; + char *ptr; + int tot_size; + VARDECL(opus_val16, buf); + VARDECL(opus_val16, bandSMR); + unsigned char tmp_data[MS_FRAME_TMP]; + OpusRepacketizer rp; + opus_int32 vbr; + const CELTMode *celt_mode; + opus_int32 bitrates[256]; + opus_val16 bandLogE[42]; + opus_val32 *mem = NULL; + opus_val32 *preemph_mem=NULL; + int frame_size; + opus_int32 rate_sum; + opus_int32 smallest_packet; + ALLOC_STACK; + + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + preemph_mem = ms_get_preemph_mem(st); + mem = ms_get_window_mem(st); + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs)); + opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr)); + opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode)); + + frame_size = frame_size_select(analysis_frame_size, st->variable_duration, Fs); + if (frame_size <= 0) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Smallest packet the encoder can produce. */ + smallest_packet = st->layout.nb_streams*2-1; + /* 100 ms needs an extra byte per stream for the ToC. */ + if (Fs/frame_size == 10) + smallest_packet += st->layout.nb_streams; + if (max_data_bytes < smallest_packet) + { + RESTORE_STACK; + return OPUS_BUFFER_TOO_SMALL; + } + ALLOC(buf, 2*frame_size, opus_val16); + coupled_size = opus_encoder_get_size(2); + mono_size = opus_encoder_get_size(1); + + ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch); + } + + /* Compute bitrate allocation between streams (this could be a lot better) */ + rate_sum = rate_allocation(st, bitrates, frame_size); + + if (!vbr) + { + if (st->bitrate_bps == OPUS_AUTO) + { + max_data_bytes = IMIN(max_data_bytes, 3*rate_sum/(3*8*Fs/frame_size)); + } else if (st->bitrate_bps != OPUS_BITRATE_MAX) + { + max_data_bytes = IMIN(max_data_bytes, IMAX(smallest_packet, + 3*st->bitrate_bps/(3*8*Fs/frame_size))); + } + } + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s])); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + opus_int32 equiv_rate; + equiv_rate = st->bitrate_bps; + if (frame_size*50 < Fs) + equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels; + if (equiv_rate > 10000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND)); + else if (equiv_rate > 7000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND)); + else if (equiv_rate > 5000*st->layout.nb_channels) + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND)); + else + opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND)); + if (s < st->layout.nb_coupled_streams) + { + /* To preserve the spatial image, force stereo CELT on coupled streams */ + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2)); + } + } + else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) { + opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY)); + } + } + + ptr = (char*)st + align(sizeof(OpusMSEncoder)); + /* Counting ToC */ + tot_size = 0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + int len; + int curr_max; + int c1, c2; + int ret; + + opus_repacketizer_init(&rp); + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + { + int i; + int left, right; + left = get_left_channel(&st->layout, s, -1); + right = get_right_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 2, + pcm, st->layout.nb_channels, left, frame_size, user_data); + (*copy_channel_in)(buf+1, 2, + pcm, st->layout.nb_channels, right, frame_size, user_data); + ptr += align(coupled_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + for (i=0;i<21;i++) + { + bandLogE[i] = bandSMR[21*left+i]; + bandLogE[21+i] = bandSMR[21*right+i]; + } + } + c1 = left; + c2 = right; + } else { + int i; + int chan = get_mono_channel(&st->layout, s, -1); + (*copy_channel_in)(buf, 1, + pcm, st->layout.nb_channels, chan, frame_size, user_data); + ptr += align(mono_size); + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + for (i=0;i<21;i++) + bandLogE[i] = bandSMR[21*chan+i]; + } + c1 = chan; + c2 = -1; + } + if (st->mapping_type == MAPPING_TYPE_SURROUND) + opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE)); + /* number of bytes left (+Toc) */ + curr_max = max_data_bytes - tot_size; + /* Reserve one byte for the last stream and two for the others */ + curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1); + /* For 100 ms, reserve an extra byte per stream for the ToC */ + if (Fs/frame_size == 10) + curr_max -= st->layout.nb_streams-s-1; + curr_max = IMIN(curr_max,MS_FRAME_TMP); + /* Repacketizer will add one or two bytes for self-delimited frames */ + if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1; + if (!vbr && s == st->layout.nb_streams-1) + opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size))); + len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth, + pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix, float_api); + if (len<0) + { + RESTORE_STACK; + return len; + } + /* We need to use the repacketizer to add the self-delimiting lengths + while taking into account the fact that the encoder can now return + more than one frame at a time (e.g. 60 ms CELT-only) */ + ret = opus_repacketizer_cat(&rp, tmp_data, len); + /* If the opus_repacketizer_cat() fails, then something's seriously wrong + with the encoder. */ + if (ret != OPUS_OK) + { + RESTORE_STACK; + return OPUS_INTERNAL_ERROR; + } + len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp), + data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1); + data += len; + tot_size += len; + } + /*printf("\n");*/ + RESTORE_STACK; + return tot_size; +} + +#if !defined(DISABLE_FLOAT_API) +static void opus_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + const float *float_src; + opus_int32 i; + (void)user_data; + float_src = (const float *)src; + for (i=0;ilayout.nb_channels, IMAX(500*st->layout.nb_channels, value)); + } + st->bitrate_bps = value; + } + break; + case OPUS_GET_BITRATE_REQUEST: + { + int s; + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = 0; + for (s=0;slayout.nb_streams;s++) + { + opus_int32 rate; + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + opus_encoder_ctl(enc, request, &rate); + *value += rate; + } + } + break; + case OPUS_GET_LSB_DEPTH_REQUEST: + case OPUS_GET_VBR_REQUEST: + case OPUS_GET_APPLICATION_REQUEST: + case OPUS_GET_BANDWIDTH_REQUEST: + case OPUS_GET_COMPLEXITY_REQUEST: + case OPUS_GET_PACKET_LOSS_PERC_REQUEST: + case OPUS_GET_DTX_REQUEST: + case OPUS_GET_VOICE_RATIO_REQUEST: + case OPUS_GET_VBR_CONSTRAINT_REQUEST: + case OPUS_GET_SIGNAL_REQUEST: + case OPUS_GET_LOOKAHEAD_REQUEST: + case OPUS_GET_SAMPLE_RATE_REQUEST: + case OPUS_GET_INBAND_FEC_REQUEST: + case OPUS_GET_FORCE_CHANNELS_REQUEST: + case OPUS_GET_PREDICTION_DISABLED_REQUEST: + case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST: + { + OpusEncoder *enc; + /* For int32* GET params, just query the first stream */ + opus_int32 *value = va_arg(ap, opus_int32*); + enc = (OpusEncoder*)ptr; + ret = opus_encoder_ctl(enc, request, value); + } + break; + case OPUS_GET_FINAL_RANGE_REQUEST: + { + int s; + opus_uint32 *value = va_arg(ap, opus_uint32*); + opus_uint32 tmp; + if (!value) + { + goto bad_arg; + } + *value=0; + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, &tmp); + if (ret != OPUS_OK) break; + *value ^= tmp; + } + } + break; + case OPUS_SET_LSB_DEPTH_REQUEST: + case OPUS_SET_COMPLEXITY_REQUEST: + case OPUS_SET_VBR_REQUEST: + case OPUS_SET_VBR_CONSTRAINT_REQUEST: + case OPUS_SET_MAX_BANDWIDTH_REQUEST: + case OPUS_SET_BANDWIDTH_REQUEST: + case OPUS_SET_SIGNAL_REQUEST: + case OPUS_SET_APPLICATION_REQUEST: + case OPUS_SET_INBAND_FEC_REQUEST: + case OPUS_SET_PACKET_LOSS_PERC_REQUEST: + case OPUS_SET_DTX_REQUEST: + case OPUS_SET_FORCE_MODE_REQUEST: + case OPUS_SET_FORCE_CHANNELS_REQUEST: + case OPUS_SET_PREDICTION_DISABLED_REQUEST: + case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST: + { + int s; + /* This works for int32 params */ + opus_int32 value = va_arg(ap, opus_int32); + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, request, value); + if (ret != OPUS_OK) + break; + } + } + break; + case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST: + { + int s; + opus_int32 stream_id; + OpusEncoder **value; + stream_id = va_arg(ap, opus_int32); + if (stream_id<0 || stream_id >= st->layout.nb_streams) + goto bad_arg; + value = va_arg(ap, OpusEncoder**); + if (!value) + { + goto bad_arg; + } + for (s=0;slayout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + } + *value = (OpusEncoder*)ptr; + } + break; + case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 value = va_arg(ap, opus_int32); + st->variable_duration = value; + } + break; + case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = st->variable_duration; + } + break; + case OPUS_RESET_STATE: + { + int s; + if (st->mapping_type == MAPPING_TYPE_SURROUND) + { + OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels); + OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120); + } + for (s=0;slayout.nb_streams;s++) + { + OpusEncoder *enc; + enc = (OpusEncoder*)ptr; + if (s < st->layout.nb_coupled_streams) + ptr += align(coupled_size); + else + ptr += align(mono_size); + ret = opus_encoder_ctl(enc, OPUS_RESET_STATE); + if (ret != OPUS_OK) + break; + } + } + break; + default: + ret = OPUS_UNIMPLEMENTED; + break; + } + return ret; +bad_arg: + return OPUS_BAD_ARG; +} + +int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) +{ + int ret; + va_list ap; + va_start(ap, request); + ret = opus_multistream_encoder_ctl_va_list(st, request, ap); + va_end(ap); + return ret; +} + +void opus_multistream_encoder_destroy(OpusMSEncoder *st) +{ + opus_free(st); +} diff --git a/src/libopus/opus_private.h b/src/libopus/opus_private.h new file mode 100644 index 00000000..8e48d42f --- /dev/null +++ b/src/libopus/opus_private.h @@ -0,0 +1,201 @@ +/* Copyright (c) 2012 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef OPUS_PRIVATE_H +#define OPUS_PRIVATE_H + +#include "celt/arch.h" +#include "opus.h" +#include "celt/celt.h" + +#include /* va_list */ +#include /* offsetof */ + +struct OpusRepacketizer { + unsigned char toc; + int nb_frames; + const unsigned char *frames[48]; + opus_int16 len[48]; + int framesize; +}; + +typedef struct ChannelLayout { + int nb_channels; + int nb_streams; + int nb_coupled_streams; + unsigned char mapping[256]; +} ChannelLayout; + +typedef enum { + MAPPING_TYPE_NONE, + MAPPING_TYPE_SURROUND, + MAPPING_TYPE_AMBISONICS +} MappingType; + +struct OpusMSEncoder { + ChannelLayout layout; + int arch; + int lfe_stream; + int application; + int variable_duration; + MappingType mapping_type; + opus_int32 bitrate_bps; + /* Encoder states go here */ + /* then opus_val32 window_mem[channels*120]; */ + /* then opus_val32 preemph_mem[channels]; */ +}; + +struct OpusMSDecoder { + ChannelLayout layout; + /* Decoder states go here */ +}; + +int opus_multistream_encoder_ctl_va_list(struct OpusMSEncoder *st, int request, + va_list ap); +int opus_multistream_decoder_ctl_va_list(struct OpusMSDecoder *st, int request, + va_list ap); + +int validate_layout(const ChannelLayout *layout); +int get_left_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_right_channel(const ChannelLayout *layout, int stream_id, int prev); +int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev); + +typedef void (*opus_copy_channel_in_func)( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +); + +typedef void (*opus_copy_channel_out_func)( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data +); + +#define MODE_SILK_ONLY 1000 +#define MODE_HYBRID 1001 +#define MODE_CELT_ONLY 1002 + +#define OPUS_SET_VOICE_RATIO_REQUEST 11018 +#define OPUS_GET_VOICE_RATIO_REQUEST 11019 + +/** Configures the encoder's expected percentage of voice + * opposed to music or other signals. + * + * @note This interface is currently more aspiration than actuality. It's + * ultimately expected to bias an automatic signal classifier, but it currently + * just shifts the static bitrate to mode mapping around a little bit. + * + * @param[in] x int: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x) +/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO + * + * @param[out] x int*: Voice percentage in the range 0-100, inclusive. + * @hideinitializer */ +#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x) + + +#define OPUS_SET_FORCE_MODE_REQUEST 11002 +#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x) + +typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int); +void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C); +int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth); + +int encode_size(int size, unsigned char *data); + +opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs); + +opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size, + unsigned char *data, opus_int32 out_data_bytes, int lsb_depth, + const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, + int analysis_channels, downmix_func downmix, int float_api); + +int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len, + opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited, + opus_int32 *packet_offset, int soft_clip); + +/* Make sure everything is properly aligned. */ +static OPUS_INLINE int align(int i) +{ + struct foo {char c; union { void* p; opus_int32 i; opus_val32 v; } u;}; + + unsigned int alignment = offsetof(struct foo, u); + + /* Optimizing compilers should optimize div and multiply into and + for all sensible alignment values. */ + return ((i + alignment - 1) / alignment) * alignment; +} + +int opus_packet_parse_impl(const unsigned char *data, opus_int32 len, + int self_delimited, unsigned char *out_toc, + const unsigned char *frames[48], opus_int16 size[48], + int *payload_offset, opus_int32 *packet_offset); + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad); + +int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len); + +int opus_multistream_encode_native +( + struct OpusMSEncoder *st, + opus_copy_channel_in_func copy_channel_in, + const void *pcm, + int analysis_frame_size, + unsigned char *data, + opus_int32 max_data_bytes, + int lsb_depth, + downmix_func downmix, + int float_api, + void *user_data +); + +int opus_multistream_decode_native( + struct OpusMSDecoder *st, + const unsigned char *data, + opus_int32 len, + void *pcm, + opus_copy_channel_out_func copy_channel_out, + int frame_size, + int decode_fec, + int soft_clip, + void *user_data +); + +#endif /* OPUS_PRIVATE_H */ diff --git a/src/libopus/opus_projection.h b/src/libopus/opus_projection.h new file mode 100644 index 00000000..9dabf4e8 --- /dev/null +++ b/src/libopus/opus_projection.h @@ -0,0 +1,568 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** + * @file opus_projection.h + * @brief Opus projection reference API + */ + +#ifndef OPUS_PROJECTION_H +#define OPUS_PROJECTION_H + +#include "opus_multistream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** @cond OPUS_INTERNAL_DOC */ + +/** These are the actual encoder and decoder CTL ID numbers. + * They should not be used directly by applications.c + * In general, SETs should be even and GETs should be odd.*/ +/**@{*/ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST 6001 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST 6003 +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST 6005 +/**@}*/ + + +/** @endcond */ + +/** @defgroup opus_projection_ctls Projection specific encoder and decoder CTLs + * + * These are convenience macros that are specific to the + * opus_projection_encoder_ctl() and opus_projection_decoder_ctl() + * interface. + * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, + * @ref opus_decoderctls, and @ref opus_multistream_ctls may be applied to a + * projection encoder or decoder as well. + */ +/**@{*/ + +/** Gets the gain (in dB. S7.8-format) of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the gain (in dB. S7.8-format) + * of the demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, __opus_check_int_ptr(x) + + +/** Gets the size in bytes of the demixing matrix from the encoder. + * @param[out] x opus_int32 *: Returns the size in bytes of the + * demixing matrix. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, __opus_check_int_ptr(x) + + +/** Copies the demixing matrix to the supplied pointer location. + * @param[out] x unsigned char *: Returns the demixing matrix to the + * supplied pointer location. + * @param y opus_int32: The size in bytes of the reserved memory at the + * pointer location. + * @hideinitializer + */ +#define OPUS_PROJECTION_GET_DEMIXING_MATRIX(x,y) OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, x, __opus_check_int(y) + + +/**@}*/ + +/** Opus projection encoder state. + * This contains the complete state of a projection Opus encoder. + * It is position independent and can be freely copied. + * @see opus_projection_ambisonics_encoder_create + */ +typedef struct OpusProjectionEncoder OpusProjectionEncoder; + + +/** Opus projection decoder state. + * This contains the complete state of a projection Opus decoder. + * It is position independent and can be freely copied. + * @see opus_projection_decoder_create + * @see opus_projection_decoder_init + */ +typedef struct OpusProjectionDecoder OpusProjectionDecoder; + + +/**\name Projection encoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionEncoder structure. + * @param channels int: The total number of input channels to encode. + * This must be no more than 255. + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_ambisonics_encoder_get_size( + int channels, + int mapping_family +); + + +/** Allocates and initializes a projection encoder state. + * Call opus_projection_encoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param mapping_family int: The mapping family to use for selecting + * the appropriate projection. + * @param[out] streams int *: The total number of streams that will + * be encoded from the input. + * @param[out] coupled_streams int *: Number of coupled (2 channel) + * streams that will be encoded from the input. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application, + int *error +) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5); + + +/** Initialize a previously allocated projection encoder state. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_ambisonics_encoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_ambisonics_encoder_create + * @see opus_projection_ambisonics_encoder_get_size + * @param st OpusProjectionEncoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate of the input signal (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels in the input signal. + * This must be at most 255. + * It may be greater than the number of + * coded channels (streams + + * coupled_streams). + * @param streams int: The total number of streams to encode from the + * input. + * This must be no more than the number of channels. + * @param coupled_streams int: Number of coupled (2 channel) streams + * to encode. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * encoded channels (streams + + * coupled_streams) must be no + * more than the number of input channels. + * @param application int: The target encoder application. + * This must be one of the following: + *
    + *
    #OPUS_APPLICATION_VOIP
    + *
    Process signal for improved speech intelligibility.
    + *
    #OPUS_APPLICATION_AUDIO
    + *
    Favor faithfulness to the original input.
    + *
    #OPUS_APPLICATION_RESTRICTED_LOWDELAY
    + *
    Configure the minimum possible coding delay by disabling certain modes + * of operation.
    + *
    + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_ambisonics_encoder_init( + OpusProjectionEncoder *st, + opus_int32 Fs, + int channels, + int mapping_family, + int *streams, + int *coupled_streams, + int application +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6); + + +/** Encodes a projection Opus frame. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const opus_int16*: The input signal as interleaved + * samples. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode( + OpusProjectionEncoder *st, + const opus_int16 *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Encodes a projection Opus frame from floating point input. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param[in] pcm const float*: The input signal as interleaved + * samples with a normal range of + * +/-1.0. + * Samples with a range beyond +/-1.0 + * are supported but will be clipped by + * decoders using the integer API and + * should only be used if it is known + * that the far end supports extended + * dynamic range. + * This must contain + * frame_size*channels + * samples. + * @param frame_size int: Number of samples per channel in the input + * signal. + * This must be an Opus frame size for the + * encoder's sampling rate. + * For example, at 48 kHz the permitted values + * are 120, 240, 480, 960, 1920, and 2880. + * Passing in a duration of less than 10 ms + * (480 samples at 48 kHz) will prevent the + * encoder from using the LPC or hybrid modes. + * @param[out] data unsigned char*: Output payload. + * This must contain storage for at + * least \a max_data_bytes. + * @param [in] max_data_bytes opus_int32: Size of the allocated + * memory for the output + * payload. This may be + * used to impose an upper limit on + * the instant bitrate, but should + * not be used as the only bitrate + * control. Use #OPUS_SET_BITRATE to + * control the bitrate. + * @returns The length of the encoded packet (in bytes) on success or a + * negative error code (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode_float( + OpusProjectionEncoder *st, + const float *pcm, + int frame_size, + unsigned char *data, + opus_int32 max_data_bytes +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4); + + +/** Frees an OpusProjectionEncoder allocated by + * opus_projection_ambisonics_encoder_create(). + * @param st OpusProjectionEncoder*: Projection encoder state to be freed. + */ +OPUS_EXPORT void opus_projection_encoder_destroy(OpusProjectionEncoder *st); + + +/** Perform a CTL function on a projection Opus encoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionEncoder*: Projection encoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_encoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls + * @see opus_genericctls + * @see opus_encoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/**@}*/ + +/**\name Projection decoder functions */ +/**@{*/ + +/** Gets the size of an OpusProjectionDecoder structure. + * @param channels int: The total number of output channels. + * This must be no more than 255. + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @returns The size in bytes on success, or a negative error code + * (see @ref opus_errorcodes) on error. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_decoder_get_size( + int channels, + int streams, + int coupled_streams +); + + +/** Allocates and initializes a projection decoder state. + * Call opus_projection_decoder_destroy() to release + * this object when finished. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @param[out] error int *: Returns #OPUS_OK on success, or an error + * code (see @ref opus_errorcodes) on + * failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size, + int *error +) OPUS_ARG_NONNULL(5); + + +/** Intialize a previously allocated projection decoder state object. + * The memory pointed to by \a st must be at least the size returned by + * opus_projection_decoder_get_size(). + * This is intended for applications which use their own allocator instead of + * malloc. + * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL. + * @see opus_projection_decoder_create + * @see opus_projection_deocder_get_size + * @param st OpusProjectionDecoder*: Projection encoder state to initialize. + * @param Fs opus_int32: Sampling rate to decode at (in Hz). + * This must be one of 8000, 12000, 16000, + * 24000, or 48000. + * @param channels int: Number of channels to output. + * This must be at most 255. + * It may be different from the number of coded + * channels (streams + + * coupled_streams). + * @param streams int: The total number of streams coded in the + * input. + * This must be no more than 255. + * @param coupled_streams int: Number of streams to decode as coupled + * (2 channel) streams. + * This must be no larger than the total + * number of streams. + * Additionally, The total number of + * coded channels (streams + + * coupled_streams) must be no + * more than 255. + * @param[in] demixing_matrix const unsigned char[demixing_matrix_size]: Demixing matrix + * that mapping from coded channels to output channels, + * as described in @ref opus_projection and + * @ref opus_projection_ctls. + * @param demixing_matrix_size opus_int32: The size in bytes of the + * demixing matrix, as + * described in @ref + * opus_projection_ctls. + * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes) + * on failure. + */ +OPUS_EXPORT int opus_projection_decoder_init( + OpusProjectionDecoder *st, + opus_int32 Fs, + int channels, + int streams, + int coupled_streams, + unsigned char *demixing_matrix, + opus_int32 demixing_matrix_size +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6); + + +/** Decode a projection Opus packet. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + opus_int16 *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Decode a projection Opus packet with floating point output. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param[in] data const unsigned char*: Input payload. + * Use a NULL + * pointer to indicate packet + * loss. + * @param len opus_int32: Number of bytes in payload. + * @param[out] pcm opus_int16*: Output signal, with interleaved + * samples. + * This must contain room for + * frame_size*channels + * samples. + * @param frame_size int: The number of samples per channel of + * available space in \a pcm. + * If this is less than the maximum packet duration + * (120 ms; 5760 for 48kHz), this function will not be capable + * of decoding some packets. In the case of PLC (data==NULL) + * or FEC (decode_fec=1), then frame_size needs to be exactly + * the duration of audio that is missing, otherwise the + * decoder will not be in the optimal state to decode the + * next incoming packet. For the PLC and FEC cases, frame_size + * must be a multiple of 2.5 ms. + * @param decode_fec int: Flag (0 or 1) to request that any in-band + * forward error correction data be decoded. + * If no such data is available, the frame is + * decoded as if it were lost. + * @returns Number of samples decoded on success or a negative error code + * (see @ref opus_errorcodes) on failure. + */ +OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode_float( + OpusProjectionDecoder *st, + const unsigned char *data, + opus_int32 len, + float *pcm, + int frame_size, + int decode_fec +) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4); + + +/** Perform a CTL function on a projection Opus decoder. + * + * Generally the request and subsequent arguments are generated by a + * convenience macro. + * @param st OpusProjectionDecoder*: Projection decoder state. + * @param request This and all remaining parameters should be replaced by one + * of the convenience macros in @ref opus_genericctls, + * @ref opus_decoderctls, @ref opus_multistream_ctls, or + * @ref opus_projection_ctls. + * @see opus_genericctls + * @see opus_decoderctls + * @see opus_multistream_ctls + * @see opus_projection_ctls + */ +OPUS_EXPORT int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) OPUS_ARG_NONNULL(1); + + +/** Frees an OpusProjectionDecoder allocated by + * opus_projection_decoder_create(). + * @param st OpusProjectionDecoder: Projection decoder state to be freed. + */ +OPUS_EXPORT void opus_projection_decoder_destroy(OpusProjectionDecoder *st); + + +/**@}*/ + +/**@}*/ + +#ifdef __cplusplus +} +#endif + +#endif /* OPUS_PROJECTION_H */ diff --git a/src/libopus/opus_projection_decoder.c b/src/libopus/opus_projection_decoder.c new file mode 100644 index 00000000..15cefaf0 --- /dev/null +++ b/src/libopus/opus_projection_decoder.c @@ -0,0 +1,258 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "celt/mathops.h" +#include "celt/os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "mapping_matrix.h" +#include "celt/stack_alloc.h" + +struct OpusProjectionDecoder +{ + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_out_float( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + float *float_dst; + const MappingMatrix *matrix; + float_dst = (float *)dst; + matrix = (const MappingMatrix *)user_data; + + if (dst_channel == 0) + OPUS_CLEAR(float_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel, + src_stride, float_dst, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_out_short( + void *dst, + int dst_stride, + int dst_channel, + const opus_val16 *src, + int src_stride, + int frame_size, + void *user_data) +{ + opus_int16 *short_dst; + const MappingMatrix *matrix; + short_dst = (opus_int16 *)dst; + matrix = (const MappingMatrix *)user_data; + if (dst_channel == 0) + OPUS_CLEAR(short_dst, frame_size * dst_stride); + + if (src != NULL) + mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel, + src_stride, short_dst, dst_stride, frame_size); +} + +static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder))); +} + +static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSDecoder*)(void*)((char*)st + + align(sizeof(OpusProjectionDecoder) + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_decoder_get_size(int channels, int streams, + int coupled_streams) +{ + opus_int32 matrix_size; + opus_int32 decoder_size; + + matrix_size = + mapping_matrix_get_size(streams + coupled_streams, channels); + if (!matrix_size) + return 0; + + decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams); + if (!decoder_size) + return 0; + + return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size; +} + +int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs, + int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size) +{ + int nb_input_streams; + opus_int32 expected_matrix_size; + int i, ret; + unsigned char mapping[255]; + VARDECL(opus_int16, buf); + ALLOC_STACK; + + /* Verify supplied matrix size. */ + nb_input_streams = streams + coupled_streams; + expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16); + if (expected_matrix_size != demixing_matrix_size) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + /* Convert demixing matrix input into internal format. */ + ALLOC(buf, nb_input_streams * channels, opus_int16); + for (i = 0; i < nb_input_streams * channels; i++) + { + int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i]; + s = ((s & 0xFFFF) ^ 0x8000) - 0x8000; + buf[i] = (opus_int16)s; + } + + /* Assign demixing matrix. */ + st->demixing_matrix_size_in_bytes = + mapping_matrix_get_size(channels, nb_input_streams); + if (!st->demixing_matrix_size_in_bytes) + { + RESTORE_STACK; + return OPUS_BAD_ARG; + } + + mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0, + buf, demixing_matrix_size); + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + ret = opus_multistream_decoder_init( + get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping); + RESTORE_STACK; + return ret; +} + +OpusProjectionDecoder *opus_projection_decoder_create( + opus_int32 Fs, int channels, int streams, int coupled_streams, + unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error) +{ + int size; + int ret; + OpusProjectionDecoder *st; + + /* Allocate space for the projection decoder. */ + size = opus_projection_decoder_get_size(channels, streams, coupled_streams); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionDecoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection decoder with provided settings. */ + ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams, + demixing_matrix, demixing_matrix_size); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +#ifdef FIXED_POINT +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#else +int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, opus_int16 *pcm, int frame_size, + int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1, + get_dec_demixing_matrix(st)); +} +#endif + +#ifndef DISABLE_FLOAT_API +int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data, + opus_int32 len, float *pcm, int frame_size, int decode_fec) +{ + return opus_multistream_decode_native(get_multistream_decoder(st), data, len, + pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0, + get_dec_demixing_matrix(st)); +} +#endif + +int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) +{ + va_list ap; + int ret = OPUS_OK; + + va_start(ap, request); + ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st), + request, ap); + va_end(ap); + return ret; +} + +void opus_projection_decoder_destroy(OpusProjectionDecoder *st) +{ + opus_free(st); +} + diff --git a/src/libopus/opus_projection_encoder.c b/src/libopus/opus_projection_encoder.c new file mode 100644 index 00000000..a3a9762a --- /dev/null +++ b/src/libopus/opus_projection_encoder.c @@ -0,0 +1,468 @@ +/* Copyright (c) 2017 Google Inc. + Written by Andrew Allen */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "celt/mathops.h" +#include "celt/os_support.h" +#include "opus_private.h" +#include "opus_defines.h" +#include "opus_projection.h" +#include "opus_multistream.h" +#include "celt/stack_alloc.h" +#include "mapping_matrix.h" + +struct OpusProjectionEncoder +{ + opus_int32 mixing_matrix_size_in_bytes; + opus_int32 demixing_matrix_size_in_bytes; + /* Encoder states go here */ +}; + +#if !defined(DISABLE_FLOAT_API) +static void opus_projection_copy_channel_in_float( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data, + (const float*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} +#endif + +static void opus_projection_copy_channel_in_short( + opus_val16 *dst, + int dst_stride, + const void *src, + int src_stride, + int src_channel, + int frame_size, + void *user_data +) +{ + mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data, + (const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size); +} + +static int get_order_plus_one_from_channels(int channels, int *order_plus_one) +{ + int order_plus_one_; + int acn_channels; + int nondiegetic_channels; + + /* Allowed numbers of channels: + * (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1. + */ + if (channels < 1 || channels > 227) + return OPUS_BAD_ARG; + + order_plus_one_ = isqrt32(channels); + acn_channels = order_plus_one_ * order_plus_one_; + nondiegetic_channels = channels - acn_channels; + if (nondiegetic_channels != 0 && nondiegetic_channels != 2) + return OPUS_BAD_ARG; + + if (order_plus_one) + *order_plus_one = order_plus_one_; + return OPUS_OK; +} + +static int get_streams_from_channels(int channels, int mapping_family, + int *streams, int *coupled_streams, + int *order_plus_one) +{ + if (mapping_family == 3) + { + if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + if (streams) + *streams = (channels + 1) / 2; + if (coupled_streams) + *coupled_streams = channels / 2; + return OPUS_OK; + } + return OPUS_BAD_ARG; +} + +static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder))); +} + +static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (MappingMatrix *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes)); +} + +static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st) +{ + /* void* cast avoids clang -Wcast-align warning */ + return (OpusMSEncoder *)(void*)((char*)st + + align(sizeof(OpusProjectionEncoder) + + st->mixing_matrix_size_in_bytes + + st->demixing_matrix_size_in_bytes)); +} + +opus_int32 opus_projection_ambisonics_encoder_get_size(int channels, + int mapping_family) +{ + int nb_streams; + int nb_coupled_streams; + int order_plus_one; + int mixing_matrix_rows, mixing_matrix_cols; + int demixing_matrix_rows, demixing_matrix_cols; + opus_int32 mixing_matrix_size, demixing_matrix_size; + opus_int32 encoder_size; + int ret; + + ret = get_streams_from_channels(channels, mapping_family, &nb_streams, + &nb_coupled_streams, &order_plus_one); + if (ret != OPUS_OK) + return 0; + + if (order_plus_one == 2) + { + mixing_matrix_rows = mapping_matrix_foa_mixing.rows; + mixing_matrix_cols = mapping_matrix_foa_mixing.cols; + demixing_matrix_rows = mapping_matrix_foa_demixing.rows; + demixing_matrix_cols = mapping_matrix_foa_demixing.cols; + } + else if (order_plus_one == 3) + { + mixing_matrix_rows = mapping_matrix_soa_mixing.rows; + mixing_matrix_cols = mapping_matrix_soa_mixing.cols; + demixing_matrix_rows = mapping_matrix_soa_demixing.rows; + demixing_matrix_cols = mapping_matrix_soa_demixing.cols; + } + else if (order_plus_one == 4) + { + mixing_matrix_rows = mapping_matrix_toa_mixing.rows; + mixing_matrix_cols = mapping_matrix_toa_mixing.cols; + demixing_matrix_rows = mapping_matrix_toa_demixing.rows; + demixing_matrix_cols = mapping_matrix_toa_demixing.cols; + } + else + return 0; + + mixing_matrix_size = + mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols); + if (!mixing_matrix_size) + return 0; + + demixing_matrix_size = + mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols); + if (!demixing_matrix_size) + return 0; + + encoder_size = + opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams); + if (!encoder_size) + return 0; + + return align(sizeof(OpusProjectionEncoder)) + + mixing_matrix_size + demixing_matrix_size + encoder_size; +} + +int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs, + int channels, int mapping_family, + int *streams, int *coupled_streams, + int application) +{ + MappingMatrix *mixing_matrix; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int i; + int ret; + int order_plus_one; + unsigned char mapping[255]; + + if (streams == NULL || coupled_streams == NULL) { + return OPUS_BAD_ARG; + } + + if (get_streams_from_channels(channels, mapping_family, streams, + coupled_streams, &order_plus_one) != OPUS_OK) + return OPUS_BAD_ARG; + + if (mapping_family == 3) + { + /* Assign mixing matrix based on available pre-computed matrices. */ + mixing_matrix = get_mixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows, + mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain, + mapping_matrix_foa_mixing_data, + sizeof(mapping_matrix_foa_mixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows, + mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain, + mapping_matrix_soa_mixing_data, + sizeof(mapping_matrix_soa_mixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows, + mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain, + mapping_matrix_toa_mixing_data, + sizeof(mapping_matrix_toa_mixing_data)); + } + else + return OPUS_BAD_ARG; + + st->mixing_matrix_size_in_bytes = mapping_matrix_get_size( + mixing_matrix->rows, mixing_matrix->cols); + if (!st->mixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + + /* Assign demixing matrix based on available pre-computed matrices. */ + demixing_matrix = get_enc_demixing_matrix(st); + if (order_plus_one == 2) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows, + mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain, + mapping_matrix_foa_demixing_data, + sizeof(mapping_matrix_foa_demixing_data)); + } + else if (order_plus_one == 3) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows, + mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain, + mapping_matrix_soa_demixing_data, + sizeof(mapping_matrix_soa_demixing_data)); + } + else if (order_plus_one == 4) + { + mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows, + mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain, + mapping_matrix_toa_demixing_data, + sizeof(mapping_matrix_toa_demixing_data)); + } + else + return OPUS_BAD_ARG; + + st->demixing_matrix_size_in_bytes = mapping_matrix_get_size( + demixing_matrix->rows, demixing_matrix->cols); + if (!st->demixing_matrix_size_in_bytes) + return OPUS_BAD_ARG; + } + else + return OPUS_UNIMPLEMENTED; + + /* Ensure matrices are large enough for desired coding scheme. */ + if (*streams + *coupled_streams > mixing_matrix->rows || + channels > mixing_matrix->cols || + channels > demixing_matrix->rows || + *streams + *coupled_streams > demixing_matrix->cols) + return OPUS_BAD_ARG; + + /* Set trivial mapping so each input channel pairs with a matrix column. */ + for (i = 0; i < channels; i++) + mapping[i] = i; + + /* Initialize multistream encoder with provided settings. */ + ms_encoder = get_multistream_encoder(st); + ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams, + *coupled_streams, mapping, application); + return ret; +} + +OpusProjectionEncoder *opus_projection_ambisonics_encoder_create( + opus_int32 Fs, int channels, int mapping_family, int *streams, + int *coupled_streams, int application, int *error) +{ + int size; + int ret; + OpusProjectionEncoder *st; + + /* Allocate space for the projection encoder. */ + size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family); + if (!size) { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + st = (OpusProjectionEncoder *)opus_alloc(size); + if (!st) + { + if (error) + *error = OPUS_ALLOC_FAIL; + return NULL; + } + + /* Initialize projection encoder with provided settings. */ + ret = opus_projection_ambisonics_encoder_init(st, Fs, channels, + mapping_family, streams, coupled_streams, application); + if (ret != OPUS_OK) + { + opus_free(st); + st = NULL; + } + if (error) + *error = ret; + return st; +} + +int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_short, pcm, frame_size, data, + max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st)); +} + +#ifndef DISABLE_FLOAT_API +#ifdef FIXED_POINT +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 16, downmix_float, 1, get_mixing_matrix(st)); +} +#else +int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm, + int frame_size, unsigned char *data, + opus_int32 max_data_bytes) +{ + return opus_multistream_encode_native(get_multistream_encoder(st), + opus_projection_copy_channel_in_float, pcm, frame_size, data, + max_data_bytes, 24, downmix_float, 1, get_mixing_matrix(st)); +} +#endif +#endif + +void opus_projection_encoder_destroy(OpusProjectionEncoder *st) +{ + opus_free(st); +} + +int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) +{ + va_list ap; + MappingMatrix *demixing_matrix; + OpusMSEncoder *ms_encoder; + int ret = OPUS_OK; + + ms_encoder = get_multistream_encoder(st); + demixing_matrix = get_enc_demixing_matrix(st); + + va_start(ap, request); + switch(request) + { + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = + ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16); + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST: + { + opus_int32 *value = va_arg(ap, opus_int32*); + if (!value) + { + goto bad_arg; + } + *value = demixing_matrix->gain; + } + break; + case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST: + { + int i, j, k, l; + int nb_input_streams; + int nb_output_streams; + unsigned char *external_char; + opus_int16 *internal_short; + opus_int32 external_size; + opus_int32 internal_size; + + /* (I/O is in relation to the decoder's perspective). */ + nb_input_streams = ms_encoder->layout.nb_streams + + ms_encoder->layout.nb_coupled_streams; + nb_output_streams = ms_encoder->layout.nb_channels; + + external_char = va_arg(ap, unsigned char *); + external_size = va_arg(ap, opus_int32); + if (!external_char) + { + goto bad_arg; + } + internal_short = mapping_matrix_get_data(demixing_matrix); + internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16); + if (external_size != internal_size) + { + goto bad_arg; + } + + /* Copy demixing matrix subset to output destination. */ + l = 0; + for (i = 0; i < nb_input_streams; i++) { + for (j = 0; j < nb_output_streams; j++) { + k = demixing_matrix->rows * i + j; + external_char[2*l] = (unsigned char)internal_short[k]; + external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8); + l++; + } + } + } + break; + default: + { + ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap); + } + break; + } + va_end(ap); + return ret; + +bad_arg: + va_end(ap); + return OPUS_BAD_ARG; +} + diff --git a/src/libopus/opus_types.h b/src/libopus/opus_types.h new file mode 100644 index 00000000..7cf67558 --- /dev/null +++ b/src/libopus/opus_types.h @@ -0,0 +1,166 @@ +/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */ +/* Modified by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +/* opus_types.h based on ogg_types.h from libogg */ + +/** + @file opus_types.h + @brief Opus reference implementation types +*/ +#ifndef OPUS_TYPES_H +#define OPUS_TYPES_H + +#define opus_int int /* used for counters etc; at least 16 bits */ +#define opus_int64 long long +#define opus_int8 signed char + +#define opus_uint unsigned int /* used for counters etc; at least 16 bits */ +#define opus_uint64 unsigned long long +#define opus_uint8 unsigned char + +/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */ +#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H)) +#include +# undef opus_int64 +# undef opus_int8 +# undef opus_uint64 +# undef opus_uint8 + typedef int8_t opus_int8; + typedef uint8_t opus_uint8; + typedef int16_t opus_int16; + typedef uint16_t opus_uint16; + typedef int32_t opus_int32; + typedef uint32_t opus_uint32; + typedef int64_t opus_int64; + typedef uint64_t opus_uint64; +#elif defined(_WIN32) + +# if defined(__CYGWIN__) +# include <_G_config.h> + typedef _G_int32_t opus_int32; + typedef _G_uint32_t opus_uint32; + typedef _G_int16 opus_int16; + typedef _G_uint16 opus_uint16; +# elif defined(__MINGW32__) + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; +# elif defined(__MWERKS__) + typedef int opus_int32; + typedef unsigned int opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; +# else + /* MSVC/Borland */ + typedef __int32 opus_int32; + typedef unsigned __int32 opus_uint32; + typedef __int16 opus_int16; + typedef unsigned __int16 opus_uint16; +# endif + +#elif defined(__MACOS__) + +# include + typedef SInt16 opus_int16; + typedef UInt16 opus_uint16; + typedef SInt32 opus_int32; + typedef UInt32 opus_uint32; + +#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ + +# include + typedef int16_t opus_int16; + typedef u_int16_t opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined(__BEOS__) + + /* Be */ +# include + typedef int16 opus_int16; + typedef u_int16 opus_uint16; + typedef int32_t opus_int32; + typedef u_int32_t opus_uint32; + +#elif defined (__EMX__) + + /* OS/2 GCC */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined (DJGPP) + + /* DJGPP */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(R5900) + + /* PS2 EE */ + typedef int opus_int32; + typedef unsigned opus_uint32; + typedef short opus_int16; + typedef unsigned short opus_uint16; + +#elif defined(__SYMBIAN32__) + + /* Symbian GCC */ + typedef signed short opus_int16; + typedef unsigned short opus_uint16; + typedef signed int opus_int32; + typedef unsigned int opus_uint32; + +#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef long opus_int32; + typedef unsigned long opus_uint32; + +#elif defined(CONFIG_TI_C6X) + + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#else + + /* Give up, take a reasonable guess */ + typedef short opus_int16; + typedef unsigned short opus_uint16; + typedef int opus_int32; + typedef unsigned int opus_uint32; + +#endif + +#endif /* OPUS_TYPES_H */ diff --git a/src/libopus/repacketizer.c b/src/libopus/repacketizer.c new file mode 100644 index 00000000..5a1eb675 --- /dev/null +++ b/src/libopus/repacketizer.c @@ -0,0 +1,349 @@ +/* Copyright (c) 2011 Xiph.Org Foundation + Written by Jean-Marc Valin */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "opus.h" +#include "opus_private.h" +#include "celt/os_support.h" + + +int opus_repacketizer_get_size(void) +{ + return sizeof(OpusRepacketizer); +} + +OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) +{ + rp->nb_frames = 0; + return rp; +} + +OpusRepacketizer *opus_repacketizer_create(void) +{ + OpusRepacketizer *rp; + rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size()); + if(rp==NULL)return NULL; + return opus_repacketizer_init(rp); +} + +void opus_repacketizer_destroy(OpusRepacketizer *rp) +{ + opus_free(rp); +} + +static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited) +{ + unsigned char tmp_toc; + int curr_nb_frames,ret; + /* Set of check ToC */ + if (len<1) return OPUS_INVALID_PACKET; + if (rp->nb_frames == 0) + { + rp->toc = data[0]; + rp->framesize = opus_packet_get_samples_per_frame(data, 8000); + } else if ((rp->toc&0xFC) != (data[0]&0xFC)) + { + /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/ + return OPUS_INVALID_PACKET; + } + curr_nb_frames = opus_packet_get_nb_frames(data, len); + if(curr_nb_frames<1) return OPUS_INVALID_PACKET; + + /* Check the 120 ms maximum packet size */ + if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960) + { + return OPUS_INVALID_PACKET; + } + + ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL); + if(ret<1)return ret; + + rp->nb_frames += curr_nb_frames; + return OPUS_OK; +} + +int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) +{ + return opus_repacketizer_cat_impl(rp, data, len, 0); +} + +int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) +{ + return rp->nb_frames; +} + +opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end, + unsigned char *data, opus_int32 maxlen, int self_delimited, int pad) +{ + int i, count; + opus_int32 tot_size; + opus_int16 *len; + const unsigned char **frames; + unsigned char * ptr; + + if (begin<0 || begin>=end || end>rp->nb_frames) + { + /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/ + return OPUS_BAD_ARG; + } + count = end-begin; + + len = rp->len+begin; + frames = rp->frames+begin; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + + ptr = data; + if (count==1) + { + /* Code 0 */ + tot_size += len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = rp->toc&0xFC; + } else if (count==2) + { + if (len[1] == len[0]) + { + /* Code 1 */ + tot_size += 2*len[0]+1; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x1; + } else { + /* Code 2 */ + tot_size += len[0]+len[1]+2+(len[0]>=252); + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x2; + ptr += encode_size(len[0], ptr); + } + } + if (count > 2 || (pad && tot_size < maxlen)) + { + /* Code 3 */ + int vbr; + int pad_amount=0; + + /* Restart the process for the padding case */ + ptr = data; + if (self_delimited) + tot_size = 1 + (len[count-1]>=252); + else + tot_size = 0; + vbr = 0; + for (i=1;i=252) + len[i]; + tot_size += len[count-1]; + + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count | 0x80; + } else { + tot_size += count*len[0]+2; + if (tot_size > maxlen) + return OPUS_BUFFER_TOO_SMALL; + *ptr++ = (rp->toc&0xFC) | 0x3; + *ptr++ = count; + } + pad_amount = pad ? (maxlen-tot_size) : 0; + if (pad_amount != 0) + { + int nb_255s; + data[1] |= 0x40; + nb_255s = (pad_amount-1)/255; + for (i=0;inb_frames, data, maxlen, 0, 0); +} + +int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + /* Moving payload to the end of the packet so we can do in-place padding */ + OPUS_MOVE(data+new_len-len, data, len); + ret = opus_repacketizer_cat(&rp, data+new_len-len, len); + if (ret != OPUS_OK) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1); + if (ret > 0) + return OPUS_OK; + else + return ret; +} + +opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len) +{ + OpusRepacketizer rp; + opus_int32 ret; + if (len < 1) + return OPUS_BAD_ARG; + opus_repacketizer_init(&rp); + ret = opus_repacketizer_cat(&rp, data, len); + if (ret < 0) + return ret; + ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0); + celt_assert(ret > 0 && ret <= len); + return ret; +} + +int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams) +{ + int s; + int count; + unsigned char toc; + opus_int16 size[48]; + opus_int32 packet_offset; + opus_int32 amount; + + if (len < 1) + return OPUS_BAD_ARG; + if (len==new_len) + return OPUS_OK; + else if (len > new_len) + return OPUS_BAD_ARG; + amount = new_len - len; + /* Seek to last stream */ + for (s=0;s cos(LSF) */ +/* Therefore the result is not accurate NLSFs, but the two */ +/* functions are accurate inverses of each other */ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "tables.h" + +/* Number of binary divisions, when not in low complexity mode */ +#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */ +#define MAX_ITERATIONS_A2NLSF_FIX 16 + +/* Helper function for A2NLSF(..) */ +/* Transforms polynomials from cos(n*f) to cos(f)^n */ +static OPUS_INLINE void silk_A2NLSF_trans_poly( + opus_int32 *p, /* I/O Polynomial */ + const opus_int dd /* I Polynomial order (= filter order / 2 ) */ +) +{ + opus_int k, n; + + for( k = 2; k <= dd; k++ ) { + for( n = dd; n > k; n-- ) { + p[ n - 2 ] -= p[ n ]; + } + p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 ); + } +} +/* Helper function for A2NLSF(..) */ +/* Polynomial evaluation */ +static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */ + opus_int32 *p, /* I Polynomial, Q16 */ + const opus_int32 x, /* I Evaluation point, Q12 */ + const opus_int dd /* I Order */ +) +{ + opus_int n; + opus_int32 x_Q16, y32; + + y32 = p[ dd ]; /* Q16 */ + x_Q16 = silk_LSHIFT( x, 4 ); + + if ( opus_likely( 8 == dd ) ) + { + y32 = silk_SMLAWW( p[ 7 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 6 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 5 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 4 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 3 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 2 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 1 ], y32, x_Q16 ); + y32 = silk_SMLAWW( p[ 0 ], y32, x_Q16 ); + } + else + { + for( n = dd - 1; n >= 0; n-- ) { + y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */ + } + } + return y32; +} + +static OPUS_INLINE void silk_A2NLSF_init( + const opus_int32 *a_Q16, + opus_int32 *P, + opus_int32 *Q, + const opus_int dd +) +{ + opus_int k; + + /* Convert filter coefs to even and odd polynomials */ + P[dd] = silk_LSHIFT( 1, 16 ); + Q[dd] = silk_LSHIFT( 1, 16 ); + for( k = 0; k < dd; k++ ) { + P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */ + Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */ + } + + /* Divide out zeros as we have that for even filter orders, */ + /* z = 1 is always a root in Q, and */ + /* z = -1 is always a root in P */ + for( k = dd; k > 0; k-- ) { + P[ k - 1 ] -= P[ k ]; + Q[ k - 1 ] += Q[ k ]; + } + + /* Transform polynomials from cos(n*f) to cos(f)^n */ + silk_A2NLSF_trans_poly( P, dd ); + silk_A2NLSF_trans_poly( Q, dd ); +} + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +) +{ + opus_int i, k, m, dd, root_ix, ffrac; + opus_int32 xlo, xhi, xmid; + opus_int32 ylo, yhi, ymid, thr; + opus_int32 nom, den; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 *PQ[ 2 ]; + opus_int32 *p; + + /* Store pointers to array */ + PQ[ 0 ] = P; + PQ[ 1 ] = Q; + + dd = silk_RSHIFT( d, 1 ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + + /* Find roots, alternating between P and Q */ + p = P; /* Pointer to polynomial */ + + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Loop counter */ + i = 0; /* Counter for bandwidth expansions applied */ + thr = 0; + while( 1 ) { + /* Evaluate polynomial */ + xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */ + yhi = silk_A2NLSF_eval_poly( p, xhi, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) { + if( yhi == 0 ) { + /* If the root lies exactly at the end of the current */ + /* interval, look for the next root in the next interval */ + thr = 1; + } else { + thr = 0; + } + /* Binary division */ + ffrac = -256; + for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) { + /* Evaluate polynomial */ + xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 ); + ymid = silk_A2NLSF_eval_poly( p, xmid, dd ); + + /* Detect zero crossing */ + if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) { + /* Reduce frequency */ + xhi = xmid; + yhi = ymid; + } else { + /* Increase frequency */ + xlo = xmid; + ylo = ymid; + ffrac = silk_ADD_RSHIFT( ffrac, 128, m ); + } + } + + /* Interpolate */ + if( silk_abs( ylo ) < 65536 ) { + /* Avoid dividing by zero */ + den = ylo - yhi; + nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 ); + if( den != 0 ) { + ffrac += silk_DIV32( nom, den ); + } + } else { + /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */ + ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) ); + } + NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX ); + + silk_assert( NLSF[ root_ix ] >= 0 ); + + root_ix++; /* Next root */ + if( root_ix >= d ) { + /* Found all roots */ + break; + } + /* Alternate pointer to polynomial */ + p = PQ[ root_ix & 1 ]; + + /* Evaluate polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/ + ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 ); + } else { + /* Increment loop counter */ + k++; + xlo = xhi; + ylo = yhi; + thr = 0; + + if( k > LSF_COS_TAB_SZ_FIX ) { + i++; + if( i > MAX_ITERATIONS_A2NLSF_FIX ) { + /* Set NLSFs to white spectrum and exit */ + NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 ); + for( k = 1; k < d; k++ ) { + NLSF[ k ] = (opus_int16)silk_ADD16( NLSF[ k-1 ], NLSF[ 0 ] ); + } + return; + } + + /* Error: Apply progressively more bandwidth expansion and run again */ + silk_bwexpander_32( a_Q16, d, 65536 - silk_LSHIFT( 1, i ) ); + + silk_A2NLSF_init( a_Q16, P, Q, dd ); + p = P; /* Pointer to polynomial */ + xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + if( ylo < 0 ) { + /* Set the first NLSF to zero and move on to the next */ + NLSF[ 0 ] = 0; + p = Q; /* Pointer to polynomial */ + ylo = silk_A2NLSF_eval_poly( p, xlo, dd ); + root_ix = 1; /* Index of current root */ + } else { + root_ix = 0; /* Index of current root */ + } + k = 1; /* Reset loop counter */ + } + } + } +} diff --git a/src/libopus/silk/API.h b/src/libopus/silk/API.h new file mode 100644 index 00000000..0feccce1 --- /dev/null +++ b/src/libopus/silk/API.h @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_API_H +#define SILK_API_H + +#include "control.h" +#include "typedef.h" +#include "errors.h" +#include "../celt/entenc.h" +#include "../celt/entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define SILK_MAX_FRAMES_PER_PACKET 3 + +/* Struct for TOC (Table of Contents) */ +typedef struct { + opus_int VADFlag; /* Voice activity for packet */ + opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */ + opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */ +} silk_TOC_struct; + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk encoder state */ +/***********************************************/ +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +); + +/*************************/ +/* Init or reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + int activity /* I Decision of Opus voice activity detector */ +); + +/****************************************/ +/* Decoder functions */ +/****************************************/ + +/***********************************************/ +/* Get size in bytes of the Silk decoder state */ +/***********************************************/ +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +); + +/*************************/ +/* Init or Reset decoder */ +/*************************/ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +); + +/******************/ +/* Decode a frame */ +/******************/ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +); + +#if 0 +/**************************************/ +/* Get table of contents for a packet */ +/**************************************/ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/silk/CNG.c b/src/libopus/silk/CNG.c new file mode 100644 index 00000000..31dfca79 --- /dev/null +++ b/src/libopus/silk/CNG.c @@ -0,0 +1,184 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" + +/* Generates excitation for CNG LPC synthesis */ +static OPUS_INLINE void silk_CNG_exc( + opus_int32 exc_Q14[], /* O CNG excitation signal Q10 */ + opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */ + opus_int length, /* I Length */ + opus_int32 *rand_seed /* I/O Seed to random index generator */ +) +{ + opus_int32 seed; + opus_int i, idx, exc_mask; + + exc_mask = CNG_BUF_MASK_MAX; + while( exc_mask > length ) { + exc_mask = silk_RSHIFT( exc_mask, 1 ); + } + + seed = *rand_seed; + for( i = 0; i < length; i++ ) { + seed = silk_RAND( seed ); + idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask ); + silk_assert( idx >= 0 ); + silk_assert( idx <= CNG_BUF_MASK_MAX ); + exc_Q14[ i ] = exc_buf_Q14[ idx ]; + } + *rand_seed = seed; +} + +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + opus_int i, NLSF_step_Q15, NLSF_acc_Q15; + + NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 ); + NLSF_acc_Q15 = 0; + for( i = 0; i < psDec->LPC_order; i++ ) { + NLSF_acc_Q15 += NLSF_step_Q15; + psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15; + } + psDec->sCNG.CNG_smth_Gain_Q16 = 0; + psDec->sCNG.rand_seed = 3176576; +} + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +) +{ + opus_int i, subfr; + opus_int32 LPC_pred_Q10, max_Gain_Q16, gain_Q16, gain_Q10; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; + silk_CNG_struct *psCNG = &psDec->sCNG; + SAVE_STACK; + + if( psDec->fs_kHz != psCNG->fs_kHz ) { + /* Reset state */ + silk_CNG_Reset( psDec ); + + psCNG->fs_kHz = psDec->fs_kHz; + } + if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) { + /* Update CNG parameters */ + + /* Smoothing of LSF's */ + for( i = 0; i < psDec->LPC_order; i++ ) { + psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 ); + } + /* Find the subframe with the highest gain */ + max_Gain_Q16 = 0; + subfr = 0; + for( i = 0; i < psDec->nb_subfr; i++ ) { + if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) { + max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ]; + subfr = i; + } + } + /* Update CNG excitation buffer with excitation from this subframe */ + silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) ); + silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) ); + + /* Smooth gains */ + for( i = 0; i < psDec->nb_subfr; i++ ) { + psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 ); + } + } + + /* Add CNG when packet is lost or during DTX */ + if( psDec->lossCnt ) { + VARDECL( opus_int32, CNG_sig_Q14 ); + ALLOC( CNG_sig_Q14, length + MAX_LPC_ORDER, opus_int32 ); + + /* Generate CNG excitation */ + gain_Q16 = silk_SMULWW( psDec->sPLC.randScale_Q14, psDec->sPLC.prevGain_Q16[1] ); + if( gain_Q16 >= (1 << 21) || psCNG->CNG_smth_Gain_Q16 > (1 << 23) ) { + gain_Q16 = silk_SMULTT( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULTT( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 16 ); + } else { + gain_Q16 = silk_SMULWW( gain_Q16, gain_Q16 ); + gain_Q16 = silk_SUB_LSHIFT32(silk_SMULWW( psCNG->CNG_smth_Gain_Q16, psCNG->CNG_smth_Gain_Q16 ), gain_Q16, 5 ); + gain_Q16 = silk_LSHIFT32( silk_SQRT_APPROX( gain_Q16 ), 8 ); + } + gain_Q10 = silk_RSHIFT( gain_Q16, 6 ); + + silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed ); + + /* Convert CNG NLSF to filter representation */ + silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* Generate CNG signal, by synthesis filtering */ + silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + for( i = 0; i < length; i++ ) { + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] ); + } + + /* Update states */ + CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( CNG_sig_Q14[ MAX_LPC_ORDER + i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with Gain and add to input signal */ + frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) ); + + } + silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q14[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + } else { + silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} diff --git a/src/libopus/silk/HP_variable_cutoff.c b/src/libopus/silk/HP_variable_cutoff.c new file mode 100644 index 00000000..6a8c900b --- /dev/null +++ b/src/libopus/silk/HP_variable_cutoff.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#ifdef FIXED_POINT +#include "fixed/main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +) +{ + opus_int quality_Q15; + opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7; + silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn; + + /* Adaptive cutoff frequency: estimate low end of pitch frequency range */ + if( psEncC1->prevSignalType == TYPE_VOICED ) { + /* difference, in log domain */ + pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag ); + pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 ); + + /* adjustment based on quality */ + quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ]; + pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ), + pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) ); + + /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */ + delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 ); + if( delta_freq_Q7 < 0 ) { + /* less smoothing for decreasing pitch frequency, to track something close to the minimum */ + delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 ); + } + + /* limit delta, to reduce impact of outliers in pitch estimation */ + delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) ); + + /* update smoother */ + psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15, + silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) ); + + /* limit frequency range */ + psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15, + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ), + silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) ); + } +} diff --git a/src/libopus/silk/Inlines.h b/src/libopus/silk/Inlines.h new file mode 100644 index 00000000..ec986cdf --- /dev/null +++ b/src/libopus/silk/Inlines.h @@ -0,0 +1,188 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/*! \file silk_Inlines.h + * \brief silk_Inlines.h defines OPUS_INLINE signal processing functions. + */ + +#ifndef SILK_FIX_INLINES_H +#define SILK_FIX_INLINES_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* count leading zeros of opus_int64 */ +static OPUS_INLINE opus_int32 silk_CLZ64( opus_int64 in ) +{ + opus_int32 in_upper; + + in_upper = (opus_int32)silk_RSHIFT64(in, 32); + if (in_upper == 0) { + /* Search in the lower 32 bits */ + return 32 + silk_CLZ32( (opus_int32) in ); + } else { + /* Search in the upper 32 bits */ + return silk_CLZ32( in_upper ); + } +} + +/* get number of leading zeros and fractional part (the bits right after the leading one */ +static OPUS_INLINE void silk_CLZ_FRAC( + opus_int32 in, /* I input */ + opus_int32 *lz, /* O number of leading zeros */ + opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */ +) +{ + opus_int32 lzeros = silk_CLZ32(in); + + * lz = lzeros; + * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f; +} + +/* Approximation of square root */ +/* Accuracy: < +/- 10% for output values > 15 */ +/* < +/- 2.5% for output values > 120 */ +static OPUS_INLINE opus_int32 silk_SQRT_APPROX( opus_int32 x ) +{ + opus_int32 y, lz, frac_Q7; + + if( x <= 0 ) { + return 0; + } + + silk_CLZ_FRAC(x, &lz, &frac_Q7); + + if( lz & 1 ) { + y = 32768; + } else { + y = 46214; /* 46214 = sqrt(2) * 32768 */ + } + + /* get scaling right */ + y >>= silk_RSHIFT(lz, 1); + + /* increment using fractional part of input */ + y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7)); + + return y; +} + +/* Divide two int32 values and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */ + const opus_int32 a32, /* I numerator (Q0) */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (>= 0) */ +) +{ + opus_int a_headrm, b_headrm, lshift; + opus_int32 b32_inv, a32_nrm, b32_nrm, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres >= 0 ); + + /* Compute number of bits head room and normalize inputs */ + a_headrm = silk_CLZ32( silk_abs(a32) ) - 1; + a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation */ + /* It's OK to overflow because the final value of a32_nrm should always be small */ + a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */ + + /* Refinement */ + result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */ + + /* Convert to Qres domain */ + lshift = 29 + a_headrm - b_headrm - Qres; + if( lshift < 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + } else { + /* Avoid undefined result */ + return 0; + } + } +} + +/* Invert int32 value and return result as int32 in a given Q-domain */ +static OPUS_INLINE opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */ + const opus_int32 b32, /* I denominator (Q0) */ + const opus_int Qres /* I Q-domain of result (> 0) */ +) +{ + opus_int b_headrm, lshift; + opus_int32 b32_inv, b32_nrm, err_Q32, result; + + silk_assert( b32 != 0 ); + silk_assert( Qres > 0 ); + + /* Compute number of bits head room and normalize input */ + b_headrm = silk_CLZ32( silk_abs(b32) ) - 1; + b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */ + + /* Inverse of b32, with 14 bits of precision */ + b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */ + + /* First approximation */ + result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */ + + /* Compute residual by subtracting product of denominator and first approximation from one */ + err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */ + + /* Refinement */ + result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */ + + /* Convert to Qres domain */ + lshift = 61 - b_headrm - Qres; + if( lshift <= 0 ) { + return silk_LSHIFT_SAT32(result, -lshift); + } else { + if( lshift < 32){ + return silk_RSHIFT(result, lshift); + }else{ + /* Avoid undefined result */ + return 0; + } + } +} + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_INLINES_H */ diff --git a/src/libopus/silk/LPC_analysis_filter.c b/src/libopus/silk/LPC_analysis_filter.c new file mode 100644 index 00000000..4e838189 --- /dev/null +++ b/src/libopus/silk/LPC_analysis_filter.c @@ -0,0 +1,111 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "../celt/celt_lpc.h" + +/*******************************************/ +/* LPC analysis filter */ +/* NB! State is kept internally and the */ +/* filter always starts with zero state */ +/* first d output samples are set to zero */ +/*******************************************/ + +/* OPT: Using celt_fir() for this function should be faster, but it may cause + integer overflows in intermediate values (not final results), which the + current implementation silences by casting to unsigned. Enabling + this should be safe in pretty much all cases, even though it is not technically + C89-compliant. */ +#define USE_CELT_FIR 0 + +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +) +{ + opus_int j; +#if defined(FIXED_POINT) && USE_CELT_FIR + opus_int16 num[SILK_MAX_ORDER_LPC]; +#else + int ix; + opus_int32 out32_Q12, out32; + const opus_int16 *in_ptr; +#endif + + celt_assert( d >= 6 ); + celt_assert( (d & 1) == 0 ); + celt_assert( d <= len ); + +#if defined(FIXED_POINT) && USE_CELT_FIR + celt_assert( d <= SILK_MAX_ORDER_LPC ); + for ( j = 0; j < d; j++ ) { + num[ j ] = -B[ j ]; + } + celt_fir( in + d, num, out + d, len - d, d, arch ); + for ( j = 0; j < d; j++ ) { + out[ j ] = 0; + } +#else + (void)arch; + for( ix = d; ix < len; ix++ ) { + in_ptr = &in[ ix - 1 ]; + + out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] ); + /* Allowing wrap around so that two wraps can cancel each other. The rare + cases where the result wraps around can only be triggered by invalid streams*/ + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] ); + for( j = 6; j < d; j += 2 ) { + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] ); + out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] ); + } + + /* Subtract prediction */ + out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 ); + + /* Scale to Q0 */ + out32 = silk_RSHIFT_ROUND( out32_Q12, 12 ); + + /* Saturate output */ + out[ ix ] = (opus_int16)silk_SAT16( out32 ); + } + + /* Set first d output samples to zero */ + silk_memset( out, 0, d * sizeof( opus_int16 ) ); +#endif +} diff --git a/src/libopus/silk/LPC_fit.c b/src/libopus/silk/LPC_fit.c new file mode 100644 index 00000000..edc930ca --- /dev/null +++ b/src/libopus/silk/LPC_fit.c @@ -0,0 +1,81 @@ +/*********************************************************************** +Copyright (c) 2013, Koen Vos. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +) +{ + opus_int i, k, idx = 0; + opus_int32 maxabs, absval, chirp_Q16; + + /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */ + for( i = 0; i < 10; i++ ) { + /* Find maximum absolute value and its index */ + maxabs = 0; + for( k = 0; k < d; k++ ) { + absval = silk_abs( a_QIN[k] ); + if( absval > maxabs ) { + maxabs = absval; + idx = k; + } + } + maxabs = silk_RSHIFT_ROUND( maxabs, QIN - QOUT ); + + if( maxabs > silk_int16_MAX ) { + /* Reduce magnitude of prediction coefficients */ + maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */ + chirp_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ), + silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) ); + silk_bwexpander_32( a_QIN, d, chirp_Q16 ); + } else { + break; + } + } + + if( i == 10 ) { + /* Reached the last iteration, clip the coefficients */ + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ) ); + a_QIN[ k ] = silk_LSHIFT( (opus_int32)a_QOUT[ k ], QIN - QOUT ); + } + } else { + for( k = 0; k < d; k++ ) { + a_QOUT[ k ] = (opus_int16)silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ); + } + } +} diff --git a/src/libopus/silk/LPC_inv_pred_gain.c b/src/libopus/silk/LPC_inv_pred_gain.c new file mode 100644 index 00000000..a9389a08 --- /dev/null +++ b/src/libopus/silk/LPC_inv_pred_gain.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "define.h" + +#define QA 24 +#define A_LIMIT SILK_FIX_CONST( 0.99975, QA ) + +#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q))) + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +static opus_int32 LPC_inverse_pred_gain_QA_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k, n, mult2Q; + opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2; + + invGain_Q30 = SILK_FIX_CONST( 1, 30 ); + for( k = order - 1; k > 0; k-- ) { + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA ); + + /* rc_mult1_Q30 range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */ + silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) ); + + /* Update inverse gain */ + /* invGain_Q30 range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */ + mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) ); + rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 ); + + /* Update AR coefficient */ + for( n = 0; n < (k + 1) >> 1; n++ ) { + opus_int64 tmp64; + tmp1 = A_QA[ n ]; + tmp2 = A_QA[ k - n - 1 ]; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1, + MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ n ] = ( opus_int32 )tmp64; + tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2, + MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q); + if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) { + return 0; + } + A_QA[ k - n - 1 ] = ( opus_int32 )tmp64; + } + } + + /* Check for stability */ + if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) { + return 0; + } + + /* Set RC equal to negated AR coef */ + rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA ); + + /* Range: [ 1 : 2^30 ] */ + rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) ); + + /* Update inverse gain */ + /* Range: [ 0 : 2^30 ] */ + invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 ); + silk_assert( invGain_Q30 >= 0 ); + silk_assert( invGain_Q30 <= ( 1 << 30 ) ); + if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) { + return 0; + } + + return invGain_Q30; +} + +/* For input in Q12 domain */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +) +{ + opus_int k; + opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 DC_resp = 0; + + /* Increase Q domain of the AR coefficients */ + for( k = 0; k < order; k++ ) { + DC_resp += (opus_int32)A_Q12[ k ]; + Atmp_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 ); + } + /* If the DC is unstable, we don't even need to do the full calculations */ + if( DC_resp >= 4096 ) { + return 0; + } + return LPC_inverse_pred_gain_QA_c( Atmp_QA, order ); +} diff --git a/src/libopus/silk/LP_variable_cutoff.c b/src/libopus/silk/LP_variable_cutoff.c new file mode 100644 index 00000000..49ad4157 --- /dev/null +++ b/src/libopus/silk/LP_variable_cutoff.c @@ -0,0 +1,135 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +/* + Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. +*/ + +#include "main.h" + +/* Helper function, interpolates the filter taps */ +static OPUS_INLINE void silk_LP_interpolate_filter_taps( + opus_int32 B_Q28[ TRANSITION_NB ], + opus_int32 A_Q28[ TRANSITION_NA ], + const opus_int ind, + const opus_int32 fac_Q16 +) +{ + opus_int nb, na; + + if( ind < TRANSITION_INT_NUM - 1 ) { + if( fac_Q16 > 0 ) { + if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */ + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 ); + } + } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */ + silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) ); + /* Piece-wise linear interpolation of B and A */ + for( nb = 0; nb < TRANSITION_NB; nb++ ) { + B_Q28[ nb ] = silk_SMLAWB( + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ], + silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] - + silk_Transition_LP_B_Q28[ ind ][ nb ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + for( na = 0; na < TRANSITION_NA; na++ ) { + A_Q28[ na ] = silk_SMLAWB( + silk_Transition_LP_A_Q28[ ind + 1 ][ na ], + silk_Transition_LP_A_Q28[ ind + 1 ][ na ] - + silk_Transition_LP_A_Q28[ ind ][ na ], + fac_Q16 - ( (opus_int32)1 << 16 ) ); + } + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) ); + } + } else { + silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) ); + silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) ); + } +} + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting psEncC->mode <> 0; */ +/* Deactivate by setting psEncC->mode = 0; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0; + opus_int ind = 0; + + silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES ); + + /* Run filter if needed */ + if( psLP->mode != 0 ) { + /* Calculate index and interpolation factor for interpolation */ +#if( TRANSITION_INT_STEPS == 64 ) + fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 ); +#else + fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES ); +#endif + ind = silk_RSHIFT( fac_Q16, 16 ); + fac_Q16 -= silk_LSHIFT( ind, 16 ); + + silk_assert( ind >= 0 ); + silk_assert( ind < TRANSITION_INT_NUM ); + + /* Interpolate filter coefficients */ + silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 ); + + /* Update transition frame number for next frame */ + psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES ); + + /* ARMA low-pass filtering */ + silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 ); + silk_biquad_alt_stride1( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length); + } +} diff --git a/src/libopus/silk/MacroCount.h b/src/libopus/silk/MacroCount.h new file mode 100644 index 00000000..78100ffe --- /dev/null +++ b/src/libopus/silk/MacroCount.h @@ -0,0 +1,710 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SIGPROCFIX_API_MACROCOUNT_H +#define SIGPROCFIX_API_MACROCOUNT_H +#include + +#ifdef silk_MACRO_COUNT +#define varDefine opus_int64 ops_count = 0; + +extern opus_int64 ops_count; + +static OPUS_INLINE opus_int64 silk_SaveCount(){ + return(ops_count); +} + +static OPUS_INLINE opus_int64 silk_SaveResetCount(){ + opus_int64 ret; + + ret = ops_count; + ops_count = 0; + return(ret); +} + +static OPUS_INLINE silk_PrintCount(){ + printf("ops_count = %d \n ", (opus_int32)ops_count); +} + +#undef silk_MUL +static OPUS_INLINE opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} + +#undef silk_MUL_uint +static OPUS_INLINE opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 * b32; + return ret; +} +#undef silk_MLA +static OPUS_INLINE opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_MLA_uint +static OPUS_INLINE opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){ + opus_uint32 ret; + ops_count += 4; + ret = a32 + b32 * c32; + return ret; +} + +#undef silk_SMULWB +static OPUS_INLINE opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 5; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + return ret; +} +#undef silk_SMLAWB +static OPUS_INLINE opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 5; + ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))); + return ret; +} + +#undef silk_SMULWT +static OPUS_INLINE opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 4; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + return ret; +} +#undef silk_SMLAWT +static OPUS_INLINE opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 4; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + return ret; +} + +#undef silk_SMULBB +static OPUS_INLINE opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32); + return ret; +} +#undef silk_SMLABB +static OPUS_INLINE opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + return ret; +} + +#undef silk_SMULBT +static OPUS_INLINE opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){ + opus_int32 ret; + ops_count += 4; + ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16); + return ret; +} + +#undef silk_SMLABT +static OPUS_INLINE opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + return ret; +} + +#undef silk_SMULTT +static OPUS_INLINE opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + ops_count += 1; + ret = (a32 >> 16) * (b32 >> 16); + return ret; +} + +#undef silk_SMLATT +static OPUS_INLINE opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + ops_count += 1; + ret = a32 + (b32 >> 16) * (c32 >> 16); + return ret; +} + + +/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw silk_MLA + +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw silk_SMLABB + +#undef silk_SMLABT_ovflw +#define silk_SMLABT_ovflw silk_SMLABT + +#undef silk_SMLATT_ovflw +#define silk_SMLATT_ovflw silk_SMLATT + +#undef silk_SMLAWB_ovflw +#define silk_SMLAWB_ovflw silk_SMLAWB + +#undef silk_SMLAWT_ovflw +#define silk_SMLAWT_ovflw silk_SMLAWT + +#undef silk_SMULL +static OPUS_INLINE opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){ + opus_int64 ret; + ops_count += 8; + ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32)); + return ret; +} + +#undef silk_SMLAL +static OPUS_INLINE opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){ + opus_int64 ret; + ops_count += 8; + ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32)); + return ret; +} +#undef silk_SMLALBB +static OPUS_INLINE opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){ + opus_int64 ret; + ops_count += 4; + ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16)); + return ret; +} + +#undef SigProcFIX_CLZ16 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ16(opus_int16 in16) +{ + opus_int32 out32 = 0; + ops_count += 10; + if( in16 == 0 ) { + return 16; + } + /* test nibbles */ + if( in16 & 0xFF00 ) { + if( in16 & 0xF000 ) { + in16 >>= 12; + } else { + out32 += 4; + in16 >>= 8; + } + } else { + if( in16 & 0xFFF0 ) { + out32 += 8; + in16 >>= 4; + } else { + out32 += 12; + } + } + /* test bits and return */ + if( in16 & 0xC ) { + if( in16 & 0x8 ) + return out32 + 0; + else + return out32 + 1; + } else { + if( in16 & 0xE ) + return out32 + 2; + else + return out32 + 3; + } +} + +#undef SigProcFIX_CLZ32 +static OPUS_INLINE opus_int32 SigProcFIX_CLZ32(opus_int32 in32) +{ + /* test highest 16 bits and convert to opus_int16 */ + ops_count += 2; + if( in32 & 0xFFFF0000 ) { + return SigProcFIX_CLZ16((opus_int16)(in32 >> 16)); + } else { + return SigProcFIX_CLZ16((opus_int16)in32) + 16; + } +} + +#undef silk_DIV32 +static OPUS_INLINE opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){ + ops_count += 64; + return a32 / b32; +} + +#undef silk_DIV32_16 +static OPUS_INLINE opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){ + ops_count += 32; + return a32 / b32; +} + +#undef silk_SAT8 +static OPUS_INLINE opus_int8 silk_SAT8(opus_int64 a){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))); + return(tmp); +} + +#undef silk_SAT16 +static OPUS_INLINE opus_int16 silk_SAT16(opus_int64 a){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))); + return(tmp); +} +#undef silk_SAT32 +static OPUS_INLINE opus_int32 silk_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))); + return(tmp); +} +#undef silk_POS_SAT32 +static OPUS_INLINE opus_int32 silk_POS_SAT32(opus_int64 a){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a)); + return(tmp); +} + +#undef silk_ADD_POS_SAT8 +static OPUS_INLINE opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){ + opus_int8 tmp; + ops_count += 1; + tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))); + return(tmp); +} +#undef silk_ADD_POS_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){ + opus_int16 tmp; + ops_count += 1; + tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_ADD_POS_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){ + opus_int32 tmp; + ops_count += 1; + tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))); + return(tmp); +} + +#undef silk_LSHIFT8 +static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){ + opus_int8 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT16 +static OPUS_INLINE opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){ + opus_int16 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT32 +static OPUS_INLINE opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} +#undef silk_LSHIFT64 +static OPUS_INLINE opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_ovflw +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a << shift; +} + +#undef silk_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a << shift; + return ret; +} + +#undef silk_RSHIFT8 +static OPUS_INLINE opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT16 +static OPUS_INLINE opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT32 +static OPUS_INLINE opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} +#undef silk_RSHIFT64 +static OPUS_INLINE opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){ + ops_count += 1; + return a >> shift; +} + +#undef silk_ADD_LSHIFT +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_LSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_ADD_RSHIFT +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT32 +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_ADD_RSHIFT_uint +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){ + opus_uint32 ret; + ops_count += 1; + ret = a + (b >> shift); + return ret; /* shift > 0*/ +} +#undef silk_SUB_LSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b << shift); + return ret; /* shift >= 0*/ +} +#undef silk_SUB_RSHIFT32 +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){ + opus_int32 ret; + ops_count += 1; + ret = a - (b >> shift); + return ret; /* shift > 0*/ +} + +#undef silk_RSHIFT_ROUND +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){ + opus_int32 ret; + ops_count += 3; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_RSHIFT_ROUND64 +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){ + opus_int64 ret; + ops_count += 6; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +#undef silk_abs_int64 +static OPUS_INLINE opus_int64 silk_abs_int64(opus_int64 a){ + ops_count += 1; + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/ +} + +#undef silk_abs_int32 +static OPUS_INLINE opus_int32 silk_abs_int32(opus_int32 a){ + ops_count += 1; + return silk_abs(a); +} + + +#undef silk_min +static silk_min(a, b){ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_max +static silk_max(a, b){ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_sign +static silk_sign(a){ + ops_count += 1; + return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )); +} + +#undef silk_ADD16 +static OPUS_INLINE opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD32 +static OPUS_INLINE opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a + b; + return ret; +} + +#undef silk_ADD64 +static OPUS_INLINE opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a + b; + return ret; +} + +#undef silk_SUB16 +static OPUS_INLINE opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){ + opus_int16 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB32 +static OPUS_INLINE opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){ + opus_int32 ret; + ops_count += 1; + ret = a - b; + return ret; +} + +#undef silk_SUB64 +static OPUS_INLINE opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){ + opus_int64 ret; + ops_count += 2; + ret = a - b; + return ret; +} + +#undef silk_ADD_SAT16 +static OPUS_INLINE opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + /* Nb will be counted in AKP_add32 and silk_SAT16*/ + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_ADD_SAT32 +static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){ + opus_int32 res; + ops_count += 1; + res = ((((a32) + (b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + return res; +} + +#undef silk_ADD_SAT64 +static OPUS_INLINE opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + return res; +} + +#undef silk_SUB_SAT16 +static OPUS_INLINE opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) { + opus_int16 res; + silk_assert(0); + /* Nb will be counted in sub-macros*/ + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + return res; +} + +#undef silk_SUB_SAT32 +static OPUS_INLINE opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) { + opus_int32 res; + ops_count += 1; + res = ((((a32)-(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + return res; +} + +#undef silk_SUB_SAT64 +static OPUS_INLINE opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) { + opus_int64 res; + ops_count += 1; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + + return res; +} + +#undef silk_SMULWW +static OPUS_INLINE opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)); + return ret; +} + +#undef silk_SMLAWW +static OPUS_INLINE opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){ + opus_int32 ret; + /* Nb will be counted in sub-macros*/ + ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)); + return ret; +} + +#undef silk_min_int +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +#undef silk_min_16 +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_32 +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} +#undef silk_min_64 +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +#undef silk_max_int +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_16 +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} +#undef silk_max_32 +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + +#undef silk_max_64 +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + ops_count += 1; + return (((a) > (b)) ? (a) : (b)); +} + + +#undef silk_LIMIT_int +static OPUS_INLINE opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2) +{ + opus_int ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + + return(ret); +} + +#undef silk_LIMIT_16 +static OPUS_INLINE opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2) +{ + opus_int16 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + +return(ret); +} + + +#undef silk_LIMIT_32 +static OPUS_INLINE opus_int32 silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2) +{ + opus_int32 ret; + ops_count += 6; + + ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))); + return(ret); +} + +#else +#define varDefine +#define silk_SaveCount() + +#endif +#endif + diff --git a/src/libopus/silk/MacroDebug.h b/src/libopus/silk/MacroDebug.h new file mode 100644 index 00000000..8dd4ce2e --- /dev/null +++ b/src/libopus/silk/MacroDebug.h @@ -0,0 +1,951 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Copyright (C) 2012 Xiph.Org Foundation +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef MACRO_DEBUG_H +#define MACRO_DEBUG_H + +/* Redefine macro functions with extensive assertion in DEBUG mode. + As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */ + +#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT) + +#undef silk_ADD16 +#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT16( a, b ) ) + { + fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD32 +#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT32( a, b ) ) + { + fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD64 +#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a + b; + if ( ret != silk_ADD_SAT64( a, b ) ) + { + fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB16 +#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){ + opus_int16 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT16( a, b ) ) + { + fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB32 +#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){ + opus_int32 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT32( a, b ) ) + { + fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SUB64 +#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){ + opus_int64 ret; + + ret = a - b; + if ( ret != silk_SUB_SAT64( a, b ) ) + { + fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_ADD_SAT16 +#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT32 +#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 res; + res = ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ? \ + ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \ + ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_ADD_SAT64 +#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) { + opus_int64 res; + int fail = 0; + res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \ + ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \ + ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) ); + if( res != a64 + b64 ) { + /* Check that we saturated to the correct extreme value */ + if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) ) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 + b64; + } + if ( fail ) + { + fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT16 +#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) { + opus_int16 res; + res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) ); + if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) ) + { + fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT32 +#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) { + opus_int32 res; + res = ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ? \ + (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \ + ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) ); + if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) ) + { + fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_SUB_SAT64 +#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) { + opus_int64 res; + int fail = 0; + res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \ + (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \ + ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) ); + if( res != a64 - b64 ) { + /* Check that we saturated to the correct extreme value */ + if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) || + ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) )) + { + fail = 1; + } + } else { + /* Saturation not necessary */ + fail = res != a64 - b64; + } + if ( fail ) + { + fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return res; +} + +#undef silk_MUL +#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + opus_int64 ret64; + ret = a32 * b32; + ret64 = (opus_int64)a32 * (opus_int64)b32; + if ( (opus_int64)ret != ret64 ) + { + fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MUL_uint +#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){ + opus_uint32 ret; + ret = a32 * b32; + if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 ) + { + fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA +#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_MLA_uint +#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){ + opus_uint32 ret; + ret = a32 + b32 * c32; + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 ) + { + fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWB +#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 ) + { + fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWB +#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) ); + if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) ) + { + fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWT +#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret; + ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16); + if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMLAWT +#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16)); + if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) ) + { + fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULL +#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){ + opus_int64 ret64; + int fail = 0; + ret64 = a64 * b64; + if( b64 != 0 ) { + fail = a64 != (ret64 / b64); + } else if( a64 != 0 ) { + fail = b64 != (ret64 / a64); + } + if ( fail ) + { + fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret64; +} + +/* no checking needed for silk_SMULBB */ +#undef silk_SMLABB +#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 ) + { + fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULBT */ +#undef silk_SMLABT +#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* no checking needed for silk_SMULTT */ +#undef silk_SMLATT +#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret; + ret = a32 + (b32 >> 16) * (c32 >> 16); + if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) ) + { + fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_SMULWW +#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){ + opus_int32 ret, tmp1, tmp2; + opus_int64 ret64; + int fail = 0; + + ret = silk_SMULWB( a32, b32 ); + tmp1 = silk_RSHIFT_ROUND( b32, 16 ); + tmp2 = silk_MUL( a32, tmp1 ); + + fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1; + + tmp1 = ret; + ret = silk_ADD32( tmp1, tmp2 ); + fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 ); + + ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 ); + fail |= (opus_int64)ret != ret64; + + if ( fail ) + { + fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + + return ret; +} + +#undef silk_SMLAWW +#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){ + opus_int32 ret, tmp; + + tmp = silk_SMULWW( b32, c32 ); + ret = silk_ADD32( a32, tmp ); + if ( ret != silk_ADD_SAT32( a32, tmp ) ) + { + fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#undef silk_MLA_ovflw +#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32))) +#undef silk_SMLABB_ovflw +#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* no checking needed for silk_SMULL + no checking needed for silk_SMLAL + no checking needed for silk_SMLALBB + no checking needed for SigProcFIX_CLZ16 + no checking needed for SigProcFIX_CLZ32*/ + +#undef silk_DIV32 +#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){ + if ( b32 == 0 ) + { + fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +#undef silk_DIV32_16 +#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){ + int fail = 0; + fail |= b32 == 0; + fail |= b32 > silk_int16_MAX; + fail |= b32 < silk_int16_MIN; + if ( fail ) + { + fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a32 / b32; +} + +/* no checking needed for silk_SAT8 + no checking needed for silk_SAT16 + no checking needed for silk_SAT32 + no checking needed for silk_POS_SAT32 + no checking needed for silk_ADD_POS_SAT8 + no checking needed for silk_ADD_POS_SAT16 + no checking needed for silk_ADD_POS_SAT32 */ + +#undef silk_LSHIFT8 +#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + opus_int8 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 8; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT16 +#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + opus_int16 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 16; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT32 +#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 32; + fail |= (opus_int64)ret != ((opus_int64)a) << shift; + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT64 +#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){ + opus_int64 ret; + int fail = 0; + ret = a << shift; + fail |= shift < 0; + fail |= shift >= 64; + fail |= (ret>>shift) != ((opus_int64)a); + if ( fail ) + { + fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_LSHIFT_ovflw +#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */ + { + fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a << shift; +} + +#undef silk_LSHIFT_uint +#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a << shift; + if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift)) + { + fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT8 +#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=8) ) + { + fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT16 +#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=16) ) + { + fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT32 +#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>=32) ) + { + fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT64 +#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){ + if ( (shift < 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_RSHIFT_uint +#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){ + if ( (shift < 0) || (shift>32) ) + { + fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return a >> shift; +} + +#undef silk_ADD_LSHIFT +#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT32 +#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_LSHIFT_uint +#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b << shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_ADD_RSHIFT +#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){ + opus_int16 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT32 +#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_ADD_RSHIFT_uint +#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){ + opus_uint32 ret; + ret = a + (b >> shift); + if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_SUB_LSHIFT32 +#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b << shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) ) + { + fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift >= 0 */ +} + +#undef silk_SUB_RSHIFT32 +#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = a - (b >> shift); + if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) ) + { + fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; /* shift > 0 */ +} + +#undef silk_RSHIFT_ROUND +#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){ + opus_int32 ret; + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return ret; +} + +#undef silk_RSHIFT_ROUND64 +#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){ + opus_int64 ret; + /* the marco definition can't handle a shift of zero */ + if ( (shift <= 0) || (shift>=64) ) + { + fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1; + return ret; +} + +/* silk_abs is used on floats also, so doesn't work... */ +/*#undef silk_abs +static OPUS_INLINE opus_int32 silk_abs(opus_int32 a){ + silk_assert(a != 0x80000000); + return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN +}*/ + +#undef silk_abs_int64 +#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){ + if ( a == silk_int64_MIN ) + { + fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +} + +#undef silk_abs_int32 +#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){ + if ( a == silk_int32_MIN ) + { + fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return silk_abs(a); +} + +#undef silk_CHECK_FIT8 +#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){ + opus_int8 ret; + ret = (opus_int8)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT16 +#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){ + opus_int16 ret; + ret = (opus_int16)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +#undef silk_CHECK_FIT32 +#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__) +static OPUS_INLINE opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){ + opus_int32 ret; + ret = (opus_int32)a; + if ( (opus_int64)ret != a ) + { + fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line); +#ifdef FIXED_DEBUG_ASSERT + silk_assert( 0 ); +#endif + } + return( ret ); +} + +/* no checking for silk_NSHIFT_MUL_32_32 + no checking for silk_NSHIFT_MUL_16_16 + no checking needed for silk_min + no checking needed for silk_max + no checking needed for silk_sign +*/ + +#endif +#endif /* MACRO_DEBUG_H */ diff --git a/src/libopus/silk/NLSF2A.c b/src/libopus/silk/NLSF2A.c new file mode 100644 index 00000000..40718e7a --- /dev/null +++ b/src/libopus/silk/NLSF2A.c @@ -0,0 +1,141 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +/* conversion between prediction filter coefficients and LSFs */ +/* order should be even */ +/* a piecewise linear approximation maps LSF <-> cos(LSF) */ +/* therefore the result is not accurate LSFs, but the two */ +/* functions are accurate inverses of each other */ + +#include "SigProc_FIX.h" +#include "tables.h" + +#define QA 16 + +/* helper function for NLSF2A(..) */ +static OPUS_INLINE void silk_NLSF2A_find_poly( + opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */ + const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */ + opus_int dd /* I polynomial order (= 1/2 * filter order) */ +) +{ + opus_int k, n; + opus_int32 ftmp; + + out[0] = silk_LSHIFT( 1, QA ); + out[1] = -cLSF[0]; + for( k = 1; k < dd; k++ ) { + ftmp = cLSF[2*k]; /* QA*/ + out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA ); + for( n = k; n > 1; n-- ) { + out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA ); + } + out[1] -= ftmp; + } +} + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +) +{ + /* This ordering was found to maximize quality. It improves numerical accuracy of + silk_NLSF2A_find_poly() compared to "standard" ordering. */ + static const unsigned char ordering16[16] = { + 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1 + }; + static const unsigned char ordering10[10] = { + 0, 9, 6, 3, 4, 5, 8, 1, 2, 7 + }; + const unsigned char *ordering; + opus_int k, i, dd; + opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta; + opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ]; + + silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); + celt_assert( d==10 || d==16 ); + + /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */ + ordering = d == 16 ? ordering16 : ordering10; + for( k = 0; k < d; k++ ) { + silk_assert( NLSF[k] >= 0 ); + + /* f_int on a scale 0-127 (rounded down) */ + f_int = silk_RSHIFT( NLSF[k], 15 - 7 ); + + /* f_frac, range: 0..255 */ + f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 ); + + silk_assert(f_int >= 0); + silk_assert(f_int < LSF_COS_TAB_SZ_FIX ); + + /* Read start and end value from table */ + cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */ + delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */ + + /* Linear interpolation */ + cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */ + } + + dd = silk_RSHIFT( d, 1 ); + + /* generate even and odd polynomials using convolution */ + silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd ); + silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd ); + + /* convert even and odd polynomials to opus_int32 Q12 filter coefs */ + for( k = 0; k < dd; k++ ) { + Ptmp = P[ k+1 ] + P[ k ]; + Qtmp = Q[ k+1 ] - Q[ k ]; + + /* the Ptmp and Qtmp values at this stage need to fit in int32 */ + a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */ + a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */ + } + + /* Convert int32 coefficients to Q12 int16 coefs */ + silk_LPC_fit( a_Q12, a32_QA1, 12, QA + 1, d ); + + for( i = 0; silk_LPC_inverse_pred_gain( a_Q12, d, arch ) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) { + /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */ + /* on the unscaled coefficients, convert to Q12 and measure again */ + silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) ); + for( k = 0; k < d; k++ ) { + a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ + } + } +} + diff --git a/src/libopus/silk/NLSF_VQ.c b/src/libopus/silk/NLSF_VQ.c new file mode 100644 index 00000000..372a0131 --- /dev/null +++ b/src/libopus/silk/NLSF_VQ.c @@ -0,0 +1,76 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q24[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +) +{ + opus_int i, m; + opus_int32 diff_Q15, diffw_Q24, sum_error_Q24, pred_Q24; + const opus_int16 *w_Q9_ptr; + const opus_uint8 *cb_Q8_ptr; + + celt_assert( ( LPC_order & 1 ) == 0 ); + + /* Loop over codebook */ + cb_Q8_ptr = pCB_Q8; + w_Q9_ptr = pWght_Q9; + for( i = 0; i < K; i++ ) { + sum_error_Q24 = 0; + pred_Q24 = 0; + for( m = LPC_order-2; m >= 0; m -= 2 ) { + /* Compute weighted absolute predictive quantization error for index m + 1 */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m + 1 ], (opus_int32)cb_Q8_ptr[ m + 1 ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m + 1 ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + /* Compute weighted absolute predictive quantization error for index m */ + diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)cb_Q8_ptr[ m ], 7 ); /* range: [ -32767 : 32767 ]*/ + diffw_Q24 = silk_SMULBB( diff_Q15, w_Q9_ptr[ m ] ); + sum_error_Q24 = silk_ADD32( sum_error_Q24, silk_abs( silk_SUB_RSHIFT32( diffw_Q24, pred_Q24, 1 ) ) ); + pred_Q24 = diffw_Q24; + + silk_assert( sum_error_Q24 >= 0 ); + } + err_Q24[ i ] = sum_error_Q24; + cb_Q8_ptr += LPC_order; + w_Q9_ptr += LPC_order; + } +} diff --git a/src/libopus/silk/NLSF_VQ_weights_laroia.c b/src/libopus/silk/NLSF_VQ_weights_laroia.c new file mode 100644 index 00000000..387e62da --- /dev/null +++ b/src/libopus/silk/NLSF_VQ_weights_laroia.c @@ -0,0 +1,80 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "define.h" +#include "SigProc_FIX.h" + +/* +R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP +Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech, +Signal Processing, pp. 641-644, 1991. +*/ + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +) +{ + opus_int k; + opus_int32 tmp1_int, tmp2_int; + + celt_assert( D > 0 ); + celt_assert( ( D & 1 ) == 0 ); + + /* First value */ + tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 ); + + /* Main loop */ + for( k = 1; k < D - 1; k += 2 ) { + tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k ] > 0 ); + + tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 ); + tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int ); + pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 ); + } + + /* Last value */ + tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 ); + tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int ); + pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX ); + silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 ); +} diff --git a/src/libopus/silk/NLSF_decode.c b/src/libopus/silk/NLSF_decode.c new file mode 100644 index 00000000..87a57e13 --- /dev/null +++ b/src/libopus/silk/NLSF_decode.c @@ -0,0 +1,93 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Predictive dequantizer for NLSF residuals */ +static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */ + opus_int16 x_Q10[], /* O Output [ order ] */ + const opus_int8 indices[], /* I Quantization indices [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, out_Q10, pred_Q10; + + out_Q10 = 0; + for( i = order-1; i >= 0; i-- ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 ); + out_Q10 = silk_LSHIFT( indices[ i ], 10 ); + if( out_Q10 > 0 ) { + out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( out_Q10 < 0 ) { + out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out_Q10 = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 ); + x_Q10[ i ] = out_Q10; + } +} + + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +) +{ + opus_int i; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int32 NLSF_Q15_tmp; + const opus_uint8 *pCB_element; + const opus_int16 *pCB_Wght_Q9; + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] ); + + /* Predictive residual dequantizer */ + silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order ); + + /* Apply inverse square-rooted weights to first stage and add to output */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ NLSFIndices[ 0 ] * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_Q15_tmp = silk_ADD_LSHIFT32( silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), pCB_Wght_Q9[ i ] ), (opus_int16)pCB_element[ i ], 7 ); + pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 ); + } + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); +} diff --git a/src/libopus/silk/NLSF_del_dec_quant.c b/src/libopus/silk/NLSF_del_dec_quant.c new file mode 100644 index 00000000..32f747d6 --- /dev/null +++ b/src/libopus/silk/NLSF_del_dec_quant.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +) +{ + opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10; + opus_int pred_Q10, diff_Q10, rate0_Q5, rate1_Q5; + opus_int16 out0_Q10, out1_Q10; + opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25; + opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ]; + opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ]; + const opus_uint8 *rates_Q5; + + opus_int out0_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + opus_int out1_Q10_table[2 * NLSF_QUANT_MAX_AMPLITUDE_EXT]; + + for (i = -NLSF_QUANT_MAX_AMPLITUDE_EXT; i <= NLSF_QUANT_MAX_AMPLITUDE_EXT-1; i++) + { + out0_Q10 = silk_LSHIFT( i, 10 ); + out1_Q10 = silk_ADD16( out0_Q10, 1024 ); + if( i > 0 ) { + out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == 0 ) { + out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else if( i == -1 ) { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } else { + out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) ); + } + out0_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out0_Q10, quant_step_size_Q16 ), 16 ); + out1_Q10_table[ i + NLSF_QUANT_MAX_AMPLITUDE_EXT ] = silk_RSHIFT( silk_SMULBB( out1_Q10, quant_step_size_Q16 ), 16 ); + } + + silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */ + + nStates = 1; + RD_Q25[ 0 ] = 0; + prev_out_Q10[ 0 ] = 0; + for( i = order - 1; i >= 0; i-- ) { + rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ]; + in_Q10 = x_Q10[ i ]; + for( j = 0; j < nStates; j++ ) { + pred_Q10 = silk_RSHIFT( silk_SMULBB( (opus_int16)pred_coef_Q8[ i ], prev_out_Q10[ j ] ), 8 ); + res_Q10 = silk_SUB16( in_Q10, pred_Q10 ); + ind_tmp = silk_RSHIFT( silk_SMULBB( inv_quant_step_size_Q6, res_Q10 ), 16 ); + ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 ); + ind[ j ][ i ] = (opus_int8)ind_tmp; + + /* compute outputs for ind_tmp and ind_tmp + 1 */ + out0_Q10 = out0_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + out1_Q10 = out1_Q10_table[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE_EXT ]; + + out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 ); + out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 ); + prev_out_Q10[ j ] = out0_Q10; + prev_out_Q10[ j + nStates ] = out1_Q10; + + /* compute RD for ind_tmp and ind_tmp + 1 */ + if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = 280; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp ); + rate1_Q5 = silk_ADD16( rate0_Q5, 43 ); + } + } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) { + if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) { + rate0_Q5 = 280; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } else { + rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp ); + rate1_Q5 = silk_SUB16( rate0_Q5, 43 ); + } + } else { + rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ]; + rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ]; + } + RD_tmp_Q25 = RD_Q25[ j ]; + diff_Q10 = silk_SUB16( in_Q10, out0_Q10 ); + RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 ); + diff_Q10 = silk_SUB16( in_Q10, out1_Q10 ); + RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 ); + } + + if( nStates <= NLSF_QUANT_DEL_DEC_STATES/2 ) { + /* double number of states and copy */ + for( j = 0; j < nStates; j++ ) { + ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1; + } + nStates = silk_LSHIFT( nStates, 1 ); + for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] = ind[ j - nStates ][ i ]; + } + } else { + /* sort lower and upper half of RD_Q25, pairwise */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) { + RD_max_Q25[ j ] = RD_Q25[ j ]; + RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + RD_Q25[ j ] = RD_min_Q25[ j ]; + RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ]; + /* swap prev_out values */ + out0_Q10 = prev_out_Q10[ j ]; + prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10; + ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES; + } else { + RD_min_Q25[ j ] = RD_Q25[ j ]; + RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ]; + ind_sort[ j ] = j; + } + } + /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */ + /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */ + while( 1 ) { + min_max_Q25 = silk_int32_MAX; + max_min_Q25 = 0; + ind_min_max = 0; + ind_max_min = 0; + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_max_Q25 > RD_max_Q25[ j ] ) { + min_max_Q25 = RD_max_Q25[ j ]; + ind_min_max = j; + } + if( max_min_Q25 < RD_min_Q25[ j ] ) { + max_min_Q25 = RD_min_Q25[ j ]; + ind_max_min = j; + } + } + if( min_max_Q25 >= max_min_Q25 ) { + break; + } + /* copy ind_min_max to ind_max_min */ + ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES; + RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ]; + RD_min_Q25[ ind_max_min ] = 0; + RD_max_Q25[ ind_min_max ] = silk_int32_MAX; + silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) ); + } + /* increment index if it comes from the upper half */ + for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) { + ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + } + } + } + + /* last sample: find winner, copy indices and return RD value */ + ind_tmp = 0; + min_Q25 = silk_int32_MAX; + for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) { + if( min_Q25 > RD_Q25[ j ] ) { + min_Q25 = RD_Q25[ j ]; + ind_tmp = j; + } + } + for( j = 0; j < order; j++ ) { + indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ]; + silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + } + indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 ); + silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT ); + silk_assert( min_Q25 >= 0 ); + return min_Q25; +} diff --git a/src/libopus/silk/NLSF_encode.c b/src/libopus/silk/NLSF_encode.c new file mode 100644 index 00000000..8aabe752 --- /dev/null +++ b/src/libopus/silk/NLSF_encode.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" + +/***********************/ +/* NLSF vector encoder */ +/***********************/ +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O (Un)quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_Q2, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +) +{ + opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7; + opus_int32 W_tmp_Q9, ret; + VARDECL( opus_int32, err_Q24 ); + VARDECL( opus_int32, RD_Q25 ); + VARDECL( opus_int, tempIndices1 ); + VARDECL( opus_int8, tempIndices2 ); + opus_int16 res_Q10[ MAX_LPC_ORDER ]; + opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ]; + opus_int16 W_adj_Q5[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + const opus_uint8 *pCB_element, *iCDF_ptr; + const opus_int16 *pCB_Wght_Q9; + SAVE_STACK; + + celt_assert( signalType >= 0 && signalType <= 2 ); + silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 ); + + /* NLSF stabilization */ + silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order ); + + /* First stage: VQ */ + ALLOC( err_Q24, psNLSF_CB->nVectors, opus_int32 ); + silk_NLSF_VQ( err_Q24, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->CB1_Wght_Q9, psNLSF_CB->nVectors, psNLSF_CB->order ); + + /* Sort the quantization errors */ + ALLOC( tempIndices1, nSurvivors, opus_int ); + silk_insertion_sort_increasing( err_Q24, tempIndices1, psNLSF_CB->nVectors, nSurvivors ); + + ALLOC( RD_Q25, nSurvivors, opus_int32 ); + ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 ); + + /* Loop over survivors */ + for( s = 0; s < nSurvivors; s++ ) { + ind1 = tempIndices1[ s ]; + + /* Residual after first stage */ + pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ]; + pCB_Wght_Q9 = &psNLSF_CB->CB1_Wght_Q9[ ind1 * psNLSF_CB->order ]; + for( i = 0; i < psNLSF_CB->order; i++ ) { + NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 ); + W_tmp_Q9 = pCB_Wght_Q9[ i ]; + res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ], W_tmp_Q9 ), 14 ); + W_adj_Q5[ i ] = silk_DIV32_varQ( (opus_int32)pW_Q2[ i ], silk_SMULBB( W_tmp_Q9, W_tmp_Q9 ), 21 ); + } + + /* Unpack entropy table indices and predictor for current CB1 index */ + silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 ); + + /* Trellis quantizer */ + RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix, + psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order ); + + /* Add rate for first stage */ + iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ]; + if( ind1 == 0 ) { + prob_Q8 = 256 - iCDF_ptr[ ind1 ]; + } else { + prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ]; + } + bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 ); + RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) ); + } + + /* Find the lowest rate-distortion error */ + silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 ); + + NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ]; + silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) ); + + /* Decode */ + silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB ); + + ret = RD_Q25[ 0 ]; + RESTORE_STACK; + return ret; +} diff --git a/src/libopus/silk/NLSF_stabilize.c b/src/libopus/silk/NLSF_stabilize.c new file mode 100644 index 00000000..b7530db1 --- /dev/null +++ b/src/libopus/silk/NLSF_stabilize.c @@ -0,0 +1,142 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +/* NLSF stabilizer: */ +/* */ +/* - Moves NLSFs further apart if they are too close */ +/* - Moves NLSFs away from borders if they are too close */ +/* - High effort to achieve a modification with minimum */ +/* Euclidean distance to input vector */ +/* - Output are sorted NLSF coefficients */ +/* */ + +#include "SigProc_FIX.h" + +/* Constant Definitions */ +#define MAX_LOOPS 20 + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +) +{ + opus_int i, I=0, k, loops; + opus_int16 center_freq_Q15; + opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15; + + /* This is necessary to ensure an output within range of a opus_int16 */ + silk_assert( NDeltaMin_Q15[L] >= 1 ); + + for( loops = 0; loops < MAX_LOOPS; loops++ ) { + /**************************/ + /* Find smallest distance */ + /**************************/ + /* First element */ + min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0]; + I = 0; + /* Middle elements */ + for( i = 1; i <= L-1; i++ ) { + diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = i; + } + } + /* Last element */ + diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] ); + if( diff_Q15 < min_diff_Q15 ) { + min_diff_Q15 = diff_Q15; + I = L; + } + + /***************************************************/ + /* Now check if the smallest distance non-negative */ + /***************************************************/ + if( min_diff_Q15 >= 0 ) { + return; + } + + if( I == 0 ) { + /* Move away from lower limit */ + NLSF_Q15[0] = NDeltaMin_Q15[0]; + + } else if( I == L) { + /* Move away from higher limit */ + NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L]; + + } else { + /* Find the lower extreme for the location of the current center frequency */ + min_center_Q15 = 0; + for( k = 0; k < I; k++ ) { + min_center_Q15 += NDeltaMin_Q15[k]; + } + min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Find the upper extreme for the location of the current center frequency */ + max_center_Q15 = 1 << 15; + for( k = L; k > I; k-- ) { + max_center_Q15 -= NDeltaMin_Q15[k]; + } + max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + + /* Move apart, sorted by value, keeping the same center frequency */ + center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ), + min_center_Q15, max_center_Q15 ); + NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 ); + NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I]; + } + } + + /* Safe and simple fall back method, which is less ideal than the above */ + if( loops == MAX_LOOPS ) + { + /* Insertion sort (fast for already almost sorted arrays): */ + /* Best case: O(n) for an already sorted array */ + /* Worst case: O(n^2) for an inversely sorted array */ + silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L ); + + /* First NLSF should be no less than NDeltaMin[0] */ + NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] ); + + /* Keep delta_min distance between the NLSFs */ + for( i = 1; i < L; i++ ) + NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], silk_ADD_SAT16( NLSF_Q15[i-1], NDeltaMin_Q15[i] ) ); + + /* Last NLSF should be no higher than 1 - NDeltaMin[L] */ + NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] ); + + /* Keep NDeltaMin distance between the NLSFs */ + for( i = L-2; i >= 0; i-- ) + NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] ); + } +} diff --git a/src/libopus/silk/NLSF_unpack.c b/src/libopus/silk/NLSF_unpack.c new file mode 100644 index 00000000..bf3b047a --- /dev/null +++ b/src/libopus/silk/NLSF_unpack.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +) +{ + opus_int i; + opus_uint8 entry; + const opus_uint8 *ec_sel_ptr; + + ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ]; + for( i = 0; i < psNLSF_CB->order; i += 2 ) { + entry = *ec_sel_ptr++; + ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ]; + ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 ); + pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ]; + } +} + diff --git a/src/libopus/silk/NSQ.c b/src/libopus/silk/NSQ.c new file mode 100644 index 00000000..a5f085df --- /dev/null +++ b/src/libopus/silk/NSQ.c @@ -0,0 +1,437 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" +#include "NSQ.h" + + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +); + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +); +#endif + +void silk_NSQ_c +( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int k, lag, start_idx, LSF_interpolation_flag; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + SAVE_STACK; + + NSQ->rand_seed = psIndices->Seed; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + /* Set up pointers to start of sub frame */ + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->rewhite_flag = 1; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + } + } + + silk_nsq_scale_states( psEncC, NSQ, x16, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType ); + + silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14, + AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10, + offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Update lagPrev for next frame */ + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech and noise shaping signals */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/***********************************/ +/* silk_noise_shape_quantizer */ +/***********************************/ + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_noise_shape_quantizer( + silk_nsq_state *NSQ, /* I/O NSQ state */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_sc_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP state */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int shapingLPCOrder, /* I Noise shaping AR filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + int arch /* I Architecture */ +) +{ + opus_int i; + opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13; + opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20; + opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + + /* Set up short term AR state */ + psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ]; + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Generate dither */ + NSQ->rand_seed = silk_RAND( NSQ->rand_seed ); + + /* Short-term prediction */ + LPC_pred_Q10 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + pred_lag_ptr++; + } else { + LTP_pred_Q13 = 0; + } + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + n_AR_Q12 = silk_NSQ_noise_shape_feedback_loop(&NSQ->sDiff_shp_Q14, NSQ->sAR2_Q14, AR_shp_Q13, shapingLPCOrder, arch); + + n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 ); + + n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 ); + n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 ); + + celt_assert( lag > 0 || signalType != TYPE_VOICED ); + + /* Combine prediction and noise shaping signals */ + tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */ + tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 ); + shp_lag_ptr++; + + tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */ + tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */ + } else { + tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */ + } + + r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if( NSQ->rand_seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* Q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 ); + + if( rd2_Q20 < rd1_Q20 ) { + q1_Q10 = q2_Q10; + } + + pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 ); + + /* Excitation */ + exc_Q14 = silk_LSHIFT( q1_Q10, 4 ); + if ( NSQ->rand_seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 ); + xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 ); + + /* Scale XQ back to normal level before saving */ + xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) ); + + /* Update states */ + psLPC_Q14++; + *psLPC_Q14 = xq_Q14; + NSQ->sDiff_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_sc_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( NSQ->sDiff_shp_Q14, n_AR_Q12, 2 ); + NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14; + + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 ); + sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 ); + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Make dither dependent on quantized signal */ + NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] ); + } + + /* Update LPC synth buffer */ + silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); +} + +static OPUS_INLINE void silk_nsq_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + const opus_int16 x16[], /* I input */ + opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */ + const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I subframe number */ + const opus_int LTP_scale_Q14, /* I */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type /* I Signal type */ +) +{ + opus_int i, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 ); + NSQ->sDiff_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sDiff_shp_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] ); + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/src/libopus/silk/NSQ.h b/src/libopus/silk/NSQ.h new file mode 100644 index 00000000..971832f6 --- /dev/null +++ b/src/libopus/silk/NSQ.h @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2014 Vidyo. +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ +#ifndef SILK_NSQ_H +#define SILK_NSQ_H + +#include "SigProc_FIX.h" + +#undef silk_short_prediction_create_arch_coef + +static OPUS_INLINE opus_int32 silk_noise_shape_quantizer_short_prediction_c(const opus_int32 *buf32, const opus_int16 *coef16, opus_int order) +{ + opus_int32 out; + silk_assert( order == 10 || order == 16 ); + + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + out = silk_RSHIFT( order, 1 ); + out = silk_SMLAWB( out, buf32[ 0 ], coef16[ 0 ] ); + out = silk_SMLAWB( out, buf32[ -1 ], coef16[ 1 ] ); + out = silk_SMLAWB( out, buf32[ -2 ], coef16[ 2 ] ); + out = silk_SMLAWB( out, buf32[ -3 ], coef16[ 3 ] ); + out = silk_SMLAWB( out, buf32[ -4 ], coef16[ 4 ] ); + out = silk_SMLAWB( out, buf32[ -5 ], coef16[ 5 ] ); + out = silk_SMLAWB( out, buf32[ -6 ], coef16[ 6 ] ); + out = silk_SMLAWB( out, buf32[ -7 ], coef16[ 7 ] ); + out = silk_SMLAWB( out, buf32[ -8 ], coef16[ 8 ] ); + out = silk_SMLAWB( out, buf32[ -9 ], coef16[ 9 ] ); + + if( order == 16 ) + { + out = silk_SMLAWB( out, buf32[ -10 ], coef16[ 10 ] ); + out = silk_SMLAWB( out, buf32[ -11 ], coef16[ 11 ] ); + out = silk_SMLAWB( out, buf32[ -12 ], coef16[ 12 ] ); + out = silk_SMLAWB( out, buf32[ -13 ], coef16[ 13 ] ); + out = silk_SMLAWB( out, buf32[ -14 ], coef16[ 14 ] ); + out = silk_SMLAWB( out, buf32[ -15 ], coef16[ 15 ] ); + } + return out; +} + +#define silk_noise_shape_quantizer_short_prediction(in, coef, coefRev, order, arch) ((void)arch,silk_noise_shape_quantizer_short_prediction_c(in, coef, order)) + +static OPUS_INLINE opus_int32 silk_NSQ_noise_shape_feedback_loop_c(const opus_int32 *data0, opus_int32 *data1, const opus_int16 *coef, opus_int order) +{ + opus_int32 out; + opus_int32 tmp1, tmp2; + opus_int j; + + tmp2 = data0[0]; + tmp1 = data1[0]; + data1[0] = tmp2; + + out = silk_RSHIFT(order, 1); + out = silk_SMLAWB(out, tmp2, coef[0]); + + for (j = 2; j < order; j += 2) { + tmp2 = data1[j - 1]; + data1[j - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[j - 1]); + tmp1 = data1[j + 0]; + data1[j + 0] = tmp2; + out = silk_SMLAWB(out, tmp2, coef[j]); + } + data1[order - 1] = tmp1; + out = silk_SMLAWB(out, tmp1, coef[order - 1]); + /* Q11 -> Q12 */ + out = silk_LSHIFT32( out, 1 ); + return out; +} + +#define silk_NSQ_noise_shape_feedback_loop(data0, data1, coef, order, arch) ((void)arch,silk_NSQ_noise_shape_feedback_loop_c(data0, data1, coef, order)) + +#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) +#include "arm/NSQ_neon.h" +#endif + +#endif /* SILK_NSQ_H */ diff --git a/src/libopus/silk/NSQ_del_dec.c b/src/libopus/silk/NSQ_del_dec.c new file mode 100644 index 00000000..5af56793 --- /dev/null +++ b/src/libopus/silk/NSQ_del_dec.c @@ -0,0 +1,733 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" +#include "NSQ.h" + + +typedef struct { + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 RandState[ DECISION_DELAY ]; + opus_int32 Q_Q10[ DECISION_DELAY ]; + opus_int32 Xq_Q14[ DECISION_DELAY ]; + opus_int32 Pred_Q15[ DECISION_DELAY ]; + opus_int32 Shape_Q14[ DECISION_DELAY ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 Seed; + opus_int32 SeedInit; + opus_int32 RD_Q10; +} NSQ_del_dec_struct; + +typedef struct { + opus_int32 Q_Q10; + opus_int32 RD_Q10; + opus_int32 xq_Q14; + opus_int32 LF_AR_Q14; + opus_int32 Diff_Q14; + opus_int32 sLTP_shp_Q14; + opus_int32 LPC_exc_Q14; +} NSQ_sample_struct; + +typedef NSQ_sample_struct NSQ_sample_pair[ 2 ]; + +#if defined(MIPSr1_ASM) +#include "mips/NSQ_del_dec_mipsr1.h" +#endif +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +); + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +); + +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +) +{ + opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr; + opus_int last_smple_idx, smpl_buf_idx, decisionDelay; + const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13; + opus_int16 *pxq; + VARDECL( opus_int32, sLTP_Q15 ); + VARDECL( opus_int16, sLTP ); + opus_int32 HarmShapeFIRPacked_Q14; + opus_int offset_Q10; + opus_int32 RDmin_Q10, Gain_Q10; + VARDECL( opus_int32, x_sc_Q10 ); + VARDECL( opus_int32, delayedGain_Q10 ); + VARDECL( NSQ_del_dec_struct, psDelDec ); + NSQ_del_dec_struct *psDD; + SAVE_STACK; + + /* Set unvoiced lag to the previous one, overwrite later for voiced */ + lag = NSQ->lagPrev; + + silk_assert( NSQ->prev_gain_Q16 != 0 ); + + /* Initialize delayed decision states */ + ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct ); + silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) ); + for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psDD->Seed = ( k + psIndices->Seed ) & 3; + psDD->SeedInit = psDD->Seed; + psDD->RD_Q10 = 0; + psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14; + psDD->Diff_Q14 = NSQ->sDiff_shp_Q14; + psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ]; + silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) ); + } + + offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ]; + smpl_buf_idx = 0; /* index of oldest samples */ + + decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length ); + + /* For voiced frames limit the decision delay to lower than the pitch lag */ + if( psIndices->signalType == TYPE_VOICED ) { + for( k = 0; k < psEncC->nb_subfr; k++ ) { + decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 ); + } + } else { + if( lag > 0 ) { + decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 ); + } + } + + if( psIndices->NLSFInterpCoef_Q2 == 4 ) { + LSF_interpolation_flag = 0; + } else { + LSF_interpolation_flag = 1; + } + + ALLOC( sLTP_Q15, psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 ); + ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 ); + ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 ); + ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 ); + /* Set up pointers to start of sub frame */ + pxq = &NSQ->xq[ psEncC->ltp_mem_length ]; + NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length; + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + subfr = 0; + for( k = 0; k < psEncC->nb_subfr; k++ ) { + A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ]; + B_Q14 = <PCoef_Q14[ k * LTP_ORDER ]; + AR_shp_Q13 = &AR_Q13[ k * MAX_SHAPE_LPC_ORDER ]; + + /* Noise shape parameters */ + silk_assert( HarmShapeGain_Q14[ k ] >= 0 ); + HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 ); + HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 ); + + NSQ->rewhite_flag = 0; + if( psIndices->signalType == TYPE_VOICED ) { + /* Voiced */ + lag = pitchL[ k ]; + + /* Re-whitening */ + if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) { + if( k == 2 ) { + /* RESET DELAYED DECISIONS */ + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) { + if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ i ].RD_Q10; + Winner_ind = i; + } + } + for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) { + if( i != Winner_ind ) { + psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 ); + silk_assert( psDelDec[ i ].RD_Q10 >= 0 ); + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + last_smple_idx = smpl_buf_idx + decisionDelay; + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + + subfr = 0; + } + + /* Rewhiten with new A coefs */ + start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ], + A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder, psEncC->arch ); + + NSQ->sLTP_buf_idx = psEncC->ltp_mem_length; + NSQ->rewhite_flag = 1; + } + } + + silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x16, x_sc_Q10, sLTP, sLTP_Q15, k, + psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay ); + + silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, + delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], + Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder, + psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay, psEncC->arch ); + + x16 += psEncC->subfr_length; + pulses += psEncC->subfr_length; + pxq += psEncC->subfr_length; + } + + /* Find winner */ + RDmin_Q10 = psDelDec[ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psDelDec[ k ].RD_Q10; + Winner_ind = k; + } + } + + /* Copy final part of signals from winner state to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + psIndices->Seed = psDD->SeedInit; + last_smple_idx = smpl_buf_idx + decisionDelay; + Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 ); + for( i = 0; i < decisionDelay; i++ ) { + last_smple_idx = ( last_smple_idx - 1 ) % DECISION_DELAY; + if( last_smple_idx < 0 ) last_smple_idx += DECISION_DELAY; + + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ]; + } + silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) ); + + /* Update states */ + NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14; + NSQ->sDiff_shp_Q14 = psDD->Diff_Q14; + NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ]; + + /* Save quantized speech signal */ + silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) ); + silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) ); + RESTORE_STACK; +} + +/******************************************/ +/* Noise shape quantizer for one subframe */ +/******************************************/ +#ifndef OVERRIDE_silk_noise_shape_quantizer_del_dec +static OPUS_INLINE void silk_noise_shape_quantizer_del_dec( + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + opus_int signalType, /* I Signal type */ + const opus_int32 x_Q10[], /* I */ + opus_int8 pulses[], /* O */ + opus_int16 xq[], /* O */ + opus_int32 sLTP_Q15[], /* I/O LTP filter state */ + opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */ + const opus_int16 a_Q12[], /* I Short term prediction coefs */ + const opus_int16 b_Q14[], /* I Long term prediction coefs */ + const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */ + opus_int lag, /* I Pitch lag */ + opus_int32 HarmShapeFIRPacked_Q14, /* I */ + opus_int Tilt_Q14, /* I Spectral tilt */ + opus_int32 LF_shp_Q14, /* I */ + opus_int32 Gain_Q16, /* I */ + opus_int Lambda_Q10, /* I */ + opus_int offset_Q10, /* I */ + opus_int length, /* I Input length */ + opus_int subfr, /* I Subframe number */ + opus_int shapingLPCOrder, /* I Shaping LPC filter order */ + opus_int predictLPCOrder, /* I Prediction filter order */ + opus_int warping_Q16, /* I */ + opus_int nStatesDelayedDecision, /* I Number of states in decision tree */ + opus_int *smpl_buf_idx, /* I/O Index to newest samples in buffers */ + opus_int decisionDelay, /* I */ + int arch /* I */ +) +{ + opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx; + opus_int32 Winner_rand_state; + opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14; + opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10; + opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10; + opus_int32 tmp1, tmp2, sLF_AR_shp_Q14; + opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14; +#ifdef silk_short_prediction_create_arch_coef + opus_int32 a_Q12_arch[MAX_LPC_ORDER]; +#endif + + VARDECL( NSQ_sample_pair, psSampleState ); + NSQ_del_dec_struct *psDD; + NSQ_sample_struct *psSS; + SAVE_STACK; + + celt_assert( nStatesDelayedDecision > 0 ); + ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair ); + + shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ]; + pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 ); + +#ifdef silk_short_prediction_create_arch_coef + silk_short_prediction_create_arch_coef(a_Q12_arch, a_Q12, predictLPCOrder); +#endif + + for( i = 0; i < length; i++ ) { + /* Perform common calculations used in all states */ + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q14 = 2; + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] ); + LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] ); + LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */ + pred_lag_ptr++; + } else { + LTP_pred_Q14 = 0; + } + + /* Long-term shaping */ + if( lag > 0 ) { + /* Symmetric, packed FIR coefficients */ + n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 ); + n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */ + shp_lag_ptr++; + } else { + n_LTP_Q14 = 0; + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + /* Delayed decision state */ + psDD = &psDelDec[ k ]; + + /* Sample state */ + psSS = psSampleState[ k ]; + + /* Generate dither */ + psDD->Seed = silk_RAND( psDD->Seed ); + + /* Pointer used in short term prediction and shaping */ + psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ]; + /* Short-term prediction */ + LPC_pred_Q14 = silk_noise_shape_quantizer_short_prediction(psLPC_Q14, a_Q12, a_Q12_arch, predictLPCOrder, arch); + LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */ + + /* Noise shape feedback */ + celt_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */ + /* Output of lowpass section */ + tmp2 = silk_SMLAWB( psDD->Diff_Q14, psDD->sAR2_Q14[ 0 ], warping_Q16 ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ 0 ] = tmp2; + n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 ); + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] ); + /* Loop over allpass sections */ + for( j = 2; j < shapingLPCOrder; j += 2 ) { + /* Output of allpass section */ + tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 ); + psDD->sAR2_Q14[ j - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] ); + /* Output of allpass section */ + tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 ); + psDD->sAR2_Q14[ j + 0 ] = tmp2; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] ); + } + psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1; + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] ); + + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */ + n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */ + n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */ + + n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */ + n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */ + + /* Input minus prediction plus noise feedback */ + /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */ + tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */ + tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */ + tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */ + tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */ + + r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */ + + /* Flip sign depending on dither */ + if ( psDD->Seed < 0 ) { + r_Q10 = -r_Q10; + } + r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 ); + + /* Find two quantization level candidates and measure their rate-distortion */ + q1_Q10 = silk_SUB32( r_Q10, offset_Q10 ); + q1_Q0 = silk_RSHIFT( q1_Q10, 10 ); + if (Lambda_Q10 > 2048) { + /* For aggressive RDO, the bias becomes more than one pulse. */ + int rdo_offset = Lambda_Q10/2 - 512; + if (q1_Q10 > rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 - rdo_offset, 10 ); + } else if (q1_Q10 < -rdo_offset) { + q1_Q0 = silk_RSHIFT( q1_Q10 + rdo_offset, 10 ); + } else if (q1_Q10 < 0) { + q1_Q0 = -1; + } else { + q1_Q0 = 0; + } + } + if( q1_Q0 > 0 ) { + q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == 0 ) { + q1_Q10 = offset_Q10; + q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else if( q1_Q0 == -1 ) { + q2_Q10 = offset_Q10; + q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 ); + } else { /* q1_Q0 < -1 */ + q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 ); + q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 ); + q2_Q10 = silk_ADD32( q1_Q10, 1024 ); + rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 ); + rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 ); + } + rr_Q10 = silk_SUB32( r_Q10, q1_Q10 ); + rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 ); + rr_Q10 = silk_SUB32( r_Q10, q2_Q10 ); + rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 ); + + if( rd1_Q10 < rd2_Q10 ) { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 0 ].Q_Q10 = q1_Q10; + psSS[ 1 ].Q_Q10 = q2_Q10; + } else { + psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 ); + psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 ); + psSS[ 0 ].Q_Q10 = q2_Q10; + psSS[ 1 ].Q_Q10 = q1_Q10; + } + + /* Update states for best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 0 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 0 ].Diff_Q14, n_AR_Q14 ); + psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 0 ].xq_Q14 = xq_Q14; + + /* Update states for second best quantization */ + + /* Quantized excitation */ + exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 ); + if ( psDD->Seed < 0 ) { + exc_Q14 = -exc_Q14; + } + + /* Add predictions */ + LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 ); + xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 ); + + /* Update states */ + psSS[ 1 ].Diff_Q14 = silk_SUB_LSHIFT32( xq_Q14, x_Q10[ i ], 4 ); + sLF_AR_shp_Q14 = silk_SUB32( psSS[ 1 ].Diff_Q14, n_AR_Q14 ); + psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 ); + psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14; + psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14; + psSS[ 1 ].xq_Q14 = xq_Q14; + } + + *smpl_buf_idx = ( *smpl_buf_idx - 1 ) % DECISION_DELAY; + if( *smpl_buf_idx < 0 ) *smpl_buf_idx += DECISION_DELAY; + last_smple_idx = ( *smpl_buf_idx + decisionDelay ) % DECISION_DELAY; + + /* Find winner */ + RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + Winner_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + Winner_ind = k; + } + } + + /* Increase RD values of expired states */ + Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ]; + for( k = 0; k < nStatesDelayedDecision; k++ ) { + if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) { + psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 ); + psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 ); + silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 ); + } + } + + /* Find worst in first set and best in second set */ + RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10; + RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10; + RDmax_ind = 0; + RDmin_ind = 0; + for( k = 1; k < nStatesDelayedDecision; k++ ) { + /* find worst in first set */ + if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) { + RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10; + RDmax_ind = k; + } + /* find best in second set */ + if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) { + RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10; + RDmin_ind = k; + } + } + + /* Replace a state if best from second set outperforms worst in first set */ + if( RDmin_Q10 < RDmax_Q10 ) { + silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i, + ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) ); + silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) ); + } + + /* Write samples from winner to output and long-term filter states */ + psDD = &psDelDec[ Winner_ind ]; + if( subfr > 0 || i >= decisionDelay ) { + pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 ); + xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( + silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) ); + NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ]; + sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ]; + } + NSQ->sLTP_shp_buf_idx++; + NSQ->sLTP_buf_idx++; + + /* Update states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + psSS = &psSampleState[ k ][ 0 ]; + psDD->LF_AR_Q14 = psSS->LF_AR_Q14; + psDD->Diff_Q14 = psSS->Diff_Q14; + psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14; + psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14; + psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10; + psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 ); + psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14; + psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) ); + psDD->RandState[ *smpl_buf_idx ] = psDD->Seed; + psDD->RD_Q10 = psSS->RD_Q10; + } + delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10; + } + /* Update LPC states */ + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_quantizer_del_dec */ + +static OPUS_INLINE void silk_nsq_del_dec_scale_states( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */ + const opus_int16 x16[], /* I Input */ + opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */ + const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */ + opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */ + opus_int subfr, /* I Subframe number */ + opus_int nStatesDelayedDecision, /* I Number of del dec states */ + const opus_int LTP_scale_Q14, /* I LTP state scaling */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */ + const opus_int signal_type, /* I Signal type */ + const opus_int decisionDelay /* I Decision delay */ +) +{ + opus_int i, k, lag; + opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q26; + NSQ_del_dec_struct *psDD; + + lag = pitchL[ subfr ]; + inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 ); + silk_assert( inv_gain_Q31 != 0 ); + + /* Scale input */ + inv_gain_Q26 = silk_RSHIFT_ROUND( inv_gain_Q31, 5 ); + for( i = 0; i < psEncC->subfr_length; i++ ) { + x_sc_Q10[ i ] = silk_SMULWW( x16[ i ], inv_gain_Q26 ); + } + + /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */ + if( NSQ->rewhite_flag ) { + if( subfr == 0 ) { + /* Do LTP downscaling */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 ); + } + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) { + silk_assert( i < MAX_FRAME_LENGTH ); + sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] ); + } + } + + /* Adjust for changing gain */ + if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 ); + + /* Scale long-term shaping state */ + for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) { + NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] ); + } + + /* Scale long-term prediction state */ + if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) { + for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) { + sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] ); + } + } + + for( k = 0; k < nStatesDelayedDecision; k++ ) { + psDD = &psDelDec[ k ]; + + /* Scale scalar states */ + psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 ); + psDD->Diff_Q14 = silk_SMULWW( gain_adj_Q16, psDD->Diff_Q14 ); + + /* Scale short-term prediction and shaping states */ + for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) { + psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] ); + } + for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) { + psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] ); + } + for( i = 0; i < DECISION_DELAY; i++ ) { + psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] ); + psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] ); + } + } + + /* Save inverse gain */ + NSQ->prev_gain_Q16 = Gains_Q16[ subfr ]; + } +} diff --git a/src/libopus/silk/PLC.c b/src/libopus/silk/PLC.c new file mode 100644 index 00000000..fc2f09e1 --- /dev/null +++ b/src/libopus/silk/PLC.c @@ -0,0 +1,448 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" +#include "PLC.h" + +#define NB_ATT 2 +static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */ +static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */ +static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */ + +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +); + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +); + + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +) +{ + psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 ); + psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 ); + psDec->sPLC.subfr_length = 20; + psDec->sPLC.nb_subfr = 2; +} + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +) +{ + /* PLC control function */ + if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) { + silk_PLC_Reset( psDec ); + psDec->sPLC.fs_kHz = psDec->fs_kHz; + } + + if( lost ) { + /****************************/ + /* Generate Signal */ + /****************************/ + silk_PLC_conceal( psDec, psDecCtrl, frame, arch ); + + psDec->lossCnt++; + } else { + /****************************/ + /* Update state */ + /****************************/ + silk_PLC_update( psDec, psDecCtrl ); + } +} + +/**************************************************/ +/* Update state of PLC */ +/**************************************************/ +static OPUS_INLINE void silk_PLC_update( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl /* I/O Decoder control */ +) +{ + opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14; + opus_int i, j; + silk_PLC_struct *psPLC; + + psPLC = &psDec->sPLC; + + /* Update parameters used in case of packet loss */ + psDec->prevSignalType = psDec->indices.signalType; + LTP_Gain_Q14 = 0; + if( psDec->indices.signalType == TYPE_VOICED ) { + /* Find the parameters for the last subframe which contains a pitch pulse */ + for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) { + if( j == psDec->nb_subfr ) { + break; + } + temp_LTP_Gain_Q14 = 0; + for( i = 0; i < LTP_ORDER; i++ ) { + temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ]; + } + if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) { + LTP_Gain_Q14 = temp_LTP_Gain_Q14; + silk_memcpy( psPLC->LTPCoef_Q14, + &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ], + LTP_ORDER * sizeof( opus_int16 ) ); + + psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 ); + } + } + + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14; + + /* Limit LT coefs */ + if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) { + opus_int scale_Q10; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 ); + scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 ); + } + } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) { + opus_int scale_Q14; + opus_int32 tmp; + + tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 ); + scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) ); + for( i = 0; i < LTP_ORDER; i++ ) { + psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 ); + } + } + } else { + psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 ); + silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 )); + } + + /* Save LPC coeficients */ + silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14; + + /* Save last two gains */ + silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) ); + + psPLC->subfr_length = psDec->subfr_length; + psPLC->nb_subfr = psDec->nb_subfr; +} + +static OPUS_INLINE void silk_PLC_energy(opus_int32 *energy1, opus_int *shift1, opus_int32 *energy2, opus_int *shift2, + const opus_int32 *exc_Q14, const opus_int32 *prevGain_Q10, int subfr_length, int nb_subfr) +{ + int i, k; + VARDECL( opus_int16, exc_buf ); + opus_int16 *exc_buf_ptr; + SAVE_STACK; + ALLOC( exc_buf, 2*subfr_length, opus_int16 ); + /* Find random noise component */ + /* Scale previous excitation signal */ + exc_buf_ptr = exc_buf; + for( k = 0; k < 2; k++ ) { + for( i = 0; i < subfr_length; i++ ) { + exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( + silk_SMULWW( exc_Q14[ i + ( k + nb_subfr - 2 ) * subfr_length ], prevGain_Q10[ k ] ), 8 ) ); + } + exc_buf_ptr += subfr_length; + } + /* Find the subframe with lowest energy of the last two and use that as random noise generator */ + silk_sum_sqr_shift( energy1, shift1, exc_buf, subfr_length ); + silk_sum_sqr_shift( energy2, shift2, &exc_buf[ subfr_length ], subfr_length ); + RESTORE_STACK; +} + +static OPUS_INLINE void silk_PLC_conceal( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* O LPC residual signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, k; + opus_int lag, idx, sLTP_buf_idx, shift1, shift2; + opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30; + opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr; + opus_int32 LPC_pred_Q10, LTP_pred_Q12; + opus_int16 rand_scale_Q14; + opus_int16 *B_Q14; + opus_int32 *sLPC_Q14_ptr; + opus_int16 A_Q12[ MAX_LPC_ORDER ]; +#ifdef SMALL_FOOTPRINT + opus_int16 *sLTP; +#else + VARDECL( opus_int16, sLTP ); +#endif + VARDECL( opus_int32, sLTP_Q14 ); + silk_PLC_struct *psPLC = &psDec->sPLC; + opus_int32 prevGain_Q10[2]; + SAVE_STACK; + + ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); +#ifdef SMALL_FOOTPRINT + /* Ugly hack that breaks aliasing rules to save stack: put sLTP at the very end of sLTP_Q14. */ + sLTP = ((opus_int16*)&sLTP_Q14[psDec->ltp_mem_length + psDec->frame_length])-psDec->ltp_mem_length; +#else + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); +#endif + + prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6); + prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6); + + if( psDec->first_frame_after_reset ) { + silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) ); + } + + silk_PLC_energy(&energy1, &shift1, &energy2, &shift2, psDec->exc_Q14, prevGain_Q10, psDec->subfr_length, psDec->nb_subfr); + + if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) { + /* First sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } else { + /* Second sub-frame has lowest energy */ + rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ]; + } + + /* Set up Gain to random noise component */ + B_Q14 = psPLC->LTPCoef_Q14; + rand_scale_Q14 = psPLC->randScale_Q14; + + /* Set up attenuation gains */ + harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + if( psDec->prevSignalType == TYPE_VOICED ) { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } else { + rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ]; + } + + /* LPC concealment. Apply BWE to previous LPC */ + silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) ); + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* First Lost frame */ + if( psDec->lossCnt == 0 ) { + rand_scale_Q14 = 1 << 14; + + /* Reduce random noise Gain for voiced frames */ + if( psDec->prevSignalType == TYPE_VOICED ) { + for( i = 0; i < LTP_ORDER; i++ ) { + rand_scale_Q14 -= B_Q14[ i ]; + } + rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */ + rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 ); + } else { + /* Reduce random noise for unvoiced frames with high LPC gain */ + opus_int32 invGain_Q30, down_scale_Q30; + + invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order, arch ); + + down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 ); + down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 ); + down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES ); + + rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 ); + } + } + + rand_seed = psPLC->rand_seed; + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + sLTP_buf_idx = psDec->ltp_mem_length; + + /* Rewhiten LTP state */ + idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( idx > 0 ); + silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order, arch ); + /* Scale LTP state */ + inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 ); + inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 ); + for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) { + sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] ); + } + + /***************************/ + /* LTP synthesis filtering */ + /***************************/ + for( k = 0; k < psDec->nb_subfr; k++ ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q12 = 2; + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + rand_seed = silk_RAND( rand_seed ); + idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK; + sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 ); + sLTP_buf_idx++; + } + + /* Gradually reduce LTP gain */ + for( j = 0; j < LTP_ORDER; j++ ) { + B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 ); + } + if ( psDec->indices.signalType != TYPE_NO_VOICE_ACTIVITY ) { + /* Gradually reduce excitation gain */ + rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 ); + } + + /* Slowly increase pitch lag */ + psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 ); + psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) ); + lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 ); + } + + /***************************/ + /* LPC synthesis filtering */ + /***************************/ + sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ]; + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + celt_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */ + for( i = 0; i < psDec->frame_length; i++ ) { + /* partly unrolled */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] ); + for( j = 10; j < psDec->LPC_order; j++ ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], + silk_LSHIFT_SAT32( LPC_pred_Q10, 4 )); + + /* Scale with Gain */ + frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) ); + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + /**************************************/ + /* Update states */ + /**************************************/ + psPLC->rand_seed = rand_seed; + psPLC->randScale_Q14 = rand_scale_Q14; + for( i = 0; i < MAX_NB_SUBFR; i++ ) { + psDecCtrl->pitchL[ i ] = lag; + } + RESTORE_STACK; +} + +/* Glues concealed frames with new good received frames */ +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +) +{ + opus_int i, energy_shift; + opus_int32 energy; + silk_PLC_struct *psPLC; + psPLC = &psDec->sPLC; + + if( psDec->lossCnt ) { + /* Calculate energy in concealed residual */ + silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length ); + + psPLC->last_frame_lost = 1; + } else { + if( psDec->sPLC.last_frame_lost ) { + /* Calculate residual in decoded signal if last frame was lost */ + silk_sum_sqr_shift( &energy, &energy_shift, frame, length ); + + /* Normalize energies */ + if( energy_shift > psPLC->conc_energy_shift ) { + psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift ); + } else if( energy_shift < psPLC->conc_energy_shift ) { + energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift ); + } + + /* Fade in the energy difference */ + if( energy > psPLC->conc_energy ) { + opus_int32 frac_Q24, LZ; + opus_int32 gain_Q16, slope_Q16; + + LZ = silk_CLZ32( psPLC->conc_energy ); + LZ = LZ - 1; + psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ ); + energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) ); + + frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) ); + + gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 ); + slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length ); + /* Make slope 4x steeper to avoid missing onsets after DTX */ + slope_Q16 = silk_LSHIFT( slope_Q16, 2 ); + + for( i = 0; i < length; i++ ) { + frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] ); + gain_Q16 += slope_Q16; + if( gain_Q16 > (opus_int32)1 << 16 ) { + break; + } + } + } + } + psPLC->last_frame_lost = 0; + } +} diff --git a/src/libopus/silk/PLC.h b/src/libopus/silk/PLC.h new file mode 100644 index 00000000..6438f516 --- /dev/null +++ b/src/libopus/silk/PLC.h @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_PLC_H +#define SILK_PLC_H + +#include "main.h" + +#define BWE_COEF 0.99 +#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */ +#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */ +#define MAX_PITCH_LAG_MS 18 +#define RAND_BUF_SIZE 128 +#define RAND_BUF_MASK ( RAND_BUF_SIZE - 1 ) +#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */ +#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */ +#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */ + +void silk_PLC_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +void silk_PLC( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O signal */ + opus_int lost, /* I Loss flag */ + int arch /* I Run-time architecture */ +); + +void silk_PLC_glue_frames( + silk_decoder_state *psDec, /* I/O decoder state */ + opus_int16 frame[], /* I/O signal */ + opus_int length /* I length of signal */ +); + +#endif + diff --git a/src/libopus/silk/SigProc_FIX.h b/src/libopus/silk/SigProc_FIX.h new file mode 100644 index 00000000..686b3a2e --- /dev/null +++ b/src/libopus/silk/SigProc_FIX.h @@ -0,0 +1,641 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_SIGPROC_FIX_H +#define SILK_SIGPROC_FIX_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */ + +#define SILK_MAX_ORDER_LPC 24 /* max order of the LPC analysis in schur() and k2a() */ + +#include /* for memset(), memcpy(), memmove() */ +#include "typedef.h" +#include "resampler_structs.h" +#include "macros.h" +#include "../celt/cpu_support.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/SigProc_FIX_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/biquad_alt_arm.h" +#include "arm/LPC_inv_pred_gain_arm.h" +#endif + +/********************************************************************/ +/* SIGNAL PROCESSING FUNCTIONS */ +/********************************************************************/ + +/*! + * Initialize/reset the resampler state for a given pair of input/output sampling rates +*/ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +); + +/*! + * Resampler: convert from one sampling rate to another + */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! +* Downsample 2x, mediocre quality +*/ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ len ] */ + const opus_int16 *in, /* I Input signal [ floor(len/2) ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * Downsample by a factor 2/3, low quality +*/ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +); + +/*! + * second order ARMA filter; + * slower than biquad() but uses more precise coefficients + * can handle (slowly) varying coefficients + */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +); + +/* Variable order MA prediction error filter. */ +void silk_LPC_analysis_filter( + opus_int16 *out, /* O Output signal */ + const opus_int16 *in, /* I Input signal */ + const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */ + const opus_int32 len, /* I Signal length */ + const opus_int32 d, /* I Filter order */ + int arch /* I Run-time architecture */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +); + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +); + +/* Compute inverse of LPC prediction gain, and */ +/* test if LPC coefficients are stable (all poles within unit circle) */ +opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */ + const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */ + const opus_int order /* I Prediction order */ +); + +/* Split signal in two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +); + +#if !defined(OVERRIDE_silk_biquad_alt_stride2) +#define silk_biquad_alt_stride2(in, B_Q28, A_Q28, S, out, len, arch) ((void)(arch), silk_biquad_alt_stride2_c(in, B_Q28, A_Q28, S, out, len)) +#endif + +#if !defined(OVERRIDE_silk_LPC_inverse_pred_gain) +#define silk_LPC_inverse_pred_gain(A_Q12, order, arch) ((void)(arch), silk_LPC_inverse_pred_gain_c(A_Q12, order)) +#endif + +/********************************************************************/ +/* SCALAR FUNCTIONS */ +/********************************************************************/ + +/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +); + +/* Approximation of a sigmoid function */ +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +); + +/* Approximation of 2^() (exact inverse of approx log2() above) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +); + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Faster than schur64(), but much less accurate. */ +/* uses SMLAWB(), requiring armv5E and higher. */ +opus_int32 silk_schur( /* O Returns residual energy */ + opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */ + const opus_int32 *c, /* I correlations [order+1] */ + const opus_int32 order /* I prediction order */ +); + +/* Calculates the reflection coefficients from the correlation sequence */ +/* Slower than schur(), but more accurate. */ +/* Uses SMULL(), available on armv4 */ +opus_int32 silk_schur64( /* O returns residual energy */ + opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */ + const opus_int32 c[], /* I Correlations [order+1] */ + opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */ + const opus_int32 order /* I Prediction order */ +); + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +); + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* every other sample of window is linearly interpolated, for speed */ +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +); + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +); + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +); + +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +); + +/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */ +/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */ +void silk_A2NLSF( + opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */ + opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */ + const opus_int d /* I Filter order (must be even) */ +); + +/* compute whitening filter coefficients from normalized line spectral frequencies */ +void silk_NLSF2A( + opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ + const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */ + const opus_int d, /* I filter order (should be even) */ + int arch /* I Run-time architecture */ +); + +/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */ +void silk_LPC_fit( + opus_int16 *a_QOUT, /* O Output signal */ + opus_int32 *a_QIN, /* I/O Input signal */ + const opus_int QOUT, /* I Input Q domain */ + const opus_int QIN, /* I Input Q domain */ + const opus_int d /* I Filter order */ +); + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +); + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +); + +/* NLSF stabilizer, for a single input data vector */ +void silk_NLSF_stabilize( + opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */ + const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */ + const opus_int L /* I Number of NLSF parameters in the input vector */ +); + +/* Laroia low complexity NLSF weights */ +void silk_NLSF_VQ_weights_laroia( + opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */ + const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */ + const opus_int D /* I Input vector dimension (even) */ +); + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +); + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +); + +/* Some for the LTP related function requires Q26 to work.*/ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +); + +/********************************************************************/ +/* INLINE ARM MATH */ +/********************************************************************/ + +/* return sum( inVec1[i] * inVec2[i] ) */ + +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +); + + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +); + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +); + +/********************************************************************/ +/* MACROS */ +/********************************************************************/ + +/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating + left. Output is 32bit int. + Note: contemporary compilers recognize the C expression below and + compile it into a 'ror' instruction if available. No need for OPUS_INLINE ASM! */ +static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot ) +{ + opus_uint32 x = (opus_uint32) a32; + opus_uint32 r = (opus_uint32) rot; + opus_uint32 m = (opus_uint32) -rot; + if( rot == 0 ) { + return a32; + } else if( rot < 0 ) { + return (opus_int32) ((x << m) | (x >> (32 - m))); + } else { + return (opus_int32) ((x << (32 - r)) | (x >> r)); + } +} + +/* Allocate opus_int16 aligned to 4-byte memory address */ +#if EMBEDDED_ARM +#define silk_DWORD_ALIGN __attribute__((aligned(4))) +#else +#define silk_DWORD_ALIGN +#endif + +/* Useful Macros that can be adjusted to other platforms */ +#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size)) +#define silk_memset(dest, src, size) memset((dest), (src), (size)) +#define silk_memmove(dest, src, size) memmove((dest), (src), (size)) + +/* Fixed point macros */ + +/* (a32 * b32) output have to be 32bit int */ +#define silk_MUL(a32, b32) ((a32) * (b32)) + +/* (a32 * b32) output have to be 32bit uint */ +#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32) + +/* a32 + (b32 * c32) output have to be 32bit int */ +#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32))) + +/* a32 + (b32 * c32) output have to be 32bit uint */ +#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32) + +/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16)) + +/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */ +#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16)) + +#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16))) + +/* (a32 * b32) */ +#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_int64)*/(b32)) + +/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b))) +/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour + (just standard two's complement implementation-specific behaviour) */ +#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b))) + +/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */ +#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32)) +#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))) + +#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16))) +#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32))) + +/* These macros enables checking for overflow in silk_API_Debug.h*/ +#define silk_ADD16(a, b) ((a) + (b)) +#define silk_ADD32(a, b) ((a) + (b)) +#define silk_ADD64(a, b) ((a) + (b)) + +#define silk_SUB16(a, b) ((a) - (b)) +#define silk_SUB32(a, b) ((a) - (b)) +#define silk_SUB64(a, b) ((a) - (b)) + +#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \ + ((a) < silk_int8_MIN ? silk_int8_MIN : (a))) +#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \ + ((a) < silk_int16_MIN ? silk_int16_MIN : (a))) +#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \ + ((a) < silk_int32_MIN ? silk_int32_MIN : (a))) + +#define silk_CHECK_FIT8(a) (a) +#define silk_CHECK_FIT16(a) (a) +#define silk_CHECK_FIT32(a) (a) + +#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) ) +#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \ + ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) ) + +#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) ) +#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \ + (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \ + ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) ) + +/* Saturation for positive input values */ +#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a)) + +/* Add with saturation for positive input values */ +#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b))) +#define silk_ADD_POS_SAT32(a, b) ((((opus_uint32)(a)+(opus_uint32)(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b))) + +#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */ +#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */ +#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */ +#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */ +#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */ +#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */ +#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */ +#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */ +#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */ + +/* saturates before shifting */ +#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \ + silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) )) + +#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */ +#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */ +#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */ + +#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */ +#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */ +#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */ + +/* Requires that shift > 0 */ +#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) +#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1) + +/* Number of rightshift required to fit the multiplication */ +#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) ) +#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) ) + + +#define silk_min(a, b) (((a) < (b)) ? (a) : (b)) +#define silk_max(a, b) (((a) > (b)) ? (a) : (b)) + +/* Macro to convert floating-point constants to fixed-point */ +#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5)) + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b) +{ + return (((a) < (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b) +{ + return (((a) < (b)) ? (a) : (b)); +} + +/* silk_min() versions with typecast in the function call */ +static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b) +{ + return (((a) > (b)) ? (a) : (b)); +} +static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b) +{ + return (((a) > (b)) ? (a) : (b)); +} + +#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \ + : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a)))) + +#define silk_LIMIT_int silk_LIMIT +#define silk_LIMIT_16 silk_LIMIT +#define silk_LIMIT_32 silk_LIMIT + +#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */ +#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1))) +#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31)) +#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a)) + +#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 )) + +/* PSEUDO-RANDOM GENERATOR */ +/* Make sure to store the result as the seed for the next call (also in between */ +/* frames), otherwise result won't be random at all. When only using some of the */ +/* bits, take the most significant bits by right-shifting. */ +#define RAND_MULTIPLIER 196314165 +#define RAND_INCREMENT 907633515 +#define silk_RAND(seed) (silk_MLA_ovflw((RAND_INCREMENT), (seed), (RAND_MULTIPLIER))) + +/* Add some multiplication functions that can be easily mapped to ARM. */ + +/* silk_SMMUL: Signed top word multiply. + ARMv6 2 instruction cycles. + ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/ +/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/ +/* the following seems faster on x86 */ +#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32) + +#if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +#define silk_burg_modified(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch) \ + ((void)(arch), silk_burg_modified_c(res_nrg, res_nrg_Q, A_Q16, x, minInvGain_Q30, subfr_length, nb_subfr, D, arch)) + +#define silk_inner_prod16_aligned_64(inVec1, inVec2, len, arch) \ + ((void)(arch),silk_inner_prod16_aligned_64_c(inVec1, inVec2, len)) +#endif + +#include "Inlines.h" +#include "MacroCount.h" +#include "MacroDebug.h" + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/SigProc_FIX_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/SigProc_FIX_armv5e.h" +#endif + +#if defined(MIPSr1_ASM) +#include "mips/sigproc_fix_mipsr1.h" +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_SIGPROC_FIX_H */ diff --git a/src/libopus/silk/VAD.c b/src/libopus/silk/VAD.c new file mode 100644 index 00000000..3f90f0b8 --- /dev/null +++ b/src/libopus/silk/VAD.c @@ -0,0 +1,361 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#include + +#include "main.h" +#include "../celt/stack_alloc.h" + +/* Silk VAD noise level estimation */ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); +#endif + +/**********************************/ +/* Initialization of the Silk VAD */ +/**********************************/ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int b, ret = 0; + + /* reset state memory */ + silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) ); + + /* init noise levels */ + /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 ); + } + + /* Initialize state */ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] ); + psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] ); + } + psSilk_VAD->counter = 15; + + /* init smoothed energy-to-noise ratio*/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */ + } + + return( ret ); +} + +/* Weighting factors for tilt measure */ +static const opus_int32 tiltWeights[ VAD_N_BANDS ] PROGMEM = { 30000, 6000, -12000, -12000 }; + +/***************************************/ +/* Get the speech activity level in Q8 */ +/***************************************/ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +) +{ + opus_int SA_Q15, pSNR_dB_Q7, input_tilt; + opus_int decimated_framelength1, decimated_framelength2; + opus_int decimated_framelength; + opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s; + opus_int32 sumSquared, smooth_coef_Q16; + opus_int16 HPstateTmp; + VARDECL( opus_int16, X ); + opus_int32 Xnrg[ VAD_N_BANDS ]; + opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ]; + opus_int32 speech_nrg, x_tmp; + opus_int X_offset[ VAD_N_BANDS ]; + opus_int ret = 0; + silk_VAD_state *psSilk_VAD = &psEncC->sVAD; + SAVE_STACK; + + /* Safety checks */ + silk_assert( VAD_N_BANDS == 4 ); + celt_assert( MAX_FRAME_LENGTH >= psEncC->frame_length ); + celt_assert( psEncC->frame_length <= 512 ); + celt_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) ); + + /***********************/ + /* Filter and Decimate */ + /***********************/ + decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 ); + decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 ); + decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 ); + /* Decimate into 4 bands: + 0 L 3L L 3L 5L + - -- - -- -- + 8 8 2 4 4 + + [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz | + + They're arranged to allow the minimal ( frame_length / 4 ) extra + scratch space during the downsampling process */ + X_offset[ 0 ] = 0; + X_offset[ 1 ] = decimated_framelength + decimated_framelength2; + X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength; + X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2; + ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 ); + + /* 0-8 kHz to 0-4 kHz and 4-8 kHz */ + silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ], + X, &X[ X_offset[ 3 ] ], psEncC->frame_length ); + + /* 0-4 kHz to 0-2 kHz and 2-4 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ], + X, &X[ X_offset[ 2 ] ], decimated_framelength1 ); + + /* 0-2 kHz to 0-1 kHz and 1-2 kHz */ + silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ], + X, &X[ X_offset[ 1 ] ], decimated_framelength2 ); + + /*********************************************/ + /* HP filter on lowest band (differentiator) */ + /*********************************************/ + X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 ); + HPstateTmp = X[ decimated_framelength - 1 ]; + for( i = decimated_framelength - 1; i > 0; i-- ) { + X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 ); + X[ i ] -= X[ i - 1 ]; + } + X[ 0 ] -= psSilk_VAD->HPstate; + psSilk_VAD->HPstate = HPstateTmp; + + /*************************************/ + /* Calculate the energy in each band */ + /*************************************/ + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Find the decimated framelength in the non-uniformly divided bands */ + decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) ); + + /* Split length into subframe lengths */ + dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 ); + dec_subframe_offset = 0; + + /* Compute energy per sub-frame */ + /* initialize with summed energy of last subframe */ + Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ]; + for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) { + sumSquared = 0; + for( i = 0; i < dec_subframe_length; i++ ) { + /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */ + /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */ + x_tmp = silk_RSHIFT( + X[ X_offset[ b ] + i + dec_subframe_offset ], 3 ); + sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp ); + + /* Safety check */ + silk_assert( sumSquared >= 0 ); + } + + /* Add/saturate summed energy of current subframe */ + if( s < VAD_INTERNAL_SUBFRAMES - 1 ) { + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared ); + } else { + /* Look-ahead subframe */ + Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) ); + } + + dec_subframe_offset += dec_subframe_length; + } + psSilk_VAD->XnrgSubfr[ b ] = sumSquared; + } + + /********************/ + /* Noise estimation */ + /********************/ + silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD ); + + /***********************************************/ + /* Signal-plus-noise to noise ratio estimation */ + /***********************************************/ + sumSquared = 0; + input_tilt = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ]; + if( speech_nrg > 0 ) { + /* Divide, with sufficient resolution */ + if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 ); + } else { + NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 ); + } + + /* Convert to log domain */ + SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128; + + /* Sum-of-squares */ + sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */ + + /* Tilt measure */ + if( speech_nrg < ( (opus_int32)1 << 20 ) ) { + /* Scale down SNR value for small subband speech energies */ + SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 ); + } + input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 ); + } else { + NrgToNoiseRatio_Q8[ b ] = 256; + } + } + + /* Mean-of-squares */ + sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */ + + /* Root-mean-square approximation, scale to dBs, and write to output pointer */ + pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */ + + /*********************************/ + /* Speech Probability Estimation */ + /*********************************/ + SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 ); + + /**************************/ + /* Frequency Tilt Measure */ + /**************************/ + psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 ); + + /**************************************************/ + /* Scale the sigmoid output based on power levels */ + /**************************************************/ + speech_nrg = 0; + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* Accumulate signal-without-noise energies, higher frequency bands have more weight */ + speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 ); + } + + if( psEncC->frame_length == 20 * psEncC->fs_kHz ) { + speech_nrg = silk_RSHIFT32( speech_nrg, 1 ); + } + /* Power scaling */ + if( speech_nrg <= 0 ) { + SA_Q15 = silk_RSHIFT( SA_Q15, 1 ); + } else if( speech_nrg < 16384 ) { + speech_nrg = silk_LSHIFT32( speech_nrg, 16 ); + + /* square-root */ + speech_nrg = silk_SQRT_APPROX( speech_nrg ); + SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 ); + } + + /* Copy the resulting speech activity in Q8 */ + psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX ); + + /***********************************/ + /* Energy Level and SNR estimation */ + /***********************************/ + /* Smoothing coefficient */ + smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) ); + + if( psEncC->frame_length == 10 * psEncC->fs_kHz ) { + smooth_coef_Q16 >>= 1; + } + + for( b = 0; b < VAD_N_BANDS; b++ ) { + /* compute smoothed energy-to-noise ratio per band */ + psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ], + NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 ); + + /* signal to noise ratio in dB per band */ + SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 ); + /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */ + psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) ); + } + + RESTORE_STACK; + return( ret ); +} + +/**************************/ +/* Noise level estimation */ +/**************************/ +# if !defined(OPUS_X86_MAY_HAVE_SSE4_1) +static OPUS_INLINE +#endif +void silk_VAD_GetNoiseLevels( + const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +) +{ + opus_int k; + opus_int32 nl, nrg, inv_nrg; + opus_int coef, min_coef; + + /* Initially faster smoothing */ + if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */ + min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 ); + /* Increment frame counter */ + psSilk_VAD->counter++; + } else { + min_coef = 0; + } + + for( k = 0; k < VAD_N_BANDS; k++ ) { + /* Get old noise level estimate for current band */ + nl = psSilk_VAD->NL[ k ]; + silk_assert( nl >= 0 ); + + /* Add bias */ + nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] ); + silk_assert( nrg > 0 ); + + /* Invert energies */ + inv_nrg = silk_DIV32( silk_int32_MAX, nrg ); + silk_assert( inv_nrg >= 0 ); + + /* Less update when subband energy is high */ + if( nrg > silk_LSHIFT( nl, 3 ) ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3; + } else if( nrg < nl ) { + coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16; + } else { + coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 ); + } + + /* Initially faster smoothing */ + coef = silk_max_int( coef, min_coef ); + + /* Smooth inverse energies */ + psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef ); + silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 ); + + /* Compute noise level by inverting again */ + nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] ); + silk_assert( nl >= 0 ); + + /* Limit noise levels (guarantee 7 bits of head room) */ + nl = silk_min( nl, 0x00FFFFFF ); + + /* Store as part of state */ + psSilk_VAD->NL[ k ] = nl; + } +} diff --git a/src/libopus/silk/VQ_WMat_EC.c b/src/libopus/silk/VQ_WMat_EC.c new file mode 100644 index 00000000..601e3969 --- /dev/null +++ b/src/libopus/silk/VQ_WMat_EC.c @@ -0,0 +1,131 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +) +{ + opus_int k, gain_tmp_Q7; + const opus_int8 *cb_row_Q7; + opus_int32 neg_xX_Q24[ 5 ]; + opus_int32 sum1_Q15, sum2_Q24; + opus_int32 bits_res_Q8, bits_tot_Q8; + + /* Negate and convert to new Q domain */ + neg_xX_Q24[ 0 ] = -silk_LSHIFT32( xX_Q17[ 0 ], 7 ); + neg_xX_Q24[ 1 ] = -silk_LSHIFT32( xX_Q17[ 1 ], 7 ); + neg_xX_Q24[ 2 ] = -silk_LSHIFT32( xX_Q17[ 2 ], 7 ); + neg_xX_Q24[ 3 ] = -silk_LSHIFT32( xX_Q17[ 3 ], 7 ); + neg_xX_Q24[ 4 ] = -silk_LSHIFT32( xX_Q17[ 4 ], 7 ); + + /* Loop over codebook */ + *rate_dist_Q8 = silk_int32_MAX; + *res_nrg_Q15 = silk_int32_MAX; + cb_row_Q7 = cb_Q7; + /* In things go really bad, at least *ind is set to something safe. */ + *ind = 0; + for( k = 0; k < L; k++ ) { + opus_int32 penalty; + gain_tmp_Q7 = cb_gain_Q7[k]; + /* Weighted rate */ + /* Quantization error: 1 - 2 * xX * cb + cb' * XX * cb */ + sum1_Q15 = SILK_FIX_CONST( 1.001, 15 ); + + /* Penalty for too large gain */ + penalty = silk_LSHIFT32( silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 11 ); + + /* first row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 0 ], XX_Q17[ 1 ], cb_row_Q7[ 1 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 2 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 3 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 4 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 0 ], cb_row_Q7[ 0 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 0 ] ); + + /* second row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 1 ], XX_Q17[ 7 ], cb_row_Q7[ 2 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 8 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 9 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 6 ], cb_row_Q7[ 1 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 1 ] ); + + /* third row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 2 ], XX_Q17[ 13 ], cb_row_Q7[ 3 ] ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 14 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 12 ], cb_row_Q7[ 2 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 2 ] ); + + /* fourth row of XX_Q17 */ + sum2_Q24 = silk_MLA( neg_xX_Q24[ 3 ], XX_Q17[ 19 ], cb_row_Q7[ 4 ] ); + sum2_Q24 = silk_LSHIFT32( sum2_Q24, 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 18 ], cb_row_Q7[ 3 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 3 ] ); + + /* last row of XX_Q17 */ + sum2_Q24 = silk_LSHIFT32( neg_xX_Q24[ 4 ], 1 ); + sum2_Q24 = silk_MLA( sum2_Q24, XX_Q17[ 24 ], cb_row_Q7[ 4 ] ); + sum1_Q15 = silk_SMLAWB( sum1_Q15, sum2_Q24, cb_row_Q7[ 4 ] ); + + /* find best */ + if( sum1_Q15 >= 0 ) { + /* Translate residual energy to bits using high-rate assumption (6 dB ==> 1 bit/sample) */ + bits_res_Q8 = silk_SMULBB( subfr_len, silk_lin2log( sum1_Q15 + penalty) - (15 << 7) ); + /* In the following line we reduce the codelength component by half ("-1"); seems to slghtly improve quality */ + bits_tot_Q8 = silk_ADD_LSHIFT32( bits_res_Q8, cl_Q5[ k ], 3-1 ); + if( bits_tot_Q8 <= *rate_dist_Q8 ) { + *rate_dist_Q8 = bits_tot_Q8; + *res_nrg_Q15 = sum1_Q15 + penalty; + *ind = (opus_int8)k; + *gain_Q7 = gain_tmp_Q7; + } + } + + /* Go to next cbk vector */ + cb_row_Q7 += LTP_ORDER; + } +} diff --git a/src/libopus/silk/ana_filt_bank_1.c b/src/libopus/silk/ana_filt_bank_1.c new file mode 100644 index 00000000..30e42f21 --- /dev/null +++ b/src/libopus/silk/ana_filt_bank_1.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +/* Coefficients for 2-band filter bank based on first-order allpass filters */ +static opus_int16 A_fb1_20 = 5394 << 1; +static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */ + +/* Split signal into two decimated bands using first-order allpass filters */ +void silk_ana_filt_bank_1( + const opus_int16 *in, /* I Input signal [N] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *outL, /* O Low band [N/2] */ + opus_int16 *outH, /* O High band [N/2] */ + const opus_int32 N /* I Number of input samples */ +) +{ + opus_int k, N2 = silk_RSHIFT( N, 1 ); + opus_int32 in32, X, Y, out_1, out_2; + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < N2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, A_fb1_21 ); + out_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, A_fb1_20 ); + out_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add/subtract, convert back to int16 and store to output */ + outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) ); + outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) ); + } +} diff --git a/src/libopus/silk/biquad_alt.c b/src/libopus/silk/biquad_alt.c new file mode 100644 index 00000000..5ae2f516 --- /dev/null +++ b/src/libopus/silk/biquad_alt.c @@ -0,0 +1,121 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +/* * + * silk_biquad_alt.c * + * * + * Second order ARMA filter * + * Can handle slowly varying filter coefficients * + * */ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +/* Second order ARMA filter, alternative implementation */ +void silk_biquad_alt_stride1( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [2] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ]: Q12 */ + inval = in[ k ]; + out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 ); + + S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval ); + + /* Scale back to Q0 and saturate */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) ); + } +} + +void silk_biquad_alt_stride2_c( + const opus_int16 *in, /* I input signal */ + const opus_int32 *B_Q28, /* I MA coefficients [3] */ + const opus_int32 *A_Q28, /* I AR coefficients [2] */ + opus_int32 *S, /* I/O State vector [4] */ + opus_int16 *out, /* O output signal */ + const opus_int32 len /* I signal length (must be even) */ +) +{ + /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */ + opus_int k; + opus_int32 A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14[ 2 ]; + + /* Negate A_Q28 values and split in two parts */ + A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */ + A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */ + A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */ + A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */ + + for( k = 0; k < len; k++ ) { + /* S[ 0 ], S[ 1 ], S[ 2 ], S[ 3 ]: Q12 */ + out32_Q14[ 0 ] = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], in[ 2 * k + 0 ] ), 2 ); + out32_Q14[ 1 ] = silk_LSHIFT( silk_SMLAWB( S[ 2 ], B_Q28[ 0 ], in[ 2 * k + 1 ] ), 2 ); + + S[ 0 ] = S[ 1 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A0_L_Q28 ), 14 ); + S[ 2 ] = S[ 3 ] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A0_L_Q28 ), 14 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14[ 0 ], A0_U_Q28 ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], out32_Q14[ 1 ], A0_U_Q28 ); + S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], in[ 2 * k + 0 ] ); + S[ 2 ] = silk_SMLAWB( S[ 2 ], B_Q28[ 1 ], in[ 2 * k + 1 ] ); + + S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 0 ], A1_L_Q28 ), 14 ); + S[ 3 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14[ 1 ], A1_L_Q28 ), 14 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14[ 0 ], A1_U_Q28 ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], out32_Q14[ 1 ], A1_U_Q28 ); + S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], in[ 2 * k + 0 ] ); + S[ 3 ] = silk_SMLAWB( S[ 3 ], B_Q28[ 2 ], in[ 2 * k + 1 ] ); + + /* Scale back to Q0 and saturate */ + out[ 2 * k + 0 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 0 ] + (1<<14) - 1, 14 ) ); + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14[ 1 ] + (1<<14) - 1, 14 ) ); + } +} diff --git a/src/libopus/silk/bwexpander.c b/src/libopus/silk/bwexpander.c new file mode 100644 index 00000000..509146c8 --- /dev/null +++ b/src/libopus/silk/bwexpander.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander( + opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */ + /* Bias in silk_SMULWB can lead to unstable filters */ + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 ); +} diff --git a/src/libopus/silk/bwexpander_32.c b/src/libopus/silk/bwexpander_32.c new file mode 100644 index 00000000..703b475e --- /dev/null +++ b/src/libopus/silk/bwexpander_32.c @@ -0,0 +1,50 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +/* Chirp (bandwidth expand) LP AR filter */ +void silk_bwexpander_32( + opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */ + const opus_int d, /* I Length of ar */ + opus_int32 chirp_Q16 /* I Chirp factor in Q16 */ +) +{ + opus_int i; + opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536; + + for( i = 0; i < d - 1; i++ ) { + ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] ); + chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 ); + } + ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] ); +} + diff --git a/src/libopus/silk/check_control_input.c b/src/libopus/silk/check_control_input.c new file mode 100644 index 00000000..31b8a7c4 --- /dev/null +++ b/src/libopus/silk/check_control_input.c @@ -0,0 +1,106 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "control.h" +#include "errors.h" + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + celt_assert( encControl != NULL ); + + if( ( ( encControl->API_sampleRate != 8000 ) && + ( encControl->API_sampleRate != 12000 ) && + ( encControl->API_sampleRate != 16000 ) && + ( encControl->API_sampleRate != 24000 ) && + ( encControl->API_sampleRate != 32000 ) && + ( encControl->API_sampleRate != 44100 ) && + ( encControl->API_sampleRate != 48000 ) ) || + ( ( encControl->desiredInternalSampleRate != 8000 ) && + ( encControl->desiredInternalSampleRate != 12000 ) && + ( encControl->desiredInternalSampleRate != 16000 ) ) || + ( ( encControl->maxInternalSampleRate != 8000 ) && + ( encControl->maxInternalSampleRate != 12000 ) && + ( encControl->maxInternalSampleRate != 16000 ) ) || + ( ( encControl->minInternalSampleRate != 8000 ) && + ( encControl->minInternalSampleRate != 12000 ) && + ( encControl->minInternalSampleRate != 16000 ) ) || + ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) || + ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) || + ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) { + celt_assert( 0 ); + return SILK_ENC_FS_NOT_SUPPORTED; + } + if( encControl->payloadSize_ms != 10 && + encControl->payloadSize_ms != 20 && + encControl->payloadSize_ms != 40 && + encControl->payloadSize_ms != 60 ) { + celt_assert( 0 ); + return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_LOSS_RATE; + } + if( encControl->useDTX < 0 || encControl->useDTX > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_DTX_SETTING; + } + if( encControl->useCBR < 0 || encControl->useCBR > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_CBR_SETTING; + } + if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_INBAND_FEC_SETTING; + } + if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->nChannelsInternal > encControl->nChannelsAPI ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR; + } + if( encControl->complexity < 0 || encControl->complexity > 10 ) { + celt_assert( 0 ); + return SILK_ENC_INVALID_COMPLEXITY_SETTING; + } + + return SILK_NO_ERROR; +} diff --git a/src/libopus/silk/code_signs.c b/src/libopus/silk/code_signs.c new file mode 100644 index 00000000..8abf67e9 --- /dev/null +++ b/src/libopus/silk/code_signs.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/ +/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/ +/* shifting avoids if-statement */ +#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 ) +#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 ) + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + const opus_int8 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] != 0 ) { + ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 ); + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +) +{ + opus_int i, j, p; + opus_uint8 icdf[ 2 ]; + opus_int16 *q_ptr; + const opus_uint8 *icdf_ptr; + + icdf[ 1 ] = 0; + q_ptr = pulses; + i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) ); + icdf_ptr = &silk_sign_iCDF[ i ]; + length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH ); + for( i = 0; i < length; i++ ) { + p = sum_pulses[ i ]; + if( p > 0 ) { + icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ]; + for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) { + if( q_ptr[ j ] > 0 ) { + /* attach sign */ +#if 0 + /* conditional implementation */ + if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) { + q_ptr[ j ] = -q_ptr[ j ]; + } +#else + /* implementation with shift, subtraction, multiplication */ + q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) ); +#endif + } + } + } + q_ptr += SHELL_CODEC_FRAME_LENGTH; + } +} diff --git a/src/libopus/silk/control.h b/src/libopus/silk/control.h new file mode 100644 index 00000000..b76ec33c --- /dev/null +++ b/src/libopus/silk/control.h @@ -0,0 +1,150 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_CONTROL_H +#define SILK_CONTROL_H + +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decoder API flags */ +#define FLAG_DECODE_NORMAL 0 +#define FLAG_PACKET_LOST 1 +#define FLAG_DECODE_LBRR 2 + +/***********************************************/ +/* Structure for controlling encoder operation */ +/***********************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 maxInternalSampleRate; + + /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 minInternalSampleRate; + + /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */ + opus_int32 desiredInternalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* I: Bitrate during active speech in bits/second; internally limited */ + opus_int32 bitRate; + + /* I: Uplink packet loss in percent (0-100) */ + opus_int packetLossPercentage; + + /* I: Complexity mode; 0 is lowest, 10 is highest complexity */ + opus_int complexity; + + /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */ + opus_int useInBandFEC; + + /* I: Flag to actually code in-band Forward Error Correction (FEC) in the current packet; 0/1 */ + opus_int LBRR_coded; + + /* I: Flag to enable discontinuous transmission (DTX); 0/1 */ + opus_int useDTX; + + /* I: Flag to use constant bitrate */ + opus_int useCBR; + + /* I: Maximum number of bits allowed for the frame */ + opus_int maxBits; + + /* I: Causes a smooth downmix to mono */ + opus_int toMono; + + /* I: Opus encoder is allowing us to switch bandwidth */ + opus_int opusCanSwitch; + + /* I: Make frames as independent as possible (but still use LPC) */ + opus_int reducedDependency; + + /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* O: Flag that bandwidth switching is allowed (because low voice activity) */ + opus_int allowBandwidthSwitch; + + /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */ + opus_int inWBmodeWithoutVariableLP; + + /* O: Stereo width */ + opus_int stereoWidth_Q14; + + /* O: Tells the Opus encoder we're ready to switch */ + opus_int switchReady; + + /* O: SILK Signal type */ + opus_int signalType; + + /* O: SILK offset (dithering) */ + opus_int offset; +} silk_EncControlStruct; + +/**************************************************************************/ +/* Structure for controlling decoder operation and reading decoder status */ +/**************************************************************************/ +typedef struct { + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsAPI; + + /* I: Number of channels; 1/2 */ + opus_int32 nChannelsInternal; + + /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */ + opus_int32 API_sampleRate; + + /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */ + opus_int32 internalSampleRate; + + /* I: Number of samples per packet in milliseconds; 10/20/40/60 */ + opus_int payloadSize_ms; + + /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */ + opus_int prevPitchLag; +} silk_DecControlStruct; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/silk/control_SNR.c b/src/libopus/silk/control_SNR.c new file mode 100644 index 00000000..182c0d8e --- /dev/null +++ b/src/libopus/silk/control_SNR.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* These tables hold SNR values divided by 21 (so they fit in 8 bits) + for different target bitrates spaced at 400 bps interval. The first + 10 values are omitted (0-4 kb/s) because they're all zeros. + These tables were obtained by running different SNRs through the + encoder and measuring the active bitrate. */ +static const unsigned char silk_TargetRate_NB_21[117 - 10] = { + 0, 15, 39, 52, 61, 68, + 74, 79, 84, 88, 92, 95, 99,102,105,108,111,114,117,119,122,124, + 126,129,131,133,135,137,139,142,143,145,147,149,151,153,155,157, + 158,160,162,163,165,167,168,170,171,173,174,176,177,179,180,182, + 183,185,186,187,189,190,192,193,194,196,197,199,200,201,203,204, + 205,207,208,209,211,212,213,215,216,217,219,220,221,223,224,225, + 227,228,230,231,232,234,235,236,238,239,241,242,243,245,246,248, + 249,250,252,253,255 +}; + +static const unsigned char silk_TargetRate_MB_21[165 - 10] = { + 0, 0, 28, 43, 52, 59, + 65, 70, 74, 78, 81, 85, 87, 90, 93, 95, 98,100,102,105,107,109, + 111,113,115,116,118,120,122,123,125,127,128,130,131,133,134,136, + 137,138,140,141,143,144,145,147,148,149,151,152,153,154,156,157, + 158,159,160,162,163,164,165,166,167,168,169,171,172,173,174,175, + 176,177,178,179,180,181,182,183,184,185,186,187,188,188,189,190, + 191,192,193,194,195,196,197,198,199,200,201,202,203,203,204,205, + 206,207,208,209,210,211,212,213,214,214,215,216,217,218,219,220, + 221,222,223,224,224,225,226,227,228,229,230,231,232,233,234,235, + 236,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250, + 251,252,253,254,255 +}; + +static const unsigned char silk_TargetRate_WB_21[201 - 10] = { + 0, 0, 0, 8, 29, 41, + 49, 56, 62, 66, 70, 74, 77, 80, 83, 86, 88, 91, 93, 95, 97, 99, + 101,103,105,107,108,110,112,113,115,116,118,119,121,122,123,125, + 126,127,129,130,131,132,134,135,136,137,138,140,141,142,143,144, + 145,146,147,148,149,150,151,152,153,154,156,157,158,159,159,160, + 161,162,163,164,165,166,167,168,169,170,171,171,172,173,174,175, + 176,177,177,178,179,180,181,181,182,183,184,185,185,186,187,188, + 189,189,190,191,192,192,193,194,195,195,196,197,198,198,199,200, + 200,201,202,203,203,204,205,206,206,207,208,209,209,210,211,211, + 212,213,214,214,215,216,216,217,218,219,219,220,221,221,222,223, + 224,224,225,226,226,227,228,229,229,230,231,232,232,233,234,234, + 235,236,237,237,238,239,240,240,241,242,243,243,244,245,246,246, + 247,248,249,249,250,251,252,253,255 +}; + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +) +{ + int id; + int bound; + const unsigned char *snr_table; + + psEncC->TargetRate_bps = TargetRate_bps; + if( psEncC->nb_subfr == 2 ) { + TargetRate_bps -= 2000 + psEncC->fs_kHz/16; + } + if( psEncC->fs_kHz == 8 ) { + bound = sizeof(silk_TargetRate_NB_21); + snr_table = silk_TargetRate_NB_21; + } else if( psEncC->fs_kHz == 12 ) { + bound = sizeof(silk_TargetRate_MB_21); + snr_table = silk_TargetRate_MB_21; + } else { + bound = sizeof(silk_TargetRate_WB_21); + snr_table = silk_TargetRate_WB_21; + } + id = (TargetRate_bps+200)/400; + id = silk_min(id - 10, bound-1); + if( id <= 0 ) { + psEncC->SNR_dB_Q7 = 0; + } else { + psEncC->SNR_dB_Q7 = snr_table[id]*21; + } + return SILK_NO_ERROR; +} diff --git a/src/libopus/silk/control_audio_bandwidth.c b/src/libopus/silk/control_audio_bandwidth.c new file mode 100644 index 00000000..b7913b84 --- /dev/null +++ b/src/libopus/silk/control_audio_bandwidth.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "tuning_parameters.h" + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +) +{ + opus_int fs_kHz; + opus_int orig_kHz; + opus_int32 fs_Hz; + + orig_kHz = psEncC->fs_kHz; + /* Handle a bandwidth-switching reset where we need to be aware what the last sampling rate was. */ + if( orig_kHz == 0 ) { + orig_kHz = psEncC->sLP.saved_fs_kHz; + } + fs_kHz = orig_kHz; + fs_Hz = silk_SMULBB( fs_kHz, 1000 ); + if( fs_Hz == 0 ) { + /* Encoder has just been initialized */ + fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) { + /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */ + fs_Hz = psEncC->API_fs_Hz; + fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz ); + fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz ); + fs_kHz = silk_DIV32_16( fs_Hz, 1000 ); + } else { + /* State machine for the internal sampling rate switching */ + if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + } + if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) { + /* Check if we should switch down */ + if( silk_SMULBB( orig_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz ) + { + /* Switch down */ + if( psEncC->sLP.mode == 0 ) { + /* New transition */ + psEncC->sLP.transition_frame_no = TRANSITION_FRAMES; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + } + if( encControl->opusCanSwitch ) { + /* Stop transition phase */ + psEncC->sLP.mode = 0; + + /* Switch to a lower sample frequency */ + fs_kHz = orig_kHz == 16 ? 12 : 8; + } else { + if( psEncC->sLP.transition_frame_no <= 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: down (at double speed) */ + psEncC->sLP.mode = -2; + } + } + } + else + /* Check if we should switch up */ + if( silk_SMULBB( orig_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz ) + { + /* Switch up */ + if( encControl->opusCanSwitch ) { + /* Switch to a higher sample frequency */ + fs_kHz = orig_kHz == 8 ? 12 : 16; + + /* New transition */ + psEncC->sLP.transition_frame_no = 0; + + /* Reset transition filter state */ + silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) ); + + /* Direction: up */ + psEncC->sLP.mode = 1; + } else { + if( psEncC->sLP.mode == 0 ) { + encControl->switchReady = 1; + /* Make room for redundancy */ + encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 ); + } else { + /* Direction: up */ + psEncC->sLP.mode = 1; + } + } + } else { + if (psEncC->sLP.mode<0) + psEncC->sLP.mode = 1; + } + } + } + + return fs_kHz; +} diff --git a/src/libopus/silk/control_codec.c b/src/libopus/silk/control_codec.c new file mode 100644 index 00000000..cd2e2f21 --- /dev/null +++ b/src/libopus/silk/control_codec.c @@ -0,0 +1,423 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#ifdef FIXED_POINT +#include "fixed/main_FIX.h" +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#else +#include "main_FLP.h" +#define silk_encoder_state_Fxx silk_encoder_state_FLP +#endif +#include "../celt/stack_alloc.h" +#include "tuning_parameters.h" +#include "pitch_est_defines.h" + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +); + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +); + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +); + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +); + + +/* Control encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +) +{ + opus_int fs_kHz, ret = 0; + + psEnc->sCmn.useDTX = encControl->useDTX; + psEnc->sCmn.useCBR = encControl->useCBR; + psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate; + psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate; + psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate; + psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate; + psEnc->sCmn.useInBandFEC = encControl->useInBandFEC; + psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI; + psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal; + psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch; + psEnc->sCmn.channelNb = channelNb; + + if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) { + if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) { + /* Change in API sampling rate in the middle of encoding a packet */ + ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz ); + } + return ret; + } + + /* Beyond this point we know that there are no previously coded frames in the payload buffer */ + + /********************************************/ + /* Determine internal sampling rate */ + /********************************************/ + fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl ); + if( force_fs_kHz ) { + fs_kHz = force_fs_kHz; + } + /********************************************/ + /* Prepare resampler and buffered data */ + /********************************************/ + ret += silk_setup_resamplers( psEnc, fs_kHz ); + + /********************************************/ + /* Set internal sampling frequency */ + /********************************************/ + ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms ); + + /********************************************/ + /* Set encoding complexity */ + /********************************************/ + ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity ); + + /********************************************/ + /* Set packet loss rate measured by farend */ + /********************************************/ + psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage; + + /********************************************/ + /* Set LBRR usage */ + /********************************************/ + ret += silk_setup_LBRR( &psEnc->sCmn, encControl ); + + psEnc->sCmn.controlled_since_last_payload = 1; + + return ret; +} + +static opus_int silk_setup_resamplers( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + SAVE_STACK; + + if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz ) + { + if( psEnc->sCmn.fs_kHz == 0 ) { + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 ); + } else { + VARDECL( opus_int16, x_buf_API_fs_Hz ); + VARDECL( silk_resampler_state_struct, temp_resampler_state ); +#ifdef FIXED_POINT + opus_int16 *x_bufFIX = psEnc->x_buf; +#else + VARDECL( opus_int16, x_bufFIX ); + opus_int32 new_buf_samples; +#endif + opus_int32 api_buf_samples; + opus_int32 old_buf_samples; + opus_int32 buf_length_ms; + + buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS; + old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz; + +#ifndef FIXED_POINT + new_buf_samples = buf_length_ms * fs_kHz; + ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ), + opus_int16 ); + silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples ); +#endif + + /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( temp_resampler_state, 1, silk_resampler_state_struct ); + ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 ); + + /* Calculate number of samples to temporarily upsample */ + api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 ); + + /* Temporary resampling of x_buf data to API_fs_Hz */ + ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 ); + ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples ); + + /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */ + ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 ); + + /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */ + ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples ); + +#ifndef FIXED_POINT + silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples); +#endif + } + } + + psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz; + + RESTORE_STACK; + return ret; +} + +static opus_int silk_setup_fs( + silk_encoder_state_Fxx *psEnc, /* I/O */ + opus_int fs_kHz, /* I */ + opus_int PacketSize_ms /* I */ +) +{ + opus_int ret = SILK_NO_ERROR; + + /* Set packet size */ + if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) { + if( ( PacketSize_ms != 10 ) && + ( PacketSize_ms != 20 ) && + ( PacketSize_ms != 40 ) && + ( PacketSize_ms != 60 ) ) { + ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED; + } + if( PacketSize_ms <= 10 ) { + psEnc->sCmn.nFramesPerPacket = 1; + psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1; + psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } else { + psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS ); + psEnc->sCmn.nb_subfr = MAX_NB_SUBFR; + psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz ); + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + if( psEnc->sCmn.fs_kHz == 8 ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } + } + psEnc->sCmn.PacketSize_ms = PacketSize_ms; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + } + + /* Set internal sampling frequency */ + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 ); + if( psEnc->sCmn.fs_kHz != fs_kHz ) { + /* reset part of the state */ + silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) ); + silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) ); + silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) ); + psEnc->sCmn.inputBufIx = 0; + psEnc->sCmn.nFramesEncoded = 0; + psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */ + + /* Initialize non-zero parameters */ + psEnc->sCmn.prevLag = 100; + psEnc->sCmn.first_frame_after_reset = 1; + psEnc->sShape.LastGainIndex = 10; + psEnc->sCmn.sNSQ.lagPrev = 100; + psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + + psEnc->sCmn.fs_kHz = fs_kHz; + if( psEnc->sCmn.fs_kHz == 8 ) { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER; + psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB; + } + psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz; + psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr ); + psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz ); + psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz ); + if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz ); + } else { + psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz ); + } + if( psEnc->sCmn.fs_kHz == 16 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( psEnc->sCmn.fs_kHz == 12 ) { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else { + psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } + } + + /* Check that settings are valid */ + celt_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length ); + + return ret; +} + +static opus_int silk_setup_complexity( + silk_encoder_state *psEncC, /* I/O */ + opus_int Complexity /* I */ +) +{ + opus_int ret = 0; + + /* Set encoding complexity */ + celt_assert( Complexity >= 0 && Complexity <= 10 ); + if( Complexity < 1 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 2 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 1; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 3; + psEncC->warping_Q16 = 0; + } else if( Complexity < 3 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 ); + psEncC->pitchEstimationLPCOrder = 6; + psEncC->shapingLPCOrder = 12; + psEncC->la_shape = 3 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 2; + psEncC->warping_Q16 = 0; + } else if( Complexity < 4 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 ); + psEncC->pitchEstimationLPCOrder = 8; + psEncC->shapingLPCOrder = 14; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 0; + psEncC->NLSF_MSVQ_Survivors = 4; + psEncC->warping_Q16 = 0; + } else if( Complexity < 6 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 ); + psEncC->pitchEstimationLPCOrder = 10; + psEncC->shapingLPCOrder = 16; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 2; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 6; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else if( Complexity < 8 ) { + psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 ); + psEncC->pitchEstimationLPCOrder = 12; + psEncC->shapingLPCOrder = 20; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = 3; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 8; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } else { + psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX; + psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 ); + psEncC->pitchEstimationLPCOrder = 16; + psEncC->shapingLPCOrder = 24; + psEncC->la_shape = 5 * psEncC->fs_kHz; + psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES; + psEncC->useInterpolatedNLSFs = 1; + psEncC->NLSF_MSVQ_Survivors = 16; + psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 ); + } + + /* Do not allow higher pitch estimation LPC order than predict LPC order */ + psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder ); + psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape; + psEncC->Complexity = Complexity; + + celt_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER ); + celt_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER ); + celt_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES ); + celt_assert( psEncC->warping_Q16 <= 32767 ); + celt_assert( psEncC->la_shape <= LA_SHAPE_MAX ); + celt_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX ); + + return ret; +} + +static OPUS_INLINE opus_int silk_setup_LBRR( + silk_encoder_state *psEncC, /* I/O */ + const silk_EncControlStruct *encControl /* I */ +) +{ + opus_int LBRR_in_previous_packet, ret = SILK_NO_ERROR; + + LBRR_in_previous_packet = psEncC->LBRR_enabled; + psEncC->LBRR_enabled = encControl->LBRR_coded; + if( psEncC->LBRR_enabled ) { + /* Set gain increase for coding LBRR excitation */ + if( LBRR_in_previous_packet == 0 ) { + /* Previous packet did not have LBRR, and was therefore coded at a higher bitrate */ + psEncC->LBRR_GainIncreases = 7; + } else { + psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 ); + } + } + + return ret; +} diff --git a/src/libopus/silk/debug.c b/src/libopus/silk/debug.c new file mode 100644 index 00000000..b9550c40 --- /dev/null +++ b/src/libopus/silk/debug.c @@ -0,0 +1,170 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "debug.h" +#include "SigProc_FIX.h" + +#if SILK_TIC_TOC + +#ifdef _WIN32 + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/ +{ + /* Returns a time counter in microsec */ + /* the resolution is platform dependent */ + /* but is typically 1.62 us resolution */ + LARGE_INTEGER lpPerformanceCount; + LARGE_INTEGER lpFrequency; + QueryPerformanceCounter(&lpPerformanceCount); + QueryPerformanceFrequency(&lpFrequency); + return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart); +} +#else /* Linux or Mac*/ +unsigned long GetHighResolutionTime(void) /* O time in usec*/ +{ + struct timeval tv; + gettimeofday(&tv, 0); + return((tv.tv_sec*1000000)+(tv.tv_usec)); +} +#endif + +int silk_Timer_nTimers = 0; +int silk_Timer_depth_ctr = 0; +char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef WIN32 +LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +#ifdef WIN32 +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + LARGE_INTEGER lpFrequency; + LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2; + int del = 0x7FFFFFFF; + double avg, sum_avg; + /* estimate overhead of calling performance counters */ + for( k = 0; k < 1000; k++ ) { + QueryPerformanceCounter(&lpPerformanceCount1); + QueryPerformanceCounter(&lpPerformanceCount2); + lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart; + if( (int)lpPerformanceCount2.LowPart < del ) + del = lpPerformanceCount2.LowPart; + } + QueryPerformanceFrequency(&lpFrequency); + /* print results to file */ + sum_avg = 0.0f; + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k]; + } + } + fp = fopen(file_name, "w"); + fprintf(fp, " min avg %% max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart; + fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]); + fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#else +void silk_TimerSave(char *file_name) +{ + if( silk_Timer_nTimers > 0 ) + { + int k; + FILE *fp; + /* print results to file */ + fp = fopen(file_name, "w"); + fprintf(fp, " min avg max count\n"); + for( k = 0; k < silk_Timer_nTimers; k++ ) + { + if (silk_Timer_depth[k] == 0) { + fprintf(fp, "%-28s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 1) { + fprintf(fp, " %-27s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 2) { + fprintf(fp, " %-26s", silk_Timer_tags[k]); + } else if (silk_Timer_depth[k] == 3) { + fprintf(fp, " %-25s", silk_Timer_tags[k]); + } else { + fprintf(fp, " %-24s", silk_Timer_tags[k]); + } + fprintf(fp, "%d ", silk_Timer_min[k]); + fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]); + fprintf(fp, "%d ", silk_Timer_max[k]); + fprintf(fp, "%10d\n", silk_Timer_cnt[k]); + } + fprintf(fp, " microseconds\n"); + fclose(fp); + } +} +#endif + +#endif /* SILK_TIC_TOC */ + +#if SILK_DEBUG +FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +int silk_debug_store_count = 0; +#endif /* SILK_DEBUG */ + diff --git a/src/libopus/silk/debug.h b/src/libopus/silk/debug.h new file mode 100644 index 00000000..6f68c1ca --- /dev/null +++ b/src/libopus/silk/debug.h @@ -0,0 +1,266 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_DEBUG_H +#define SILK_DEBUG_H + +#include "typedef.h" +#include /* file writing */ +#include /* strcpy, strcmp */ + +#ifdef __cplusplus +extern "C" +{ +#endif + +unsigned long GetHighResolutionTime(void); /* O time in usec*/ + +/* Set to 1 to enable DEBUG_STORE_DATA() macros for dumping + * intermediate signals from the codec. + */ +#define SILK_DEBUG 0 + +/* Flag for using timers */ +#define SILK_TIC_TOC 0 + + +#if SILK_TIC_TOC + +#if (defined(_WIN32) || defined(_WINCE)) +#include /* timer */ +#else /* Linux or Mac*/ +#include +#endif + +/*********************************/ +/* timer functions for profiling */ +/*********************************/ +/* example: */ +/* */ +/* TIC(LPC) */ +/* do_LPC(in_vec, order, acoef); // do LPC analysis */ +/* TOC(LPC) */ +/* */ +/* and call the following just before exiting (from main) */ +/* */ +/* silk_TimerSave("silk_TimingData.txt"); */ +/* */ +/* results are now in silk_TimingData.txt */ + +void silk_TimerSave(char *file_name); + +/* max number of timers (in different locations) */ +#define silk_NUM_TIMERS_MAX 50 +/* max length of name tags in TIC(..), TOC(..) */ +#define silk_NUM_TIMERS_MAX_TAG_LEN 30 + +extern int silk_Timer_nTimers; +extern int silk_Timer_depth_ctr; +extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN]; +#ifdef _WIN32 +extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX]; +#else +extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX]; +#endif +extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX]; +extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX]; + +/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */ +#ifdef _WIN32 +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + QueryPerformanceCounter(&silk_Timer_start[ID]); \ +} +#else +#define TIC(TAG_NAME) { \ + static int init = 0; \ + static int ID = -1; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + if (ID == -1) { \ + ID = silk_Timer_nTimers; \ + silk_Timer_nTimers++; \ + silk_Timer_depth[ID] = silk_Timer_depth_ctr; \ + strcpy(silk_Timer_tags[ID], #TAG_NAME); \ + silk_Timer_cnt[ID] = 0; \ + silk_Timer_sum[ID] = 0; \ + silk_Timer_min[ID] = 0xFFFFFFFF; \ + silk_Timer_max[ID] = 0; \ + } \ + } \ + silk_Timer_depth_ctr++; \ + silk_Timer_start[ID] = GetHighResolutionTime(); \ +} +#endif + +#ifdef _WIN32 +#define TOC(TAG_NAME) { \ + LARGE_INTEGER lpPerformanceCount; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + QueryPerformanceCounter(&lpPerformanceCount); \ + lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \ + if((lpPerformanceCount.QuadPart < 100000000) && \ + (lpPerformanceCount.QuadPart >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \ + if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \ + } \ + silk_Timer_depth_ctr--; \ +} +#else +#define TOC(TAG_NAME) { \ + unsigned long endTime; \ + static int init = 0; \ + static int ID = 0; \ + if( init == 0 ) \ + { \ + int k; \ + init = 1; \ + for( k = 0; k < silk_Timer_nTimers; k++ ) { \ + if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \ + ID = k; \ + break; \ + } \ + } \ + } \ + endTime = GetHighResolutionTime(); \ + endTime -= silk_Timer_start[ID]; \ + if((endTime < 100000000) && \ + (endTime >= 0)) { \ + silk_Timer_cnt[ID]++; \ + silk_Timer_sum[ID] += endTime; \ + if( endTime > silk_Timer_max[ID] ) \ + silk_Timer_max[ID] = endTime; \ + if( endTime < silk_Timer_min[ID] ) \ + silk_Timer_min[ID] = endTime; \ + } \ + silk_Timer_depth_ctr--; \ +} +#endif + +#else /* SILK_TIC_TOC */ + +/* define macros as empty strings */ +#define TIC(TAG_NAME) +#define TOC(TAG_NAME) +#define silk_TimerSave(FILE_NAME) + +#endif /* SILK_TIC_TOC */ + + +#if SILK_DEBUG +/************************************/ +/* write data to file for debugging */ +/************************************/ +/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */ + +#define silk_NUM_STORES_MAX 100 +extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ]; +extern int silk_debug_store_count; + +/* Faster way of storing the data */ +#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \ + static opus_int init = 0, cnt = 0; \ + static FILE **fp; \ + if (init == 0) { \ + init = 1; \ + cnt = silk_debug_store_count++; \ + silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \ + } \ + fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \ +} + +/* Call this at the end of main() */ +#define SILK_DEBUG_STORE_CLOSE_FILES { \ + opus_int i; \ + for( i = 0; i < silk_debug_store_count; i++ ) { \ + fclose( silk_debug_store_fp[ i ] ); \ + } \ +} + +#else /* SILK_DEBUG */ + +/* define macros as empty strings */ +#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES) +#define SILK_DEBUG_STORE_CLOSE_FILES + +#endif /* SILK_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_DEBUG_H */ diff --git a/src/libopus/silk/dec_API.c b/src/libopus/silk/dec_API.c new file mode 100644 index 00000000..36b5ba5a --- /dev/null +++ b/src/libopus/silk/dec_API.c @@ -0,0 +1,419 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#include "API.h" +#include "main.h" +#include "../celt/stack_alloc.h" +#include "../celt/os_support.h" + +/************************/ +/* Decoder Super Struct */ +/************************/ +typedef struct { + silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ]; + stereo_dec_state sStereo; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int prev_decode_only_middle; +} silk_decoder; + +/*********************/ +/* Decoder functions */ +/*********************/ + +opus_int silk_Get_Decoder_Size( /* O Returns error code */ + opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *decSizeBytes = sizeof( silk_decoder ); + + return ret; +} + +/* Reset decoder state */ +opus_int silk_InitDecoder( /* O Returns error code */ + void *decState /* I/O State */ +) +{ + opus_int n, ret = SILK_NO_ERROR; + silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state; + + for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) { + ret = silk_init_decoder( &channel_state[ n ] ); + } + silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo)); + /* Not strictly needed, but it's cleaner that way */ + ((silk_decoder *)decState)->prev_decode_only_middle = 0; + + return ret; +} + +/* Decode a frame */ +opus_int silk_Decode( /* O Returns error code */ + void* decState, /* I/O State */ + silk_DecControlStruct* decControl, /* I/O Control Structure */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int newPacketFlag, /* I Indicates first decoder call for this packet */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 *samplesOut, /* O Decoded output speech vector */ + opus_int32 *nSamplesOut, /* O Number of samples decoded */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR; + opus_int32 nSamplesOutDec, LBRR_symbol; + opus_int16 *samplesOut1_tmp[ 2 ]; + VARDECL( opus_int16, samplesOut1_tmp_storage1 ); + VARDECL( opus_int16, samplesOut1_tmp_storage2 ); + VARDECL( opus_int16, samplesOut2_tmp ); + opus_int32 MS_pred_Q13[ 2 ] = { 0 }; + opus_int16 *resample_out_ptr; + silk_decoder *psDec = ( silk_decoder * )decState; + silk_decoder_state *channel_state = psDec->channel_state; + opus_int has_side; + opus_int stereo_to_mono; + int delay_stack_alloc; + SAVE_STACK; + + celt_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 ); + + /**********************************/ + /* Test if first frame in payload */ + /**********************************/ + if( newPacketFlag ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */ + } + } + + /* If Mono -> Stereo transition in bitstream: init state of second channel */ + if( decControl->nChannelsInternal > psDec->nChannelsInternal ) { + ret += silk_init_decoder( &channel_state[ 1 ] ); + } + + stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 && + ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz ); + + if( channel_state[ 0 ].nFramesDecoded == 0 ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + opus_int fs_kHz_dec; + if( decControl->payloadSize_ms == 0 ) { + /* Assuming packet loss, use 10 ms */ + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 10 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 2; + } else if( decControl->payloadSize_ms == 20 ) { + channel_state[ n ].nFramesPerPacket = 1; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 40 ) { + channel_state[ n ].nFramesPerPacket = 2; + channel_state[ n ].nb_subfr = 4; + } else if( decControl->payloadSize_ms == 60 ) { + channel_state[ n ].nFramesPerPacket = 3; + channel_state[ n ].nb_subfr = 4; + } else { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_FRAME_SIZE; + } + fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1; + if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_DEC_INVALID_SAMPLING_FREQUENCY; + } + ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate ); + } + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) { + silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) ); + silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) ); + silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) ); + } + psDec->nChannelsAPI = decControl->nChannelsAPI; + psDec->nChannelsInternal = decControl->nChannelsInternal; + + if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) { + ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY; + RESTORE_STACK; + return( ret ); + } + + if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) { + /* First decoder call for this payload */ + /* Decode VAD flags and LBRR flag */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1); + } + channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1); + } + /* Decode LBRR flags */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) ); + if( channel_state[ n ].LBRR_flag ) { + if( channel_state[ n ].nFramesPerPacket == 1 ) { + channel_state[ n ].LBRR_flags[ 0 ] = 1; + } else { + LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1; + for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) { + channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1; + } + } + } + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + /* Regular decoding: skip all LBRR data */ + for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) { + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( channel_state[ n ].LBRR_flags[ i ] ) { + opus_int16 pulses[ MAX_FRAME_LENGTH ]; + opus_int condCoding; + + if( decControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding ); + silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType, + channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length ); + } + } + } + } + } + + /* Get MS predictor index */ + if( decControl->nChannelsInternal == 2 ) { + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) ) + { + silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 ); + /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */ + if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) || + ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ) + { + silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle ); + } else { + decode_only_middle = 0; + } + } else { + for( n = 0; n < 2; n++ ) { + MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ]; + } + } + } + + /* Reset side channel decoder prediction memory for first frame with side coding */ + if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) { + silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) ); + silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) ); + psDec->channel_state[ 1 ].lagPrev = 100; + psDec->channel_state[ 1 ].LastGainIndex = 10; + psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psDec->channel_state[ 1 ].first_frame_after_reset = 1; + } + + /* Check if the temp buffer fits into the output PCM buffer. If it fits, + we can delay allocating the temp buffer until after the SILK peak stack + usage. We need to use a < and not a <= because of the two extra samples. */ + delay_stack_alloc = decControl->internalSampleRate*decControl->nChannelsInternal + < decControl->API_sampleRate*decControl->nChannelsAPI; + ALLOC( samplesOut1_tmp_storage1, delay_stack_alloc ? ALLOC_NONE + : decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ), + opus_int16 ); + if ( delay_stack_alloc ) + { + samplesOut1_tmp[ 0 ] = samplesOut; + samplesOut1_tmp[ 1 ] = samplesOut + channel_state[ 0 ].frame_length + 2; + } else { + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage1; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage1 + channel_state[ 0 ].frame_length + 2; + } + + if( lostFlag == FLAG_DECODE_NORMAL ) { + has_side = !decode_only_middle; + } else { + has_side = !psDec->prev_decode_only_middle + || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 ); + } + /* Call decoder for one frame */ + for( n = 0; n < decControl->nChannelsInternal; n++ ) { + if( n == 0 || has_side ) { + opus_int FrameIndex; + opus_int condCoding; + + FrameIndex = channel_state[ 0 ].nFramesDecoded - n; + /* Use independent coding if no previous frame available */ + if( FrameIndex <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( lostFlag == FLAG_DECODE_LBRR ) { + condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY; + } else if( n > 0 && psDec->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding, arch); + } else { + silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) ); + } + channel_state[ n ].nFramesDecoded++; + } + + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) { + /* Convert Mid/Side to Left/Right */ + silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec ); + } else { + /* Buffering */ + silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) ); + } + + /* Number of output samples */ + *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) ); + + /* Set up pointers to temp buffers */ + ALLOC( samplesOut2_tmp, + decControl->nChannelsAPI == 2 ? *nSamplesOut : ALLOC_NONE, opus_int16 ); + if( decControl->nChannelsAPI == 2 ) { + resample_out_ptr = samplesOut2_tmp; + } else { + resample_out_ptr = samplesOut; + } + + ALLOC( samplesOut1_tmp_storage2, delay_stack_alloc + ? decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2 ) + : ALLOC_NONE, + opus_int16 ); + if ( delay_stack_alloc ) { + OPUS_COPY(samplesOut1_tmp_storage2, samplesOut, decControl->nChannelsInternal*(channel_state[ 0 ].frame_length + 2)); + samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage2; + samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage2 + channel_state[ 0 ].frame_length + 2; + } + for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) { + + /* Resample decoded signal to API_sampleRate */ + ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec ); + + /* Interleave if stereo output and stereo stream */ + if( decControl->nChannelsAPI == 2 ) { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ n + 2 * i ] = resample_out_ptr[ i ]; + } + } + } + + /* Create two channel output from mono stream */ + if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) { + if ( stereo_to_mono ){ + /* Resample right channel for newly collapsed stereo just in case + we weren't doing collapsing when switching to mono */ + ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec ); + + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ]; + } + } else { + for( i = 0; i < *nSamplesOut; i++ ) { + samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ]; + } + } + } + + /* Export pitch lag, measured at 48 kHz sampling rate */ + if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) { + int mult_tab[ 3 ] = { 6, 4, 3 }; + decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ]; + } else { + decControl->prevPitchLag = 0; + } + + if( lostFlag == FLAG_PACKET_LOST ) { + /* On packet loss, remove the gain clamping to prevent having the energy "bounce back" + if we lose packets when the energy is going down */ + for ( i = 0; i < psDec->nChannelsInternal; i++ ) + psDec->channel_state[ i ].LastGainIndex = 10; + } else { + psDec->prev_decode_only_middle = decode_only_middle; + } + RESTORE_STACK; + return ret; +} + +#if 0 +/* Getting table of contents for a packet */ +opus_int silk_get_TOC( + const opus_uint8 *payload, /* I Payload data */ + const opus_int nBytesIn, /* I Number of input bytes */ + const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */ + silk_TOC_struct *Silk_TOC /* O Type of content */ +) +{ + opus_int i, flags, ret = SILK_NO_ERROR; + + if( nBytesIn < 1 ) { + return -1; + } + if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) { + return -1; + } + + silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) ); + + /* For stereo, extract the flags for the mid channel */ + flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 ); + + Silk_TOC->inbandFECFlag = flags & 1; + for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) { + flags = silk_RSHIFT( flags, 1 ); + Silk_TOC->VADFlags[ i ] = flags & 1; + Silk_TOC->VADFlag |= flags & 1; + } + + return ret; +} +#endif diff --git a/src/libopus/silk/decode_core.c b/src/libopus/silk/decode_core.c new file mode 100644 index 00000000..eb7a9d26 --- /dev/null +++ b/src/libopus/silk/decode_core.c @@ -0,0 +1,237 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" + +/**********************************************************/ +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +/**********************************************************/ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType; + opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ]; + VARDECL( opus_int16, sLTP ); + VARDECL( opus_int32, sLTP_Q15 ); + opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10; + opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14; + VARDECL( opus_int32, res_Q14 ); + VARDECL( opus_int32, sLPC_Q14 ); + SAVE_STACK; + + silk_assert( psDec->prev_gain_Q16 != 0 ); + + ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 ); + ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 ); + ALLOC( res_Q14, psDec->subfr_length, opus_int32 ); + ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 ); + + offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ]; + + if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) { + NLSF_interpolation_flag = 1; + } else { + NLSF_interpolation_flag = 0; + } + + /* Decode excitation */ + rand_seed = psDec->indices.Seed; + for( i = 0; i < psDec->frame_length; i++ ) { + rand_seed = silk_RAND( rand_seed ); + psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 ); + if( psDec->exc_Q14[ i ] > 0 ) { + psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4; + } else + if( psDec->exc_Q14[ i ] < 0 ) { + psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4; + } + psDec->exc_Q14[ i ] += offset_Q10 << 4; + if( rand_seed < 0 ) { + psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ]; + } + + rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] ); + } + + /* Copy LPC state */ + silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + + pexc_Q14 = psDec->exc_Q14; + pxq = xq; + sLTP_buf_idx = psDec->ltp_mem_length; + /* Loop over subframes */ + for( k = 0; k < psDec->nb_subfr; k++ ) { + pres_Q14 = res_Q14; + A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ]; + + /* Preload LPC coeficients to array on stack. Gives small performance gain */ + silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) ); + B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ]; + signalType = psDec->indices.signalType; + + Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 ); + inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 ); + + /* Calculate gain adjustment factor */ + if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) { + gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 ); + + /* Scale short term state */ + for( i = 0; i < MAX_LPC_ORDER; i++ ) { + sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] ); + } + } else { + gain_adj_Q16 = (opus_int32)1 << 16; + } + + /* Save inv_gain */ + silk_assert( inv_gain_Q31 != 0 ); + psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ]; + + /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */ + if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED && + psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) { + + silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) ); + B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 ); + + signalType = TYPE_VOICED; + psDecCtrl->pitchL[ k ] = psDec->lagPrev; + } + + if( signalType == TYPE_VOICED ) { + /* Voiced */ + lag = psDecCtrl->pitchL[ k ]; + + /* Re-whitening */ + if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) { + /* Rewhiten with new A coefs */ + start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2; + celt_assert( start_idx > 0 ); + + if( k == 2 ) { + silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) ); + } + + silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ], + A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order, arch ); + + /* After rewhitening the LTP state is unscaled */ + if( k == 0 ) { + /* Do LTP downscaling to reduce inter-packet dependency */ + inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 ); + } + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] ); + } + } else { + /* Update LTP state when Gain changes */ + if( gain_adj_Q16 != (opus_int32)1 << 16 ) { + for( i = 0; i < lag + LTP_ORDER/2; i++ ) { + sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] ); + } + } + } + } + + /* Long-term prediction */ + if( signalType == TYPE_VOICED ) { + /* Set up pointer */ + pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ]; + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Unrolled loop */ + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LTP_pred_Q13 = 2; + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] ); + LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] ); + pred_lag_ptr++; + + /* Generate LPC excitation */ + pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 ); + + /* Update states */ + sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 ); + sLTP_buf_idx++; + } + } else { + pres_Q14 = pexc_Q14; + } + + for( i = 0; i < psDec->subfr_length; i++ ) { + /* Short-term prediction */ + celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 ); + /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */ + LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] ); + if( psDec->LPC_order == 16 ) { + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] ); + LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] ); + } + + /* Add prediction to LPC excitation */ + sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( pres_Q14[ i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) ); + + /* Scale with gain */ + pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) ); + } + + /* Update LPC filter state */ + silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) ); + pexc_Q14 += psDec->subfr_length; + pxq += psDec->subfr_length; + } + + /* Save LPC state */ + silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/src/libopus/silk/decode_frame.c b/src/libopus/silk/decode_frame.c new file mode 100644 index 00000000..bb8952d2 --- /dev/null +++ b/src/libopus/silk/decode_frame.c @@ -0,0 +1,130 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" +#include "PLC.h" + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( silk_decoder_control, psDecCtrl ); + opus_int L, mv_len, ret = 0; + SAVE_STACK; + + L = psDec->frame_length; + ALLOC( psDecCtrl, 1, silk_decoder_control ); + psDecCtrl->LTP_scale_Q14 = 0; + + /* Safety checks */ + celt_assert( L > 0 && L <= MAX_FRAME_LENGTH ); + + if( lostFlag == FLAG_DECODE_NORMAL || + ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) ) + { + VARDECL( opus_int16, pulses ); + ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) & + ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int16 ); + /*********************************************/ + /* Decode quantization indices of side info */ + /*********************************************/ + silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding ); + + /*********************************************/ + /* Decode quantization indices of excitation */ + /*********************************************/ + silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType, + psDec->indices.quantOffsetType, psDec->frame_length ); + + /********************************************/ + /* Decode parameters and pulse signal */ + /********************************************/ + silk_decode_parameters( psDec, psDecCtrl, condCoding ); + + /********************************************************/ + /* Run inverse NSQ */ + /********************************************************/ + silk_decode_core( psDec, psDecCtrl, pOut, pulses, arch ); + + /********************************************************/ + /* Update PLC state */ + /********************************************************/ + silk_PLC( psDec, psDecCtrl, pOut, 0, arch ); + + psDec->lossCnt = 0; + psDec->prevSignalType = psDec->indices.signalType; + celt_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 ); + + /* A frame has been decoded without errors */ + psDec->first_frame_after_reset = 0; + } else { + /* Handle packet loss by extrapolation */ + psDec->indices.signalType = psDec->prevSignalType; + silk_PLC( psDec, psDecCtrl, pOut, 1, arch ); + } + + /*************************/ + /* Update output buffer. */ + /*************************/ + celt_assert( psDec->ltp_mem_length >= psDec->frame_length ); + mv_len = psDec->ltp_mem_length - psDec->frame_length; + silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) ); + silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) ); + + /************************************************/ + /* Comfort noise generation / estimation */ + /************************************************/ + silk_CNG( psDec, psDecCtrl, pOut, L ); + + /****************************************************************/ + /* Ensure smooth connection of extrapolated and good frames */ + /****************************************************************/ + silk_PLC_glue_frames( psDec, pOut, L ); + + /* Update some decoder state variables */ + psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; + + /* Set output frame length */ + *pN = L; + + RESTORE_STACK; + return ret; +} diff --git a/src/libopus/silk/decode_indices.c b/src/libopus/silk/decode_indices.c new file mode 100644 index 00000000..da2952fb --- /dev/null +++ b/src/libopus/silk/decode_indices.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Decode side-information parameters from payload */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int decode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + + /*******************************************/ + /* Decode signal type and quantizer offset */ + /*******************************************/ + if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2; + } else { + Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 ); + } + psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 ); + psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 ); + + /****************/ + /* Decode gains */ + /****************/ + /* First subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* Conditional coding */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } else { + /* Independent coding, in two stages: MSB bits followed by 3 LSBs */ + psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 ); + psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 ); + } + + /* Remaining subframes */ + for( i = 1; i < psDec->nb_subfr; i++ ) { + psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 ); + } + + /**********************/ + /* Decode LSF Indices */ + /**********************/ + psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] ); + celt_assert( psDec->psNLSF_CB->order == psDec->LPC_order ); + for( i = 0; i < psDec->psNLSF_CB->order; i++ ) { + Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + if( Ix == 0 ) { + Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) { + Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 ); + } + psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE ); + } + + /* Decode LSF interpolation factor */ + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 ); + } else { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.signalType == TYPE_VOICED ) + { + /*********************/ + /* Decode pitch lags */ + /*********************/ + /* Get lag index */ + decode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) { + /* Decode Delta index */ + delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 ); + if( delta_lagIndex > 0 ) { + delta_lagIndex = delta_lagIndex - 9; + psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex ); + decode_absolute_lagIndex = 0; + } + } + if( decode_absolute_lagIndex ) { + /* Absolute decoding */ + psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 ); + psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 ); + } + psDec->ec_prevLagIndex = psDec->indices.lagIndex; + + /* Get countour index */ + psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 ); + + /********************/ + /* Decode LTP gains */ + /********************/ + /* Decode PERIndex value */ + psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 ); + + for( k = 0; k < psDec->nb_subfr; k++ ) { + psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 ); + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 ); + } else { + psDec->indices.LTP_scaleIndex = 0; + } + } + psDec->ec_prevSignalType = psDec->indices.signalType; + + /***************/ + /* Decode seed */ + /***************/ + psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 ); +} diff --git a/src/libopus/silk/decode_parameters.c b/src/libopus/silk/decode_parameters.c new file mode 100644 index 00000000..40a571b5 --- /dev/null +++ b/src/libopus/silk/decode_parameters.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, Ix; + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ]; + const opus_int8 *cbk_ptr_Q7; + + /* Dequant Gains */ + silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices, + &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr ); + + /****************/ + /* Decode NLSFs */ + /****************/ + silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB ); + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order, psDec->arch ); + + /* If just reset, e.g., because internal Fs changed, do not allow interpolation */ + /* improves the case of packet loss in the first frame after a switch */ + if( psDec->first_frame_after_reset == 1 ) { + psDec->indices.NLSFInterpCoef_Q2 = 4; + } + + if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) { + /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */ + /* the previous NLSF1, and the current NLSF1 */ + for( i = 0; i < psDec->LPC_order; i++ ) { + pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2, + pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 ); + } + + /* Convert NLSF parameters to AR prediction filter coefficients */ + silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order, psDec->arch ); + } else { + /* Copy LPC coefficients for first half from second half */ + silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) ); + } + + silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) ); + + /* After a packet loss do BWE of LPC coefs */ + if( psDec->lossCnt ) { + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 ); + } + + if( psDec->indices.signalType == TYPE_VOICED ) { + /*********************/ + /* Decode pitch lags */ + /*********************/ + + /* Decode pitch values */ + silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr ); + + /* Decode Codebook Index */ + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */ + + for( k = 0; k < psDec->nb_subfr; k++ ) { + Ix = psDec->indices.LTPIndex[ k ]; + for( i = 0; i < LTP_ORDER; i++ ) { + psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 ); + } + } + + /**********************/ + /* Decode LTP scaling */ + /**********************/ + Ix = psDec->indices.LTP_scaleIndex; + psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ]; + } else { + silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) ); + silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) ); + psDec->indices.PERIndex = 0; + psDecCtrl->LTP_scale_Q14 = 0; + } +} diff --git a/src/libopus/silk/decode_pitch.c b/src/libopus/silk/decode_pitch.c new file mode 100644 index 00000000..620f6a19 --- /dev/null +++ b/src/libopus/silk/decode_pitch.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "SigProc_FIX.h" +#include "pitch_est_defines.h" + +void silk_decode_pitch( + opus_int16 lagIndex, /* I */ + opus_int8 contourIndex, /* O */ + opus_int pitch_lags[], /* O 4 pitch values */ + const opus_int Fs_kHz, /* I sampling frequency (kHz) */ + const opus_int nb_subfr /* I number of sub frames */ +) +{ + opus_int lag, k, min_lag, max_lag, cbk_size; + const opus_int8 *Lag_CB_ptr; + + if( Fs_kHz == 8 ) { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_EXT; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE2_10MS; + } + } else { + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 ); + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + } + + min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz ); + max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz ); + lag = min_lag + lagIndex; + + for( k = 0; k < nb_subfr; k++ ) { + pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size ); + pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag ); + } +} diff --git a/src/libopus/silk/decode_pulses.c b/src/libopus/silk/decode_pulses.c new file mode 100644 index 00000000..872b7e73 --- /dev/null +++ b/src/libopus/silk/decode_pulses.c @@ -0,0 +1,115 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/*********************************************/ +/* Decode quantization indices of excitation */ +/*********************************************/ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex; + opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ]; + opus_int16 *pulses_ptr; + const opus_uint8 *cdf_ptr; + + /*********************/ + /* Decode rate level */ + /*********************/ + RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + } + + /***************************************************/ + /* Sum-Weighted-Pulses Decoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + nLshifts[ i ] = 0; + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 ); + + /* LSB indication */ + while( sum_pulses[ i ] == SILK_MAX_PULSES + 1 ) { + nLshifts[ i ]++; + /* When we've already got 10 LSBs, we shift the table to not allow (SILK_MAX_PULSES + 1) */ + sum_pulses[ i ] = ec_dec_icdf( psRangeDec, + silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 ); + } + } + + /***************************************************/ + /* Shell decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] ); + } else { + silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( pulses[0] ) ); + } + } + + /***************************************************/ + /* LSB Decoding */ + /***************************************************/ + for( i = 0; i < iter; i++ ) { + if( nLshifts[ i ] > 0 ) { + nLS = nLshifts[ i ]; + pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ]; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = pulses_ptr[ k ]; + for( j = 0; j < nLS; j++ ) { + abs_q = silk_LSHIFT( abs_q, 1 ); + abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 ); + } + pulses_ptr[ k ] = abs_q; + } + /* Mark the number of pulses non-zero for sign decoding. */ + sum_pulses[ i ] |= nLS << 5; + } + } + + /****************************************/ + /* Decode and add signs to pulse signal */ + /****************************************/ + silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); +} diff --git a/src/libopus/silk/decoder_set_fs.c b/src/libopus/silk/decoder_set_fs.c new file mode 100644 index 00000000..4550d767 --- /dev/null +++ b/src/libopus/silk/decoder_set_fs.c @@ -0,0 +1,108 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +) +{ + opus_int frame_length, ret = 0; + + celt_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 ); + celt_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 ); + + /* New (sub)frame length */ + psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz ); + frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length ); + + /* Initialize resampler when switching internal or external sampling frequency */ + if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) { + /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */ + ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 ); + + psDec->fs_API_hz = fs_API_Hz; + } + + if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) { + if( fs_kHz == 8 ) { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF; + } + } else { + if( psDec->nb_subfr == MAX_NB_SUBFR ) { + psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF; + } else { + psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF; + } + } + if( psDec->fs_kHz != fs_kHz ) { + psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz ); + if( fs_kHz == 8 || fs_kHz == 12 ) { + psDec->LPC_order = MIN_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB; + } else { + psDec->LPC_order = MAX_LPC_ORDER; + psDec->psNLSF_CB = &silk_NLSF_CB_WB; + } + if( fs_kHz == 16 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF; + } else if( fs_kHz == 12 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF; + } else if( fs_kHz == 8 ) { + psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF; + } else { + /* unsupported sampling rate */ + celt_assert( 0 ); + } + psDec->first_frame_after_reset = 1; + psDec->lagPrev = 100; + psDec->LastGainIndex = 10; + psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY; + silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf)); + silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) ); + } + + psDec->fs_kHz = fs_kHz; + psDec->frame_length = frame_length; + } + + /* Check that settings are valid */ + celt_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH ); + + return ret; +} + diff --git a/src/libopus/silk/define.h b/src/libopus/silk/define.h new file mode 100644 index 00000000..247cb0bf --- /dev/null +++ b/src/libopus/silk/define.h @@ -0,0 +1,234 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_DEFINE_H +#define SILK_DEFINE_H + +#include "errors.h" +#include "typedef.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Max number of encoder channels (1/2) */ +#define ENCODER_NUM_CHANNELS 2 +/* Number of decoder channels (1/2) */ +#define DECODER_NUM_CHANNELS 2 + +#define MAX_FRAMES_PER_PACKET 3 + +/* Limits on bitrate */ +#define MIN_TARGET_RATE_BPS 5000 +#define MAX_TARGET_RATE_BPS 80000 + +/* LBRR thresholds */ +#define LBRR_NB_MIN_RATE_BPS 12000 +#define LBRR_MB_MIN_RATE_BPS 14000 +#define LBRR_WB_MIN_RATE_BPS 16000 + +/* DTX settings */ +#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */ +#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */ +#define DTX_ACTIVITY_THRESHOLD 0.1f + +/* VAD decision */ +#define VAD_NO_DECISION -1 +#define VAD_NO_ACTIVITY 0 +#define VAD_ACTIVITY 1 + +/* Maximum sampling frequency */ +#define MAX_FS_KHZ 16 +#define MAX_API_FS_KHZ 48 + +/* Signal types */ +#define TYPE_NO_VOICE_ACTIVITY 0 +#define TYPE_UNVOICED 1 +#define TYPE_VOICED 2 + +/* Conditional coding types */ +#define CODE_INDEPENDENTLY 0 +#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1 +#define CODE_CONDITIONALLY 2 + +/* Settings for stereo processing */ +#define STEREO_QUANT_TAB_SIZE 16 +#define STEREO_QUANT_SUB_STEPS 5 +#define STEREO_INTERP_LEN_MS 8 /* must be even */ +#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */ + +/* Range of pitch lag estimates */ +#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ + +/* Maximum number of subframes */ +#define MAX_NB_SUBFR 4 + +/* Number of samples per frame */ +#define LTP_MEM_LENGTH_MS 20 +#define SUB_FRAME_LENGTH_MS 5 +#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ ) +#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR ) +#define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for pitch analysis */ +#define LA_PITCH_MS 2 +#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ ) + +/* Order of LPC used in find pitch */ +#define MAX_FIND_PITCH_LPC_ORDER 16 + +/* Length of LPC window used in find pitch */ +#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) ) +#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ ) + +/* Milliseconds of lookahead for noise shape analysis */ +#define LA_SHAPE_MS 5 +#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ ) + +/* Maximum length of LPC window used in noise shape analysis */ +#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ ) + +/* dB level of lowest gain quantization level */ +#define MIN_QGAIN_DB 2 +/* dB level of highest gain quantization level */ +#define MAX_QGAIN_DB 88 +/* Number of gain quantization levels */ +#define N_LEVELS_QGAIN 64 +/* Max increase in gain quantization index */ +#define MAX_DELTA_GAIN_QUANT 36 +/* Max decrease in gain quantization index */ +#define MIN_DELTA_GAIN_QUANT -4 + +/* Quantization offsets (multiples of 4) */ +#define OFFSET_VL_Q10 32 +#define OFFSET_VH_Q10 100 +#define OFFSET_UVL_Q10 100 +#define OFFSET_UVH_Q10 240 + +#define QUANT_LEVEL_ADJUST_Q10 80 + +/* Maximum numbers of iterations used to stabilize an LPC vector */ +#define MAX_LPC_STABILIZE_ITERATIONS 16 +#define MAX_PREDICTION_POWER_GAIN 1e4f +#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f + +#define MAX_LPC_ORDER 16 +#define MIN_LPC_ORDER 10 + +/* Find Pred Coef defines */ +#define LTP_ORDER 5 + +/* LTP quantization settings */ +#define NB_LTP_CBKS 3 + +/* Flag to use harmonic noise shaping */ +#define USE_HARM_SHAPING 1 + +/* Max LPC order of noise shaping filters */ +#define MAX_SHAPE_LPC_ORDER 24 + +#define HARM_SHAPE_FIR_TAPS 3 + +/* Maximum number of delayed decision states */ +#define MAX_DEL_DEC_STATES 4 + +#define LTP_BUF_LENGTH 512 +#define LTP_MASK ( LTP_BUF_LENGTH - 1 ) + +#define DECISION_DELAY 40 + +/* Number of subframes for excitation entropy coding */ +#define SHELL_CODEC_FRAME_LENGTH 16 +#define LOG2_SHELL_CODEC_FRAME_LENGTH 4 +#define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH ) + +/* Number of rate levels, for entropy coding of excitation */ +#define N_RATE_LEVELS 10 + +/* Maximum sum of pulses per shell coding frame */ +#define SILK_MAX_PULSES 16 + +#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */ + +# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER + +/***************************/ +/* Voice activity detector */ +/***************************/ +#define VAD_N_BANDS 4 + +#define VAD_INTERNAL_SUBFRAMES_LOG2 2 +#define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 ) + +#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */ +#define VAD_NOISE_LEVELS_BIAS 50 + +/* Sigmoid settings */ +#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */ +#define VAD_SNR_FACTOR_Q16 45000 + +/* smoothing for SNR measurement */ +#define VAD_SNR_SMOOTH_COEF_Q18 4096 + +/* Size of the piecewise linear cosine approximation table for the LSFs */ +#define LSF_COS_TAB_SZ_FIX 128 + +/******************/ +/* NLSF quantizer */ +/******************/ +#define NLSF_W_Q 2 +#define NLSF_VQ_MAX_VECTORS 32 +#define NLSF_QUANT_MAX_AMPLITUDE 4 +#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10 +#define NLSF_QUANT_LEVEL_ADJ 0.1 +#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2 +#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 ) + +/* Transition filtering for mode switching */ +#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/ +#define TRANSITION_NB 3 /* Hardcoded in tables */ +#define TRANSITION_NA 2 /* Hardcoded in tables */ +#define TRANSITION_INT_NUM 5 /* Hardcoded in tables */ +#define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS ) +#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) ) + +/* BWE factors to apply after packet loss */ +#define BWE_AFTER_LOSS_Q16 63570 + +/* Defines for CN generation */ +#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */ +#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */ +#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/silk/enc_API.c b/src/libopus/silk/enc_API.c new file mode 100644 index 00000000..97f37935 --- /dev/null +++ b/src/libopus/silk/enc_API.c @@ -0,0 +1,576 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#include "define.h" +#include "API.h" +#include "control.h" +#include "typedef.h" +#include "../celt/stack_alloc.h" +#include "structs.h" +#include "tuning_parameters.h" +#ifdef FIXED_POINT +#include "fixed/main_FIX.h" +#else +#include "main_FLP.h" +#endif + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +); + +/****************************************/ +/* Encoder functions */ +/****************************************/ + +opus_int silk_Get_Encoder_Size( /* O Returns error code */ + opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */ +) +{ + opus_int ret = SILK_NO_ERROR; + + *encSizeBytes = sizeof( silk_encoder ); + + return ret; +} + +/*************************/ +/* Init or Reset encoder */ +/*************************/ +opus_int silk_InitEncoder( /* O Returns error code */ + void *encState, /* I/O State */ + int arch, /* I Run-time architecture */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + silk_encoder *psEnc; + opus_int n, ret = SILK_NO_ERROR; + + psEnc = (silk_encoder *)encState; + + /* Reset encoder */ + silk_memset( psEnc, 0, sizeof( silk_encoder ) ); + for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) { + if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) { + celt_assert( 0 ); + } + } + + psEnc->nChannelsAPI = 1; + psEnc->nChannelsInternal = 1; + + /* Read control structure */ + if( ret += silk_QueryEncoder( encState, encStatus ) ) { + celt_assert( 0 ); + } + + return ret; +} + +/***************************************/ +/* Read control structure from encoder */ +/***************************************/ +static opus_int silk_QueryEncoder( /* O Returns error code */ + const void *encState, /* I State */ + silk_EncControlStruct *encStatus /* O Encoder Status */ +) +{ + opus_int ret = SILK_NO_ERROR; + silk_encoder_state_Fxx *state_Fxx; + silk_encoder *psEnc = (silk_encoder *)encState; + + state_Fxx = psEnc->state_Fxx; + + encStatus->nChannelsAPI = psEnc->nChannelsAPI; + encStatus->nChannelsInternal = psEnc->nChannelsInternal; + encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz; + encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz; + encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz; + encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz; + encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms; + encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps; + encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc; + encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity; + encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC; + encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX; + encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR; + encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch; + encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0; + + return ret; +} + + +/**************************/ +/* Encode frame with Silk */ +/**************************/ +/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */ +/* encControl->payloadSize_ms is set to */ +opus_int silk_Encode( /* O Returns error code */ + void *encState, /* I/O State */ + silk_EncControlStruct *encControl, /* I Control status */ + const opus_int16 *samplesIn, /* I Speech sample input vector */ + opus_int nSamplesIn, /* I Number of samples in input vector */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */ + const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0; + opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms; + opus_int nSamplesFromInput = 0, nSamplesFromInputMax; + opus_int speech_act_thr_for_switch_Q8; + opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum; + silk_encoder *psEnc = ( silk_encoder * )encState; + VARDECL( opus_int16, buf ); + opus_int transition, curr_block, tot_blocks; + SAVE_STACK; + + if (encControl->reducedDependency) + { + psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1; + psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1; + } + psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0; + + /* Check values in encoder control structure */ + if( ( ret = check_control_input( encControl ) ) != 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return ret; + } + + encControl->switchReady = 0; + + if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) { + /* Mono -> Stereo transition: init state of second channel and stereo state */ + ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch ); + silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) ); + silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) ); + psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1; + psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0; + psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1; + psEnc->sStereo.width_prev_Q14 = 0; + psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 ); + if( psEnc->nChannelsAPI == 2 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) ); + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) ); + } + } + + transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal); + + psEnc->nChannelsAPI = encControl->nChannelsAPI; + psEnc->nChannelsInternal = encControl->nChannelsInternal; + + nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate ); + tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1; + curr_block = 0; + if( prefillFlag ) { + silk_LP_state save_LP; + /* Only accept input length of 10 ms */ + if( nBlocksOf10ms != 1 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + if ( prefillFlag == 2 ) { + save_LP = psEnc->state_Fxx[ 0 ].sCmn.sLP; + /* Save the sampling rate so the bandwidth switching code can keep handling transitions. */ + save_LP.saved_fs_kHz = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + } + /* Reset Encoder */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch ); + /* Restore the variable LP state. */ + if ( prefillFlag == 2 ) { + psEnc->state_Fxx[ n ].sCmn.sLP = save_LP; + } + celt_assert( !ret ); + } + tmp_payloadSize_ms = encControl->payloadSize_ms; + encControl->payloadSize_ms = 10; + tmp_complexity = encControl->complexity; + encControl->complexity = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1; + } + } else { + /* Only accept input lengths that are a multiple of 10 ms */ + if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + /* Make sure no more than one packet can be produced */ + if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) { + celt_assert( 0 ); + RESTORE_STACK; + return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES; + } + } + + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + /* Force the side channel to the same rate as the mid */ + opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0; + if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) { + silk_assert( 0 ); + RESTORE_STACK; + return ret; + } + if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) { + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0; + } + } + psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX; + } + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + + /* Input buffering/resampling and encoding */ + nSamplesToBufferMax = + 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz; + nSamplesFromInputMax = + silk_DIV32_16( nSamplesToBufferMax * + psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + ALLOC( buf, nSamplesFromInputMax, opus_int16 ); + while( 1 ) { + nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax ); + nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 ); + /* Resample and write to buffer */ + if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) { + opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n ]; + } + /* Making sure to start both resamplers from the same state when switching from mono to stereo */ + if( psEnc->nPrevChannelsInternal == 1 && id==0 ) { + silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state)); + } + + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + + nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx; + nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz ); + for( n = 0; n < nSamplesFromInput; n++ ) { + buf[ n ] = samplesIn[ 2 * n + 1 ]; + } + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + + psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer; + } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) { + /* Combine left and right channels before resampling */ + for( n = 0; n < nSamplesFromInput; n++ ) { + sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ]; + buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + } + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + /* On the first mono frame, average the results for the two resampler states */ + if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) { + ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) { + psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] = + silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] + + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1); + } + } + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } else { + celt_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 ); + silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16)); + ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, + &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput ); + psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer; + } + + samplesIn += nSamplesFromInput * encControl->nChannelsAPI; + nSamplesIn -= nSamplesFromInput; + + /* Default */ + psEnc->allowBandwidthSwitch = 0; + + /* Silk encoder */ + if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) { + /* Enough data in input buffer, so encode */ + celt_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + celt_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length ); + + /* Deal with LBRR data */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) { + /* Create space at start of payload for VAD and FEC flags */ + opus_uint8 iCDF[ 2 ] = { 0, 0 }; + iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + ec_enc_icdf( psRangeEnc, 0, iCDF, 8 ); + + /* Encode any LBRR data from previous packet */ + /* Encode LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + LBRR_symbol = 0; + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i ); + } + psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0; + if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) { + ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 ); + } + } + + /* Code LBRR indices and excitation signals */ + for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) { + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) { + opus_int condCoding; + + if( encControl->nChannelsInternal == 2 && n == 0 ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] ); + /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */ + if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] ); + } + } + /* Use conditional coding if previous frame available */ + if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) { + condCoding = CODE_CONDITIONALLY; + } else { + condCoding = CODE_INDEPENDENTLY; + } + silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding ); + silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType, + psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length ); + } + } + } + + /* Reset LBRR flags */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) ); + } + + psEnc->nBitsUsedLBRR = ec_tell( psRangeEnc ); + } + + silk_HP_variable_cutoff( psEnc->state_Fxx ); + + /* Total target bits for packet */ + nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + /* Subtract bits used for LBRR */ + if( !prefillFlag ) { + nBits -= psEnc->nBitsUsedLBRR; + } + /* Divide by number of uncoded frames left in packet */ + nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket ); + /* Convert to bits/second */ + if( encControl->payloadSize_ms == 10 ) { + TargetRate_bps = silk_SMULBB( nBits, 100 ); + } else { + TargetRate_bps = silk_SMULBB( nBits, 50 ); + } + /* Subtract fraction of bits in excess of target in previous frames and packets */ + TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + if( !prefillFlag && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded > 0 ) { + /* Compare actual vs target bits so far in this packet */ + opus_int32 bitsBalance = ec_tell( psRangeEnc ) - psEnc->nBitsUsedLBRR - nBits * psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded; + TargetRate_bps -= silk_DIV32_16( silk_MUL( bitsBalance, 1000 ), BITRESERVOIR_DECAY_TIME_MS ); + } + /* Never exceed input bitrate */ + TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 ); + + /* Convert Left/Right to Mid/Side */ + if( encControl->nChannelsInternal == 2 ) { + silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ], + psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], + MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono, + psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length ); + if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + /* Reset side channel encoder memory for first frame with side coding */ + if( psEnc->prev_decode_only_middle == 1 ) { + silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) ); + silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) ); + silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) ); + psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100; + psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10; + psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536; + psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1; + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ], activity ); + } else { + psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0; + } + if( !prefillFlag ) { + silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) { + silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] ); + } + } + } else { + /* Buffering */ + silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) ); + } + silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ], activity ); + + /* Encode */ + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + opus_int maxBits, useCBR; + + /* Handling rate constraints */ + maxBits = encControl->maxBits; + if( tot_blocks == 2 && curr_block == 0 ) { + maxBits = maxBits * 3 / 5; + } else if( tot_blocks == 3 ) { + if( curr_block == 0 ) { + maxBits = maxBits * 2 / 5; + } else if( curr_block == 1 ) { + maxBits = maxBits * 3 / 4; + } + } + useCBR = encControl->useCBR && curr_block == tot_blocks - 1; + + if( encControl->nChannelsInternal == 1 ) { + channelRate_bps = TargetRate_bps; + } else { + channelRate_bps = MStargetRates_bps[ n ]; + if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) { + useCBR = 0; + /* Give mid up to 1/2 of the max bits for that frame */ + maxBits -= encControl->maxBits / ( tot_blocks * 2 ); + } + } + + if( channelRate_bps > 0 ) { + opus_int condCoding; + + silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps ); + + /* Use independent coding if no previous frame available */ + if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) { + condCoding = CODE_INDEPENDENTLY; + } else if( n > 0 && psEnc->prev_decode_only_middle ) { + /* If we skipped a side frame in this packet, we don't + need LTP scaling; the LTP state is well-defined. */ + condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING; + } else { + condCoding = CODE_CONDITIONALLY; + } + if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) { + silk_assert( 0 ); + } + } + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0; + psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++; + } + psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ]; + + /* Insert VAD and FEC flags at beginning of bitstream */ + if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) { + flags = 0; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) { + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ]; + } + flags = silk_LSHIFT( flags, 1 ); + flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag; + } + if( !prefillFlag ) { + ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal ); + } + + /* Return zero bytes if all channels DTXed */ + if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) { + *nBytesOut = 0; + } + + psEnc->nBitsExceeded += *nBytesOut * 8; + psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 ); + psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 ); + + /* Update flag indicating if bandwidth switching is allowed */ + speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ), + SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms ); + if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) { + psEnc->allowBandwidthSwitch = 1; + psEnc->timeSinceSwitchAllowed_ms = 0; + } else { + psEnc->allowBandwidthSwitch = 0; + psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms; + } + } + + if( nSamplesIn == 0 ) { + break; + } + } else { + break; + } + curr_block++; + } + + psEnc->nPrevChannelsInternal = encControl->nChannelsInternal; + + encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch; + encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0; + encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 ); + encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14; + if( prefillFlag ) { + encControl->payloadSize_ms = tmp_payloadSize_ms; + encControl->complexity = tmp_complexity; + for( n = 0; n < encControl->nChannelsInternal; n++ ) { + psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0; + psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0; + } + } + + encControl->signalType = psEnc->state_Fxx[0].sCmn.indices.signalType; + encControl->offset = silk_Quantization_Offsets_Q10 + [ psEnc->state_Fxx[0].sCmn.indices.signalType >> 1 ] + [ psEnc->state_Fxx[0].sCmn.indices.quantOffsetType ]; + RESTORE_STACK; + return ret; +} + diff --git a/src/libopus/silk/encode_indices.c b/src/libopus/silk/encode_indices.c new file mode 100644 index 00000000..0892b3f7 --- /dev/null +++ b/src/libopus/silk/encode_indices.c @@ -0,0 +1,181 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Encode side-information parameters to payload */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int i, k, typeOffset; + opus_int encode_absolute_lagIndex, delta_lagIndex; + opus_int16 ec_ix[ MAX_LPC_ORDER ]; + opus_uint8 pred_Q8[ MAX_LPC_ORDER ]; + const SideInfoIndices *psIndices; + + if( encode_LBRR ) { + psIndices = &psEncC->indices_LBRR[ FrameIndex ]; + } else { + psIndices = &psEncC->indices; + } + + /*******************************************/ + /* Encode signal type and quantizer offset */ + /*******************************************/ + typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType; + celt_assert( typeOffset >= 0 && typeOffset < 6 ); + celt_assert( encode_LBRR == 0 || typeOffset >= 2 ); + if( encode_LBRR || typeOffset >= 2 ) { + ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 ); + } + + /****************/ + /* Encode gains */ + /****************/ + /* first subframe */ + if( condCoding == CODE_CONDITIONALLY ) { + /* conditional coding */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 ); + } else { + /* independent coding, in two stages: MSB bits followed by 3 LSBs */ + silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN ); + ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 ); + } + + /* remaining subframes */ + for( i = 1; i < psEncC->nb_subfr; i++ ) { + silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ); + ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 ); + } + + /****************/ + /* Encode NLSFs */ + /****************/ + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 ); + silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] ); + celt_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder ); + for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) { + if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) { + ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 ); + } else { + ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 ); + } + } + + /* Encode NLSF interpolation factor */ + if( psEncC->nb_subfr == MAX_NB_SUBFR ) { + silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 ); + ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 ); + } + + if( psIndices->signalType == TYPE_VOICED ) + { + /*********************/ + /* Encode pitch lags */ + /*********************/ + /* lag index */ + encode_absolute_lagIndex = 1; + if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) { + /* Delta Encoding */ + delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex; + if( delta_lagIndex < -8 || delta_lagIndex > 11 ) { + delta_lagIndex = 0; + } else { + delta_lagIndex = delta_lagIndex + 9; + encode_absolute_lagIndex = 0; /* Only use delta */ + } + silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 ); + ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 ); + } + if( encode_absolute_lagIndex ) { + /* Absolute encoding */ + opus_int32 pitch_high_bits, pitch_low_bits; + pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) ); + silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 ); + silk_assert( pitch_high_bits < 32 ); + ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 ); + } + psEncC->ec_prevLagIndex = psIndices->lagIndex; + + /* Countour index */ + silk_assert( psIndices->contourIndex >= 0 ); + silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) || + ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) || + ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) ); + ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 ); + + /********************/ + /* Encode LTP gains */ + /********************/ + /* PERIndex value */ + silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 ); + + /* Codebook Indices */ + for( k = 0; k < psEncC->nb_subfr; k++ ) { + silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) ); + ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 ); + } + + /**********************/ + /* Encode LTP scaling */ + /**********************/ + if( condCoding == CODE_INDEPENDENTLY ) { + silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 ); + ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 ); + } + silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 ); + } + + psEncC->ec_prevSignalType = psIndices->signalType; + + /***************/ + /* Encode seed */ + /***************/ + silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 ); + ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 ); +} diff --git a/src/libopus/silk/encode_pulses.c b/src/libopus/silk/encode_pulses.c new file mode 100644 index 00000000..4c5db41a --- /dev/null +++ b/src/libopus/silk/encode_pulses.c @@ -0,0 +1,206 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" + +/*********************************************/ +/* Encode quantization indices of excitation */ +/*********************************************/ + +static OPUS_INLINE opus_int combine_and_check( /* return ok */ + opus_int *pulses_comb, /* O */ + const opus_int *pulses_in, /* I */ + opus_int max_pulses, /* I max value for sum of pulses */ + opus_int len /* I number of output values */ +) +{ + opus_int k, sum; + + for( k = 0; k < len; k++ ) { + sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ]; + if( sum > max_pulses ) { + return 1; + } + pulses_comb[ k ] = sum; + } + + return 0; +} + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +) +{ + opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0; + opus_int32 abs_q, minSumBits_Q5, sumBits_Q5; + VARDECL( opus_int, abs_pulses ); + VARDECL( opus_int, sum_pulses ); + VARDECL( opus_int, nRshifts ); + opus_int pulses_comb[ 8 ]; + opus_int *abs_pulses_ptr; + const opus_int8 *pulses_ptr; + const opus_uint8 *cdf_ptr; + const opus_uint8 *nBits_ptr; + SAVE_STACK; + + silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/ + + /****************************/ + /* Prepare for shell coding */ + /****************************/ + /* Calculate number of shell blocks */ + silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH ); + iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH ); + if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) { + celt_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */ + iter++; + silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8)); + } + + /* Take the absolute value of the pulses */ + ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int ); + silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) ); + for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) { + abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] ); + abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] ); + abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] ); + abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] ); + } + + /* Calc sum pulses per shell code frame */ + ALLOC( sum_pulses, iter, opus_int ); + ALLOC( nRshifts, iter, opus_int ); + abs_pulses_ptr = abs_pulses; + for( i = 0; i < iter; i++ ) { + nRshifts[ i ] = 0; + + while( 1 ) { + /* 1+1 -> 2 */ + scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 ); + /* 2+2 -> 4 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 ); + /* 4+4 -> 8 */ + scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 ); + /* 8+8 -> 16 */ + scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 ); + + if( scale_down ) { + /* We need to downscale the quantization signal */ + nRshifts[ i ]++; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 ); + } + } else { + /* Jump out of while(1) loop and go to next shell coding frame */ + break; + } + } + abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH; + } + + /**************/ + /* Rate level */ + /**************/ + /* find rate level that leads to fewest bits for coding of pulses per block info */ + minSumBits_Q5 = silk_int32_MAX; + for( k = 0; k < N_RATE_LEVELS - 1; k++ ) { + nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ]; + sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + sumBits_Q5 += nBits_ptr[ SILK_MAX_PULSES + 1 ]; + } else { + sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ]; + } + } + if( sumBits_Q5 < minSumBits_Q5 ) { + minSumBits_Q5 = sumBits_Q5; + RateLevelIndex = k; + } + } + ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 ); + + /***************************************************/ + /* Sum-Weighted-Pulses Encoding */ + /***************************************************/ + cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ]; + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] == 0 ) { + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 ); + } else { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, cdf_ptr, 8 ); + for( k = 0; k < nRshifts[ i ] - 1; k++ ) { + ec_enc_icdf( psRangeEnc, SILK_MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 ); + } + } + + /******************/ + /* Shell Encoding */ + /******************/ + for( i = 0; i < iter; i++ ) { + if( sum_pulses[ i ] > 0 ) { + silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] ); + } + } + + /****************/ + /* LSB Encoding */ + /****************/ + for( i = 0; i < iter; i++ ) { + if( nRshifts[ i ] > 0 ) { + pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ]; + nLS = nRshifts[ i ] - 1; + for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) { + abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] ); + for( j = nLS; j > 0; j-- ) { + bit = silk_RSHIFT( abs_q, j ) & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + bit = abs_q & 1; + ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 ); + } + } + } + + /****************/ + /* Encode signs */ + /****************/ + silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses ); + RESTORE_STACK; +} diff --git a/src/libopus/silk/errors.h b/src/libopus/silk/errors.h new file mode 100644 index 00000000..45070800 --- /dev/null +++ b/src/libopus/silk/errors.h @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_ERRORS_H +#define SILK_ERRORS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/******************/ +/* Error messages */ +/******************/ +#define SILK_NO_ERROR 0 + +/**************************/ +/* Encoder error messages */ +/**************************/ + +/* Input length is not a multiple of 10 ms, or length is longer than the packet length */ +#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101 + +/* Sampling frequency not 8000, 12000 or 16000 Hertz */ +#define SILK_ENC_FS_NOT_SUPPORTED -102 + +/* Packet size not 10, 20, 40, or 60 ms */ +#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103 + +/* Allocated payload buffer too short */ +#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104 + +/* Loss rate not between 0 and 100 percent */ +#define SILK_ENC_INVALID_LOSS_RATE -105 + +/* Complexity setting not valid, use 0...10 */ +#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106 + +/* Inband FEC setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107 + +/* DTX setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_DTX_SETTING -108 + +/* CBR setting not valid, use 0 or 1 */ +#define SILK_ENC_INVALID_CBR_SETTING -109 + +/* Internal encoder error */ +#define SILK_ENC_INTERNAL_ERROR -110 + +/* Internal encoder error */ +#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111 + +/**************************/ +/* Decoder error messages */ +/**************************/ + +/* Output sampling frequency lower than internal decoded sampling frequency */ +#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200 + +/* Payload size exceeded the maximum allowed 1024 bytes */ +#define SILK_DEC_PAYLOAD_TOO_LARGE -201 + +/* Payload has bit errors */ +#define SILK_DEC_PAYLOAD_ERROR -202 + +/* Payload has bit errors */ +#define SILK_DEC_INVALID_FRAME_SIZE -203 + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/silk/fixed/LTP_analysis_filter_FIX.c b/src/libopus/silk/fixed/LTP_analysis_filter_FIX.c new file mode 100644 index 00000000..a14eca78 --- /dev/null +++ b/src/libopus/silk/fixed/LTP_analysis_filter_FIX.c @@ -0,0 +1,90 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +) +{ + const opus_int16 *x_ptr, *x_lag_ptr; + opus_int16 Btmp_Q14[ LTP_ORDER ]; + opus_int16 *LTP_res_ptr; + opus_int k, i; + opus_int32 LTP_est; + + x_ptr = x; + LTP_res_ptr = LTP_res; + for( k = 0; k < nb_subfr; k++ ) { + + x_lag_ptr = x_ptr - pitchL[ k ]; + + Btmp_Q14[ 0 ] = LTPCoef_Q14[ k * LTP_ORDER ]; + Btmp_Q14[ 1 ] = LTPCoef_Q14[ k * LTP_ORDER + 1 ]; + Btmp_Q14[ 2 ] = LTPCoef_Q14[ k * LTP_ORDER + 2 ]; + Btmp_Q14[ 3 ] = LTPCoef_Q14[ k * LTP_ORDER + 3 ]; + Btmp_Q14[ 4 ] = LTPCoef_Q14[ k * LTP_ORDER + 4 ]; + + /* LTP analysis FIR filter */ + for( i = 0; i < subfr_length + pre_length; i++ ) { + LTP_res_ptr[ i ] = x_ptr[ i ]; + + /* Long-term prediction */ + LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 1 ], Btmp_Q14[ 1 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ 0 ], Btmp_Q14[ 2 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -1 ], Btmp_Q14[ 3 ] ); + LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ -2 ], Btmp_Q14[ 4 ] ); + + LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/ + + /* Subtract long-term prediction */ + LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est ); + + /* Scale residual */ + LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] ); + + x_lag_ptr++; + } + + /* Update pointers */ + LTP_res_ptr += subfr_length + pre_length; + x_ptr += subfr_length; + } +} + diff --git a/src/libopus/silk/fixed/LTP_analysis_filter_FIX.lo b/src/libopus/silk/fixed/LTP_analysis_filter_FIX.lo new file mode 100644 index 00000000..762ccd9e --- /dev/null +++ b/src/libopus/silk/fixed/LTP_analysis_filter_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/LTP_analysis_filter_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/LTP_analysis_filter_FIX.o' + +# Name of the non-PIC object +non_pic_object='LTP_analysis_filter_FIX.o' + diff --git a/src/libopus/silk/fixed/LTP_analysis_filter_FIX.o b/src/libopus/silk/fixed/LTP_analysis_filter_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..714ff662821a8dfc539895e6d6d2fb7888ceb4eb GIT binary patch literal 13896 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 CuRlNl literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.c b/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.c new file mode 100644 index 00000000..d607134f --- /dev/null +++ b/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.c @@ -0,0 +1,53 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + opus_int round_loss; + + if( condCoding == CODE_INDEPENDENTLY ) { + /* Only scale if first frame in packet */ + round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket; + psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( + silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 ); + } else { + /* Default is minimum scaling */ + psEnc->sCmn.indices.LTP_scaleIndex = 0; + } + psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ]; +} diff --git a/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.lo b/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.lo new file mode 100644 index 00000000..24d93f5b --- /dev/null +++ b/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/LTP_scale_ctrl_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/LTP_scale_ctrl_FIX.o' + +# Name of the non-PIC object +non_pic_object='LTP_scale_ctrl_FIX.o' + diff --git a/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.o b/src/libopus/silk/fixed/LTP_scale_ctrl_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..06f6521da96a0384f653ae181ec30732ec46b4fa GIT binary patch literal 20696 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⪻d|lrX2Ixy`WDAHaEV^R9O|%&r+Q+Ea7v+jv*t7W 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 IBgppu3+1p46951J literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/apply_sine_window_FIX.c b/src/libopus/silk/fixed/apply_sine_window_FIX.c new file mode 100644 index 00000000..f5bb4544 --- /dev/null +++ b/src/libopus/silk/fixed/apply_sine_window_FIX.c @@ -0,0 +1,101 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "../SigProc_FIX.h" + +/* Apply sine window to signal vector. */ +/* Window types: */ +/* 1 -> sine window from 0 to pi/2 */ +/* 2 -> sine window from pi/2 to pi */ +/* Every other sample is linearly interpolated, for speed. */ +/* Window length must be between 16 and 120 (incl) and a multiple of 4. */ + +/* Matlab code for table: + for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end +*/ +static const opus_int16 freq_table_Q16[ 27 ] = { + 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202, + 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422, + 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702, +}; + +void silk_apply_sine_window( + opus_int16 px_win[], /* O Pointer to windowed signal */ + const opus_int16 px[], /* I Pointer to input signal */ + const opus_int win_type, /* I Selects a window type */ + const opus_int length /* I Window length, multiple of 4 */ +) +{ + opus_int k, f_Q16, c_Q16; + opus_int32 S0_Q16, S1_Q16; + + celt_assert( win_type == 1 || win_type == 2 ); + + /* Length must be in a range from 16 to 120 and a multiple of 4 */ + celt_assert( length >= 16 && length <= 120 ); + celt_assert( ( length & 3 ) == 0 ); + + /* Frequency */ + k = ( length >> 2 ) - 4; + celt_assert( k >= 0 && k <= 26 ); + f_Q16 = (opus_int)freq_table_Q16[ k ]; + + /* Factor used for cosine approximation */ + c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 ); + silk_assert( c_Q16 >= -32768 ); + + /* initialize state */ + if( win_type == 1 ) { + /* start from 0 */ + S0_Q16 = 0; + /* approximation of sin(f) */ + S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 ); + } else { + /* start from 1 */ + S0_Q16 = ( (opus_int32)1 << 16 ); + /* approximation of cos(f) */ + S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 ); + } + + /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */ + /* 4 samples at a time */ + for( k = 0; k < length; k += 4 ) { + px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] ); + px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] ); + S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1; + S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) ); + + px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] ); + px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] ); + S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16; + S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) ); + } +} diff --git a/src/libopus/silk/fixed/apply_sine_window_FIX.lo b/src/libopus/silk/fixed/apply_sine_window_FIX.lo new file mode 100644 index 00000000..0228ba81 --- /dev/null +++ b/src/libopus/silk/fixed/apply_sine_window_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/apply_sine_window_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/apply_sine_window_FIX.o' + +# Name of the non-PIC object +non_pic_object='apply_sine_window_FIX.o' + diff --git a/src/libopus/silk/fixed/apply_sine_window_FIX.o b/src/libopus/silk/fixed/apply_sine_window_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..fdbd8fc619fb8f5bbeb26105776781ddf659d4d3 GIT binary patch literal 10688 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 B?{okF literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/autocorr_FIX.c b/src/libopus/silk/fixed/autocorr_FIX.c new file mode 100644 index 00000000..5ed29cd1 --- /dev/null +++ b/src/libopus/silk/fixed/autocorr_FIX.c @@ -0,0 +1,48 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "../SigProc_FIX.h" +#include "../../celt/celt_lpc.h" + +/* Compute autocorrelation */ +void silk_autocorr( + opus_int32 *results, /* O Result (length correlationCount) */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *inputData, /* I Input data to correlate */ + const opus_int inputDataSize, /* I Length of input */ + const opus_int correlationCount, /* I Number of correlation taps to compute */ + int arch /* I Run-time architecture */ +) +{ + opus_int corrCount; + corrCount = silk_min_int( inputDataSize, correlationCount ); + *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch); +} diff --git a/src/libopus/silk/fixed/autocorr_FIX.lo b/src/libopus/silk/fixed/autocorr_FIX.lo new file mode 100644 index 00000000..b0ef65da --- /dev/null +++ b/src/libopus/silk/fixed/autocorr_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/autocorr_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/autocorr_FIX.o' + +# Name of the non-PIC object +non_pic_object='autocorr_FIX.o' + diff --git a/src/libopus/silk/fixed/autocorr_FIX.o b/src/libopus/silk/fixed/autocorr_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..9d4cbba4e76e75fb2d0feb93dfcb97f5269d7e9f GIT binary patch literal 8024 zcmbtY4Qw366`r~E+2=SpJ252ZB%p&P!J*up&vuLpg!qS;xC)8mB$7i4oAurLZtL@{ zwR@L1v_O75dSR+X8X*y-IA{^b&~Cp9c8KAAr~x`!zg` z1~F(OCMpqG?2jCKZH9k#w&|Vw!1EH6oBoM3$?tyy#F*qiK)FrI|3Wz-<$t4`l=6ot zcecQTH8GB$O9C!HzXTBh1|(<@V4DO{0mdX~6ktMv7(WdW9*|%Oe+@uUf~8^{vl6rk zP?2B-KM4`cNwAV{0dPcuRs0ZuqY@Q zCP7AkrzGeS;28kV2lOlZSbhnNWks5A>5x%h)`0^VNIW>y zfgakUL7x#A+yx8fFi{urZ2LIhyK16kp9pYelx4wY)%;Noi9s=O=TXigiTj2Ukli$l z2F4P-tYfr2DGXMF_ZU)`g*9o0A(i7Y5K1yu%Sq;JuM#%~)R+?0Qf*+c4j!fU^QvTE zxJQYZfZDCZu&+If`cmtVvt3G5!9b`=4Ex%(sIT=w5aUWz4mjJV#IUdNMSa19i^AE2 z62pcQiyD3;Fx;m^)pLX$VoDA>+jpL`E5HeCLQuq3B_w<(tAHRue9=M1Hyexi^g^vd z7i8%12{4E-c#j$9@5h(HQ=CK)`%Y;(Gv&p4>WyUGzO4YnA^$47=H|bP-@K{e7=$u`uFlJRNZqD^Qb7XWPox|hMZl^Hj zxj8`;F(rN_pSP#dMF#t9XNZ-^N08p#H39RKt+LcT`GA9rGpMj9ZS zrs+;inHA>etdh;l(VeDeTX}P~;xRKo_T*%-YMG+MzC{o<4C;@JZr^IomZ~zSL!MKyMGkSY%8&|38YV1LbZ6|0 zZFwa-Gw9{3PT9rv>RFy+`D!>R9|m0RY<0Gb|+I)2OS^QWyz@=-duEGVV8mPD^_kgHS4(*J6CbNlwa|1h8AlO z^F^xzRsl>IE?hMYqE#kN%qJujM*vGi<(EyBTnpf=>xW+g7@L?ZAJtihSoO%NS5}*tSuIz68(QTHB;JmKH6vF#B)d8*C)>0A zY6*5J^e=NJx?|T54_}q++&c-cX;n^ds;4SY_O@()x~q4iWW@$6PGKPNTgDlmYvXH{ zHpT9RoopR&YlQ}F-~7_Z&zNtr5e0UO=hAJ(!G8Fg=tuv6hK zS*IAmhoZL8VB#WHO9C>24@zy5p?#iIt06B}3I?^Y$Op-gmw`Y}2?m2hU!7ve)Ao5S zMsUojZ8GE)poVM%v?798l|_A8F9wKhdg%qC9mD4gyRYAgAZkaZ<8o^H&QYZ>i&*Ae&+u{Ls6$Y#s3wRpVLb@^i7qf1UhXuJP)P?bCR5#vRglygOsr zq4D1#{zi@8MR-c%@1!_=jlWsCXGb*tTg2b3@!ur;u*N?@@jR*VHxvIgjenWqIi>OH z>Z|5W0|9ga6HNJ=R*J}LF$nQptSL?4&NB>=vw=*Fg^-mN3ix7|c4)MPY z@u;u9yMHHM<&)Iedm;U1&{w4m4-Qb2{^b&~BJpax)5PDS@t>keyMGa0ojuS`_>`#5 zM5@K`cSlT~419u0gE1s;2O7h@3oUY&nA)Uu-LweGO-x36yw=I@ZTORL3V!teF=5&02>VWMhli7idDC*9?ct)^?}x^E<9~)G zSlQ$FasSZA?*ga$1d848U-o}=5&K)o{($COgX~tYuNVKXD1Nn0G5)3Sug8B6^{>VW zP?Vq3X8A*HVXFRB{SauQtlNKine?OfRf!gIrR-0Vy=qtW8M0Sc)yhuc7eGKRq6n(b zlKp_jtMM!PIS}gQ@7+52!@HugS9z`1H~LP{!TuQv7=Pzztz(aA)=~@%W3Qkxlwnx~ VPksCtQ$71Ox~QHCETy2^{|Ed$R!jf@ literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/burg_modified_FIX.c b/src/libopus/silk/fixed/burg_modified_FIX.c new file mode 100644 index 00000000..b4a31d60 --- /dev/null +++ b/src/libopus/silk/fixed/burg_modified_FIX.c @@ -0,0 +1,280 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "../SigProc_FIX.h" +#include "../define.h" +#include "../tuning_parameters.h" +#include "../../celt/pitch.h" + +#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */ + +#define QA 25 +#define N_BITS_HEAD_ROOM 3 +#define MIN_RSHIFTS -16 +#define MAX_RSHIFTS (32 - QA) + +/* Compute reflection coefficients from input signal */ +void silk_burg_modified_c( + opus_int32 *res_nrg, /* O Residual energy */ + opus_int *res_nrg_Q, /* O Residual energy Q value */ + opus_int32 A_Q16[], /* O Prediction coefficients (length order) */ + const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */ + const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */ + const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */ + const opus_int nb_subfr, /* I Number of subframes stacked in x */ + const opus_int D, /* I Order */ + int arch /* I Run-time architecture */ +) +{ + opus_int k, n, s, lz, rshifts, reached_max_gain; + opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; + const opus_int16 *x_ptr; + opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; + opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; + opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; + opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + opus_int64 C0_64; + + celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); + + /* Compute autocorrelations, added over subframes */ + C0_64 = silk_inner_prod16_aligned_64( x, x, subfr_length*nb_subfr, arch ); + lz = silk_CLZ64(C0_64); + rshifts = 32 + 1 + N_BITS_HEAD_ROOM - lz; + if (rshifts > MAX_RSHIFTS) rshifts = MAX_RSHIFTS; + if (rshifts < MIN_RSHIFTS) rshifts = MIN_RSHIFTS; + + if (rshifts > 0) { + C0 = (opus_int32)silk_RSHIFT64(C0_64, rshifts ); + } else { + C0 = silk_LSHIFT32((opus_int32)C0_64, -rshifts ); + } + + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64( + silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n, arch ), rshifts ); + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + int i; + opus_int32 d; + x_ptr = x + s * subfr_length; + celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch ); + for( n = 1; n < D + 1; n++ ) { + for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ ) + d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] ); + xcorr[ n - 1 ] += d; + } + for( n = 1; n < D + 1; n++ ) { + C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts ); + } + } + } + silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) ); + + /* Initialize */ + CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */ + + invGain_Q30 = (opus_int32)1 << 30; + reached_max_gain = 0; + for( n = 0; n < D; n++ ) { + /* Update first row of correlation matrix (without first element) */ + /* Update last row of correlation matrix (without last element, stored in reversed order) */ + /* Update C * Af */ + /* Update C * flipud(Af) (stored in reversed order) */ + if( rshifts > -2 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp_QA = Af_QA[ k ]; + tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */ + tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */ + } + tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */ + tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */ + } + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */ + x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */ + tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */ + tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */ + for( k = 0; k < n; k++ ) { + C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */ + C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */ + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */ + /* We sometimes have get overflows in the multiplications (even beyond +/- 2^32), + but they cancel each other and the real result seems to always fit in a 32-bit + signed integer. This was determined experimentally, not theoretically (unfortunately). */ + tmp1 = silk_MLA_ovflw( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */ + tmp2 = silk_MLA_ovflw( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */ + } + tmp1 = -tmp1; /* Q17 */ + tmp2 = -tmp2; /* Q17 */ + for( k = 0; k <= n; k++ ) { + CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1, + silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */ + CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2, + silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */ + } + } + } + + /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */ + tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */ + tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */ + num = 0; /* Q( -rshifts ) */ + nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */ + for( k = 0; k < n; k++ ) { + Atmp_QA = Af_QA[ k ]; + lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1; + lz = silk_min( 32 - QA, lz ); + Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */ + + tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */ + nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ), + Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */ + } + CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */ + CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */ + num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */ + num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */ + + /* Calculate the next order reflection (parcor) coefficient */ + if( silk_abs( num ) < nrg ) { + rc_Q31 = silk_DIV32_varQ( num, nrg, 31 ); + } else { + rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN; + } + + /* Update inverse prediction gain */ + tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 ); + tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 ); + if( tmp1 <= minInvGain_Q30 ) { + /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */ + tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */ + rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */ + if( rc_Q31 > 0 ) { + /* Newton-Raphson iteration */ + rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */ + rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */ + if( num < 0 ) { + /* Ensure adjusted reflection coefficients has the original sign */ + rc_Q31 = -rc_Q31; + } + } + invGain_Q30 = minInvGain_Q30; + reached_max_gain = 1; + } else { + invGain_Q30 = tmp1; + } + + /* Update the AR coefficients */ + for( k = 0; k < (n + 1) >> 1; k++ ) { + tmp1 = Af_QA[ k ]; /* QA */ + tmp2 = Af_QA[ n - k - 1 ]; /* QA */ + Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */ + Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */ + } + Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */ + + if( reached_max_gain ) { + /* Reached max prediction gain; set remaining coefficients to zero and exit loop */ + for( k = n + 1; k < D; k++ ) { + Af_QA[ k ] = 0; + } + break; + } + + /* Update C * Af and C * Ab */ + for( k = 0; k <= n + 1; k++ ) { + tmp1 = CAf[ k ]; /* Q( -rshifts ) */ + tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */ + CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */ + } + } + + if( reached_max_gain ) { + for( k = 0; k < D; k++ ) { + /* Scale coefficients */ + A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); + } + /* Subtract energy of preceding samples from C0 */ + if( rshifts > 0 ) { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D, arch ), rshifts ); + } + } else { + for( s = 0; s < nb_subfr; s++ ) { + x_ptr = x + s * subfr_length; + C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D, arch), -rshifts); + } + } + /* Approximate residual energy */ + *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 ); + *res_nrg_Q = -rshifts; + } else { + /* Return residual energy */ + nrg = CAf[ 0 ]; /* Q( -rshifts ) */ + tmp1 = (opus_int32)1 << 16; /* Q16 */ + for( k = 0; k < D; k++ ) { + Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */ + nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */ + tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */ + A_Q16[ k ] = -Atmp1; + } + *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ + *res_nrg_Q = -rshifts; + } +} diff --git a/src/libopus/silk/fixed/burg_modified_FIX.lo b/src/libopus/silk/fixed/burg_modified_FIX.lo new file mode 100644 index 00000000..05cdcd59 --- /dev/null +++ b/src/libopus/silk/fixed/burg_modified_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/burg_modified_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/burg_modified_FIX.o' + +# Name of the non-PIC object +non_pic_object='burg_modified_FIX.o' + diff --git a/src/libopus/silk/fixed/burg_modified_FIX.o b/src/libopus/silk/fixed/burg_modified_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..aa1a769e763d661fce6949def202bc9e8c5d4555 GIT binary patch literal 30592 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 v9p_cfq{kREq|Nda(?*B@QR?v 0 ) { + /* Right shifting used */ + for( lag = 0; lag < order; lag++ ) { + inner_prod = 0; + for( i = 0; i < L; i++ ) { + inner_prod = silk_ADD_RSHIFT32( inner_prod, silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts ); + } + Xt[ lag ] = inner_prod; /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } else { + silk_assert( rshifts == 0 ); + for( lag = 0; lag < order; lag++ ) { + Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); /* X[:,lag]'*t */ + ptr1--; /* Go to next column of X */ + } + } +} + +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations and energy */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, j, lag; + opus_int32 energy; + const opus_int16 *ptr1, *ptr2; + + /* Calculate energy to find shift used to fit in 32 bits */ + silk_sum_sqr_shift( nrg, rshifts, x, L + order - 1 ); + energy = *nrg; + + /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */ + /* Remove contribution of first order - 1 samples */ + for( i = 0; i < order - 1; i++ ) { + energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), *rshifts ); + } + + /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */ + /* Fill out the diagonal of the correlation matrix */ + matrix_ptr( XX, 0, 0, order ) = energy; + silk_assert( energy >= 0 ); + ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */ + for( j = 1; j < order; j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), *rshifts ) ); + matrix_ptr( XX, j, j, order ) = energy; + silk_assert( energy >= 0 ); + } + + ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */ + /* Calculate the remaining elements of the correlation matrix */ + if( *rshifts > 0 ) { + /* Right shifting used */ + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = 0; + for( i = 0; i < L; i++ ) { + energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), *rshifts ); + } + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), *rshifts ) ); + energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), *rshifts ) ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--; /* Update pointer to first sample of next column (lag) in X */ + } + } else { + for( lag = 1; lag < order; lag++ ) { + /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */ + energy = silk_inner_prod_aligned( ptr1, ptr2, L, arch ); + matrix_ptr( XX, lag, 0, order ) = energy; + matrix_ptr( XX, 0, lag, order ) = energy; + /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */ + for( j = 1; j < ( order - lag ); j++ ) { + energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) ); + energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] ); + matrix_ptr( XX, lag + j, j, order ) = energy; + matrix_ptr( XX, j, lag + j, order ) = energy; + } + ptr2--;/* Update pointer to first sample of next column (lag) in X */ + } + } +} + diff --git a/src/libopus/silk/fixed/corrMatrix_FIX.lo b/src/libopus/silk/fixed/corrMatrix_FIX.lo new file mode 100644 index 00000000..be8b343e --- /dev/null +++ b/src/libopus/silk/fixed/corrMatrix_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/corrMatrix_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/corrMatrix_FIX.o' + +# Name of the non-PIC object +non_pic_object='corrMatrix_FIX.o' + diff --git a/src/libopus/silk/fixed/corrMatrix_FIX.o b/src/libopus/silk/fixed/corrMatrix_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..9bdb7b931bf4ec50dde97675fcce84d2dfc3b736 GIT binary patch literal 17184 zcmbtbdw5jUwclqR$w0^hh!7rXYzGWt9+LnD0nLO2CO8p70t5vQlgWgPOlIOdFi-?) zL>+Owa%(^PwN}u3Kl}LFOK*E`ZN0WY)q-t5rE06K*P8a$TOZYWzqaCo!d+|cwa%RE z4F9zI`*O}&zxCK_uf6u(XXZ@ywFg%@3`1};#5E$%F)GB^iagyS$rf>us1*K9{*BpF z{tf<~w(PSTx`W|UYjRuGo(qir(R1M0wuAlNmc6k9$M<%RzG(!`oDSr!T$yVR9?w=8eGU zJC62jMaSrIS77ODnP&o{PkV0M>fhqu>c7cvKBfFYUw?qU{Mlc0WIuo&gV|?-x#cTC zc!!KSkbS)^``fnc+d&Y6!@%e>t~XJVZ9f}a`bp+>%`1-2pZz5cusyf;{D$s8_HV)L zQ=QqL!4Lz1Y|vYk3(h#7O?zG0N^daxTp;^#FndzEY(H@RpmT4HKezFm|KJpFAp2e* zw`YSxj=TKWjKJuR9py(~c=6)}rvppRWZn&iUEaXKJ>IHp@pU=K?C6I^Ah+eBbHQBf zqO;}q{Sc-l5Dt1>{@kF^o(r4{gx~Eno(-IM!x7BQofJ6pt3Ym1eK1!!X-#g=oU?0k zJ#)?lvpwFL;DYA|>UjK++sQJR(YGD#W!?j|Hb$ym2a96foWkEd4lh z+JCUp8_2bvJ@7*Led{oS?1@0O&D$I}*ygQTn+skn+Om7R)g8vGf$YfuP7O#s-@_6L z7|#b69Ea&L0-#cXf`)@GuW>vOJ`J=NJh(a*oQBy7=F(gb=(pw|jIuLVY50yGcy{l6 z4A=L8?>ObHvdLe5Y zAD=sa{ya>|$rMhbepFVI5-l01vyq6Ja#K}Q0F!~-=qwFqQ+?sXW z6)^tPvGlK*lh|2vU=#-J>KJ{?5ilT(pc99>+zYgKH0G@~$`5$4>(QqJwt|)8!K^_t zR6aX%+l)@*HArSh_D8{7z$NpDNi;rg&wj`m?99GyC9z|{OUjST+r8fXnE34L2Yb9O zocxL)RH&y7dZ_NqrQHImUY2GXs8o8@I zJxp1Pfb4836_~Jc$jghs&MlLvDhWUq5He0@iy%>t$x3=Y^IXu`<8AI3JppNY*AaB~ zTN(001(Y9HHZegzEfK;6;}OCmx1=eOwq3R;sYD!jb-dCHSEr{K8K*JoS zoABNzEnyDHVo#9=`<42xs#`5`)&mwf`!OcnRauLi{qIZ`HT@PycNJttx+z-Z0McD! z@r(b6@@9*_>J0J$i*GJP{a&~fc~-*J>5|!WdgM(e#PgPc!ofU9ITzNY}vBf*)ZZ)1VkbGR=x{NTx+GF3AKGI^k!0cDdOyhQ7ZdXi| z5d?3eikWL{0p@PS%rl+?wfhxQYy1kBFDRx?GDj3sFPX0@ra>~_QcR;!3pU?VOp}c5 zxMCI?ebCR-Le_op7v(fm6(7Mts#HFLB+-xJaA_JI!|ADjc`XO5$a6Q$ZYkCqhFyj$ z1W}w#i6$AHF3M3Pr@r`F193&S*l53`D^PLLUD&50@6MB1i<~?g11ar=%L|}6Rk%;G z!Q?rJ&?<3O$eJq+L!h|gWsLiU`+e3fnTPPSz?2PNgS#C3l#N)lL~lacq3~X$U5eg} zbdjQOKvR{VDK`!RuIhBk7Q|JZPT7idwbH){=^90wNH-{Y8`8~+4xyhGNM;k<-6)W2 zaY`Q!$o(I1DMiVzfskWz$ZN51KMjaXTxksorPjx+RU_PQTk-`6OZjZrQKbE)!aW&i zWxo(%DZiTKmBM|6CBG73DZhc`mkIY8OJ0kxl<#KwWZ}NqlGhGgV+ zyM_B2OTHRmDUY)pYVsya9za;i?_+t9aPPI`YYW@ zvh+`I`91u}s6q85po=`8#`W_SkVZN_8VM5thmL63eTE`=BMi0b%9pM(GNZ@ncqn+5WC2 z--@tOHS4SqhK^Z_y${J!jHMKIdpTHD;Na$rWg9_ZX*Xy!v6hPyb1@*Qhd~rdtzykgq}+cGxep&!6DSUDn$PTU8vRR)D|eW#+~ z^C2{2Ewh!qy~0?BCfF+D$?d}EVpi#{e~P3tP{rt81y{!*F*7QRjYwmgd9$5~g}{p? zt3m~1Q-GpTY%d3=v9nMa+v9ND9)gZ%8yg%cxb`^qz_rV<6RztgAG%}T1FpT|Q@*)k zj?x$6M_`fH-iz99sRstGL*fCL#Uc+zQRKm}RsJq#>oFpXhp=bNUk!&?nHI(Zi-BZb z!P!#@TF7i=FKAvlK6|w+RN1TJ?8zMYto%VTEk>oJk$Wu2HsL_9O&q=hlO>1mxDAs9 zi4$V3REA60iHj}r7DE_Qjd^9$OPpnM%BC9AiYsQq+|Cfrva3s$m2^OgoL*5F$_*?X2Z6m6N6$&a#pcbY_6sO!Xqf#p3`tI>Z=F#!Q+{Lu_DjjsH@D_Y#dWCQIz4soksdKqEhe*ZpZMtPGGH!;}- z%Mu&fGHnZO{{=%UwnAIaq|NRN7qsJC8lsoUu;r?oNp^*4?Y&@H*?}Q8Gr7nb;ua=( z^yq8zVdlE>icH!&-8`Yw%P2~GcvTr|IJ}i6V+Y+GqG5s^59u+>&Ug4>(m!F@`3|3^ zfc`>vhwx4C#r+wiQv$R0fa}l^*p25NW^g_UOKrkW8;6e){9U?xq*@-l+yHwgnZ&Wn8>n9fp; zL5^~?*cs&As6_0^$Ib=I6$m>XlUGqj^{{S}VX<@*Y3X5s z)`Z&QlwVB*90W|>Ly+3ynfpp!k;$=fio{H~v9=+4n0$?tV1!JL5rm!gTrgU8V2Caz z@yjD@hSyFtTVt5bFhicH#jn0S(KSJQ}q(3oTgkPjy9z9t?JUh=^q;$gsH zvWG$k1nYN@eIXrq;*o7X-C-+X*T?e^lcy|b1C!4Z2(uj-MB*z{2!^- zLIdQ%?yy3*!RnicE8(v8G<~S$R~p7AWuaMMPoba2cjd9 zeo>!ECF^6+zWVLqaQ#U05_8F-+E_H68L8bK&(vR4AB~4&nf{2 zWADWfNT@F+BLTWQx_wezyp4!k6s<-MMEDR~30|Am*&%F9;gl;1l`zTwQQ`Tb4K-D`Hg+T6Gu1x21|^7e~u zft}ZN97fs^n2tBkX1x9xFB_bbdL5aWpRK>HAK9H!yll%2f%?tM>XC6=p-e7A27_{5 zhZkuq6^5O+I_4S9%f8`EIYNfxiWwU=->`bcHPW_5+RA{XsWf;QMP$0$bIMu%u%jFb z3}@K9KG?m=T-j=FY87T`Fp*66Wd?-VvDSfBjXC#&~Szr#pC*YKb#&>pQLh*EWIx^fH-5oKzmI%`XzfFx0`N~$G zxoP`g+U!~?%%M+p9-ue z8G_PFM-y=~xX$#OU5!xFxCB&!p`v(vP)TYcl95oqiV;RAXD^ft56T@XE};Jrjx#f4 zrfx~X0)nX&tFPZsz0&8azN&6Bsy=?sKq3CYpHDA&Vs0|Q!ousN(uqRWf}QdDRwDcGfH6Sil=N(E+F)`C1z@Hmpkgf&qz@AmEO7To`#Fq;Haj}I?2UYXGL z-ky9htm+81o5QgT&I=b9_J=3fg(j7!Q}&B{p_Ku(t;thT4SM3aMisw^LP*5=t#m=R z7!I6Z>MZE)^aq1xTgOJT$KMLL?2nIT^_(ND4%8BqV~_`lnc_2B)jO^utSMPR^8A*= z6>)W1Q2y~0Rw~xuV1mHbI`v@F=i|`~#pIz4se}Dlo+0uKm!a?@f^UhCPY~5sq`0=& zdpGV9@brhzX)s}n1XYQYkKdbH<=$+9^Ju(q^->~XD&>-2zP)>0 zbK{aF{tP^t)~Ax;dK`1Dudb=iC&cQNE3dAu+0d7Xr!#8PuWiam&bQasT-UH@fkM?I zeZ9H2 zqqA(k;cRpi>}6Gnb1J;an%KSaKJf}egwOE*cYdM-p2_iJMSCGh7~HY(JHJ7o3;CJ&(NC^a?WxmT9bDV$51MONt?F*?QM(tN zp9OXg%Y*)ynHu*1CF6TWUa@9Wd}rb3WZ3ZcQP>d2+%WzfDivKHJ}AmI8LmttAb*1c zcf|3pm+Yqkjg9g7)SrA^XT$N8EjE7Xh-%h{OrRH_5E}X+Rms=MYu^7%>UWujcTmZ; zYIrw&pRi5C7t@l6Y4}m{lhW{=#E)qBb(Ew78or$Ry+^}8BK^;6c!-wbqZ)pM^uMCv zzaakG8vX-{|CokE8Xl){#Wegkq`ynU zms9@l)Nno%KBwU;$^Q`z|2*;E)bRfy{s|2)p?*(l_%y;_((qY?|5n4R34c$+uckWr zM8jRQ8Be16;`yCT^TMx%7~eyF=4$%a5?`a?rzk)C0+;=4q54T_`tMNuBO3lL^?Qeg zPbNS2YxvtVzYl5nQsTd&;rCJ9e_O-rDGxu;@FyvcuV^^e*&7;umg4`ThWF5Ti%8D- zIY@b%rQz=rK2O8(Cpp-B8vZlN!wL;Qq0~i(hTl#3+@RsFlYU6U|C{0&((p%#-=*RF z^74R&^J~XL8a|EqFKhVSl>h(K@Gnt3V;cSdjf)?NInS3<{;NsOxRd6oMZ=$=ez$4( zqf|fpHN1l2IilgmDZb+xzKr<))$kk1{}hUs;~b@VY1Hs;^1njEA0hp%8vb?CzfHsc zh2pqd!||tx*!aBScz#a!!(AEWyGjfVe4xfka&{3FWeB)W6ISJAvwYWR)B zFVgTRjkia`JE`BahJQ%;e?Y_W7m?TwYxt!U&oK>ONc>MUyo>bzs^K2W4}Ub{@!~%> zV5=rMAD{i~>Ds)2FGHk|#CXB>fXM9LK=>{7-E-`r-HTztZqV%IBLJely|k+HmxLC*fyo zIQsuC;b(0)>hrli4H;;7Lw$bEyHvx&l%F~cKT3F$4M%bt)zu0cj{b8rkF7Qw$>&Hv zXv0z8OY_xb!;yTE^l!A`sQ(!0ZzCLsk0H*bJp8kU^KXxSV)KLK6QqAy(+81kf3oRg zzmq7Qvl_mG@JaNQ3yM+yal*@NILf$As%$vw^K<@u4SyJg&=%To^uzVA*oI40S}#}I zaMb5|SZ~8oKgjD#!|x!x--e?fp2xTiM?YUB{ge$yeV)hLY&h!AqIy;T=am1Rfxkk! zSJRJ>{vpD7-k$|u*wp_q<^8l%9X@IEgYhu_l!nix_)lH{r|FdIh_*1*~uKdz#gX=g13&_;hl%w8h)`6VSVUQ)P)m6L-5lEQ5T1I zeRc5u5Z?8{yFW6D44MPU&`^W}|HtmtV2-)tytB6!BJ>}q@I0^{{$?DviWUawe(DNE z1c=A)=CB`{egVI3mTf*<5vMXzAY31!{l@}`KwW#oAJ(AHztALWRf5GurER^cv2z`Nwgh}JV=*mT`( z1u)dR3nvy@gSuH)-Tp?96q^5U;TO-)*dE7^q3GjJ1E%`~NIXvcr|gTjfNlb?Lj8|X z|6FI-KTf6I|9-%*e~uGK*{--m-B({Ae;o5cP%C7A%jM)p-K;Cy@%;g^w-ku@64~oG z+cEw%AQ02iB#w~%7%S49$ItM;0#PV`9~PKDEJ?QKycX&keebWqs}QFsVEB&-fp0T( jdrYssb^#Ir+CM&njIHV8$1*QuU$a6PeaB{tq;CKJpfwHh literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/encode_frame_FIX.c b/src/libopus/silk/fixed/encode_frame_FIX.c new file mode 100644 index 00000000..a121d0a1 --- /dev/null +++ b/src/libopus/silk/fixed/encode_frame_FIX.c @@ -0,0 +1,448 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include +#include "main_FIX.h" +#include "../../celt/stack_alloc.h" +#include "../tuning_parameters.h" + +/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +); + +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +) +{ + const opus_int activity_threshold = SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ); + + /****************************/ + /* Voice Activity Detection */ + /****************************/ + silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.arch ); + /* If Opus VAD is inactive and Silk VAD is active: lower Silk VAD to just under the threshold */ + if( activity == VAD_NO_ACTIVITY && psEnc->sCmn.speech_activity_Q8 >= activity_threshold ) { + psEnc->sCmn.speech_activity_Q8 = activity_threshold - 1; + } + + /**************************************************/ + /* Convert speech activity into VAD and DTX flags */ + /**************************************************/ + if( psEnc->sCmn.speech_activity_Q8 < activity_threshold ) { + psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY; + psEnc->sCmn.noSpeechCounter++; + if( psEnc->sCmn.noSpeechCounter <= NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.inDTX = 0; + } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) { + psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX; + psEnc->sCmn.inDTX = 0; + } + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0; + } else { + psEnc->sCmn.noSpeechCounter = 0; + psEnc->sCmn.inDTX = 0; + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + } +} + +/****************/ +/* Encode frame */ +/****************/ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +) +{ + silk_encoder_control_FIX sEncCtrl; + opus_int i, iter, maxIter, found_upper, found_lower, ret = 0; + opus_int16 *x_frame; + ec_enc sRangeEnc_copy, sRangeEnc_copy2; + silk_nsq_state sNSQ_copy, sNSQ_copy2; + opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper; + opus_int32 gainsID, gainsID_lower, gainsID_upper; + opus_int16 gainMult_Q8; + opus_int16 ec_prevLagIndex_copy; + opus_int ec_prevSignalType_copy; + opus_int8 LastGainIndex_copy2; + opus_int gain_lock[ MAX_NB_SUBFR ] = {0}; + opus_int16 best_gain_mult[ MAX_NB_SUBFR ]; + opus_int best_sum[ MAX_NB_SUBFR ]; + SAVE_STACK; + + /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */ + LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0; + + psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3; + + /**************************************************************/ + /* Set up Input Pointers, and insert frame in input buffer */ + /*************************************************************/ + /* start of frame to encode */ + x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; + + /***************************************/ + /* Ensure smooth bandwidth transitions */ + /***************************************/ + silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length ); + + /*******************************************/ + /* Copy new frame to front of input buffer */ + /*******************************************/ + silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) ); + + if( !psEnc->sCmn.prefillFlag ) { + VARDECL( opus_int16, res_pitch ); + VARDECL( opus_uint8, ec_buf_copy ); + opus_int16 *res_pitch_frame; + + ALLOC( res_pitch, + psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + + psEnc->sCmn.ltp_mem_length, opus_int16 ); + /* start of pitch LPC residual frame */ + res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; + + /*****************************************/ + /* Find pitch lags, initial LPC analysis */ + /*****************************************/ + silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame - psEnc->sCmn.ltp_mem_length, psEnc->sCmn.arch ); + + /************************/ + /* Noise shape analysis */ + /************************/ + silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch ); + + /***************************************************/ + /* Find linear prediction coefficients (LPC + LTP) */ + /***************************************************/ + silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, condCoding ); + + /****************************************/ + /* Process gains */ + /****************************************/ + silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding ); + + /****************************************/ + /* Low Bitrate Redundant Encoding */ + /****************************************/ + silk_LBRR_encode_FIX( psEnc, &sEncCtrl, x_frame, condCoding ); + + /* Loop over quantizer and entropy coding to control bitrate */ + maxIter = 6; + gainMult_Q8 = SILK_FIX_CONST( 1, 8 ); + found_lower = 0; + found_upper = 0; + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + gainsID_lower = -1; + gainsID_upper = -1; + /* Copy part of the input state */ + silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) ); + silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + seed_copy = psEnc->sCmn.indices.Seed; + ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex; + ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType; + ALLOC( ec_buf_copy, 1275, opus_uint8 ); + for( iter = 0; ; iter++ ) { + if( gainsID == gainsID_lower ) { + nBits = nBits_lower; + } else if( gainsID == gainsID_upper ) { + nBits = nBits_upper; + } else { + /* Restore part of the input state */ + if( iter > 0 ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) ); + psEnc->sCmn.indices.Seed = seed_copy; + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + } + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, x_frame, psEnc->sCmn.pulses, + sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR_Q13, sEncCtrl.HarmShapeGain_Q14, + sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14, + psEnc->sCmn.arch); + } + + if ( iter == maxIter && !found_lower ) { + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + } + + /****************************************/ + /* Encode Parameters */ + /****************************************/ + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + /****************************************/ + /* Encode Excitation Signal */ + /****************************************/ + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + + /* If we still bust after the last iteration, do some damage control. */ + if ( iter == maxIter && !found_lower && nBits > maxBits ) { + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + + /* Keep gains the same as the last frame. */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + psEnc->sCmn.indices.GainsIndices[ i ] = 4; + } + if (condCoding != CODE_CONDITIONALLY) { + psEnc->sCmn.indices.GainsIndices[ 0 ] = sEncCtrl.lastGainIndexPrev; + } + psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy; + psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy; + /* Clear all pulses. */ + for ( i = 0; i < psEnc->sCmn.frame_length; i++ ) { + psEnc->sCmn.pulses[ i ] = 0; + } + + silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding ); + + silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType, + psEnc->sCmn.pulses, psEnc->sCmn.frame_length ); + + nBits = ec_tell( psRangeEnc ); + } + + if( useCBR == 0 && iter == 0 && nBits <= maxBits ) { + break; + } + } + + if( iter == maxIter ) { + if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) { + /* Restore output state from earlier iteration that did meet the bitrate budget */ + silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) ); + celt_assert( sRangeEnc_copy2.offs <= 1275 ); + silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs ); + silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) ); + psEnc->sShape.LastGainIndex = LastGainIndex_copy2; + } + break; + } + + if( nBits > maxBits ) { + if( found_lower == 0 && iter >= 2 ) { + /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */ + sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 ); + found_upper = 0; + gainsID_upper = -1; + } else { + found_upper = 1; + nBits_upper = nBits; + gainMult_upper = gainMult_Q8; + gainsID_upper = gainsID; + } + } else if( nBits < maxBits - 5 ) { + found_lower = 1; + nBits_lower = nBits; + gainMult_lower = gainMult_Q8; + if( gainsID != gainsID_lower ) { + gainsID_lower = gainsID; + /* Copy part of the output state */ + silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) ); + celt_assert( psRangeEnc->offs <= 1275 ); + silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs ); + silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + LastGainIndex_copy2 = psEnc->sShape.LastGainIndex; + } + } else { + /* Within 5 bits of budget: close enough */ + break; + } + + if ( !found_lower && nBits > maxBits ) { + int j; + for ( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + int sum=0; + for ( j = i*psEnc->sCmn.subfr_length; j < (i+1)*psEnc->sCmn.subfr_length; j++ ) { + sum += abs( psEnc->sCmn.pulses[j] ); + } + if ( iter == 0 || (sum < best_sum[i] && !gain_lock[i]) ) { + best_sum[i] = sum; + best_gain_mult[i] = gainMult_Q8; + } else { + gain_lock[i] = 1; + } + } + } + if( ( found_lower & found_upper ) == 0 ) { + /* Adjust gain according to high-rate rate/distortion curve */ + if( nBits > maxBits ) { + if (gainMult_Q8 < 16384) { + gainMult_Q8 *= 2; + } else { + gainMult_Q8 = 32767; + } + } else { + opus_int32 gain_factor_Q16; + gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) ); + gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 ); + } + + } else { + /* Adjust gain by interpolating */ + gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower ); + /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */ + if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ); + } else + if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) { + gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ); + } + } + + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + opus_int16 tmp; + if ( gain_lock[i] ) { + tmp = best_gain_mult[i]; + } else { + tmp = gainMult_Q8; + } + sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], tmp ), 8 ); + } + + /* Quantize gains */ + psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev; + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16, + &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Unique identifier of gains vector */ + gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr ); + } + } + + /* Update input buffer */ + silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ], + ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) ); + + /* Exit without entropy coding */ + if( psEnc->sCmn.prefillFlag ) { + /* No payload */ + *pnBytesOut = 0; + RESTORE_STACK; + return ret; + } + + /* Parameters needed for next frame */ + psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ]; + psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType; + + /****************************************/ + /* Finalize payload */ + /****************************************/ + psEnc->sCmn.first_frame_after_reset = 0; + /* Payload size */ + *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 ); + + RESTORE_STACK; + return ret; +} + +/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */ +static OPUS_INLINE void silk_LBRR_encode_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */ + const opus_int16 x16[], /* I Input signal */ + opus_int condCoding /* I The type of conditional coding used so far for this frame */ +) +{ + opus_int32 TempGains_Q16[ MAX_NB_SUBFR ]; + SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ]; + silk_nsq_state sNSQ_LBRR; + + /*******************************************/ + /* Control use of inband LBRR */ + /*******************************************/ + if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) { + psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1; + + /* Copy noise shaping quantizer state and quantization indices from regular encoding */ + silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) ); + silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) ); + + /* Save original gains */ + silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + + if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) { + /* First frame in packet or previous frame not LBRR coded */ + psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex; + + /* Increase Gains to get target LBRR rate */ + psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases; + psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 ); + } + + /* Decode to get gains in sync with decoder */ + /* Overwrite unquantized gains with quantized gains */ + silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices, + &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /*****************************************/ + /* Noise shaping quantization */ + /*****************************************/ + if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) { + silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } else { + silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, x16, + psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14, + psEncCtrl->AR_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14, + psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14, psEnc->sCmn.arch ); + } + + /* Restore original gains */ + silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + } +} diff --git a/src/libopus/silk/fixed/encode_frame_FIX.lo b/src/libopus/silk/fixed/encode_frame_FIX.lo new file mode 100644 index 00000000..1c4a00ae --- /dev/null +++ b/src/libopus/silk/fixed/encode_frame_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/encode_frame_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/encode_frame_FIX.o' + +# Name of the non-PIC object +non_pic_object='encode_frame_FIX.o' + diff --git a/src/libopus/silk/fixed/encode_frame_FIX.o b/src/libopus/silk/fixed/encode_frame_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..d9ef799f3c70aa28a6f42284a50be189b5dd0c06 GIT binary patch literal 51152 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 literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/find_LPC_FIX.c b/src/libopus/silk/fixed/find_LPC_FIX.c new file mode 100644 index 00000000..feb4330f --- /dev/null +++ b/src/libopus/silk/fixed/find_LPC_FIX.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" +#include "../../celt/stack_alloc.h" +#include "../tuning_parameters.h" + +/* Finds LPC vector from correlations, and converts to NLSF */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +) +{ + opus_int k, subfr_length; + opus_int32 a_Q16[ MAX_LPC_ORDER ]; + opus_int isInterpLower, shift; + opus_int32 res_nrg0, res_nrg1; + opus_int rshift0, rshift1; + + /* Used only for LSF interpolation */ + opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg; + opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q; + opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ]; + opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ]; + SAVE_STACK; + + subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder; + + /* Default: no interpolation */ + psEncC->indices.NLSFInterpCoef_Q2 = 4; + + /* Burg AR analysis for the full frame */ + silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch ); + + if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) { + VARDECL( opus_int16, LPC_res ); + + /* Optimal solution for last 10 ms */ + silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch ); + + /* subtract residual energy here, as that's easier than adding it to the */ + /* residual energy of the first 10 ms in each iteration of the search below */ + shift = res_tmp_nrg_Q - res_nrg_Q; + if( shift >= 0 ) { + if( shift < 32 ) { + res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift ); + } + } else { + silk_assert( shift > -32 ); + res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg; + res_nrg_Q = res_tmp_nrg_Q; + } + + /* Convert to NLSFs */ + silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder ); + + ALLOC( LPC_res, 2 * subfr_length, opus_int16 ); + + /* Search over interpolation indices to find the one with lowest residual energy */ + for( k = 3; k >= 0; k-- ) { + /* Interpolate NLSFs for first half */ + silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder ); + + /* Convert to LPC for residual energy evaluation */ + silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + /* Calculate residual energy with NLSF interpolation */ + silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder, psEncC->arch ); + + silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ); + silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ); + + /* Add subframe energies from first half frame */ + shift = rshift0 - rshift1; + if( shift >= 0 ) { + res_nrg1 = silk_RSHIFT( res_nrg1, shift ); + res_nrg_interp_Q = -rshift0; + } else { + res_nrg0 = silk_RSHIFT( res_nrg0, -shift ); + res_nrg_interp_Q = -rshift1; + } + res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 ); + + /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */ + shift = res_nrg_interp_Q - res_nrg_Q; + if( shift >= 0 ) { + if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + if( -shift < 32 ) { + if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) { + isInterpLower = silk_TRUE; + } else { + isInterpLower = silk_FALSE; + } + } else { + isInterpLower = silk_FALSE; + } + } + + /* Determine whether current interpolated NLSFs are best so far */ + if( isInterpLower == silk_TRUE ) { + /* Interpolation has lower residual energy */ + res_nrg = res_nrg_interp; + res_nrg_Q = res_nrg_interp_Q; + psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k; + } + } + } + + if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) { + /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */ + silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder ); + } + + celt_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) ); + RESTORE_STACK; +} diff --git a/src/libopus/silk/fixed/find_LPC_FIX.lo b/src/libopus/silk/fixed/find_LPC_FIX.lo new file mode 100644 index 00000000..f668a4f0 --- /dev/null +++ b/src/libopus/silk/fixed/find_LPC_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/find_LPC_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/find_LPC_FIX.o' + +# Name of the non-PIC object +non_pic_object='find_LPC_FIX.o' + diff --git a/src/libopus/silk/fixed/find_LPC_FIX.o b/src/libopus/silk/fixed/find_LPC_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..d55f49ef3e851e6fd89f01f1d5091559eb070ff0 GIT binary patch literal 25216 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 literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/find_LTP_FIX.c b/src/libopus/silk/fixed/find_LTP_FIX.c new file mode 100644 index 00000000..7a8143f5 --- /dev/null +++ b/src/libopus/silk/fixed/find_LTP_FIX.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" +#include "../tuning_parameters.h" + +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_ptr[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int i, k, extra_shifts; + opus_int xx_shifts, xX_shifts, XX_shifts; + const opus_int16 *lag_ptr; + opus_int32 *XXLTP_Q17_ptr, *xXLTP_Q17_ptr; + opus_int32 xx, nrg, temp; + + xXLTP_Q17_ptr = xXLTP_Q17; + XXLTP_Q17_ptr = XXLTP_Q17; + for( k = 0; k < nb_subfr; k++ ) { + lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 ); + + silk_sum_sqr_shift( &xx, &xx_shifts, r_ptr, subfr_length + LTP_ORDER ); /* xx in Q( -xx_shifts ) */ + silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, XXLTP_Q17_ptr, &nrg, &XX_shifts, arch ); /* XXLTP_Q17_ptr and nrg in Q( -XX_shifts ) */ + extra_shifts = xx_shifts - XX_shifts; + if( extra_shifts > 0 ) { + /* Shift XX */ + xX_shifts = xx_shifts; + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_RSHIFT32( XXLTP_Q17_ptr[ i ], extra_shifts ); /* Q( -xX_shifts ) */ + } + nrg = silk_RSHIFT32( nrg, extra_shifts ); /* Q( -xX_shifts ) */ + } else if( extra_shifts < 0 ) { + /* Shift xx */ + xX_shifts = XX_shifts; + xx = silk_RSHIFT32( xx, -extra_shifts ); /* Q( -xX_shifts ) */ + } else { + xX_shifts = xx_shifts; + } + silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, xXLTP_Q17_ptr, xX_shifts, arch ); /* xXLTP_Q17_ptr in Q( -xX_shifts ) */ + + /* At this point all correlations are in Q(-xX_shifts) */ + temp = silk_SMLAWB( 1, nrg, SILK_FIX_CONST( LTP_CORR_INV_MAX, 16 ) ); + temp = silk_max( temp, xx ); +TIC(div) +#if 0 + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( XXLTP_Q17_ptr[ i ], temp, 17 ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = silk_DIV32_varQ( xXLTP_Q17_ptr[ i ], temp, 17 ); + } +#else + for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) { + XXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)XXLTP_Q17_ptr[ i ], 17 ) / temp ); + } + for( i = 0; i < LTP_ORDER; i++ ) { + xXLTP_Q17_ptr[ i ] = (opus_int32)( silk_LSHIFT64( (opus_int64)xXLTP_Q17_ptr[ i ], 17 ) / temp ); + } +#endif +TOC(div) + r_ptr += subfr_length; + XXLTP_Q17_ptr += LTP_ORDER * LTP_ORDER; + xXLTP_Q17_ptr += LTP_ORDER; + } +} diff --git a/src/libopus/silk/fixed/find_LTP_FIX.lo b/src/libopus/silk/fixed/find_LTP_FIX.lo new file mode 100644 index 00000000..9bf636a0 --- /dev/null +++ b/src/libopus/silk/fixed/find_LTP_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/find_LTP_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/find_LTP_FIX.o' + +# Name of the non-PIC object +non_pic_object='find_LTP_FIX.o' + diff --git a/src/libopus/silk/fixed/find_LTP_FIX.o b/src/libopus/silk/fixed/find_LTP_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..c81c0f688228bdf22ba75a90c07d22a7402d57d5 GIT binary patch literal 15008 zcmbtb4SZD9mA`LhG8srR2>~U12vGwK;7qe}L3*R?Inx+3g3_n!Oa{%Rg!I2ZF2C=$UYajVX-WlCfb`XHT$Y(#v zfood;tSbYf&1H>XSfvxaS&w^rgphA)>=y6zx8&EeVvh z6|RPpKlBp!>krxeyPtRX55GUf|84)NFGg0JZe8+T=7fLbKmGd$rujoo|Lzwp;+E6? zB_}f{0`_p3s}&_nVr4~vkuMAPesBg#0BQ7u{WW5eG7J5?U+CYs$#<=9lW((6f4*=o z?FGAP%ncYGs5)0Wexme#Q$ZadZhXS)kBgo}+| z9Ij4aavV9)c$zr_Ks#L5!P(h^I+_#C%o*ae3u(K9n{j{kvVB~@l>{;`0f->ye;P&N6AelIpZFaocX9p&iaKU zb4u zl1rBZ>2PJ>YJ(_t3Z{rNX~7h0??D8^g1Jyz4$LmWOxLi7ZWT<4b{BZtEtuKb_kh_an0eZN zfZ74Uc(jwi+$|U{XYLnF1!oQlrjj#H2&P)|fX%also}955=@=;cQDQiEFa`7_Z~hC zCAs%wlA@FkAW8Itm@ZAjLpVJ}Ft6(YbGY7s*)0eGgkig}g%QQsPr;AW=(${fJLGH_vBPKa{CI(Wl8BQ~ytEMn#AzZk@yfqzya#EApf@1x6!bM{Dhiap@d?01 zpXOhSxaiaTO-Ppt{mn?13tC6IQqWtFZV+@3{WL-`4IBpre1+!s_5kTT4W|N>TmoAN z&&kHmxy+dl2(LpyISRQ}lhi6_&T3P>0AVigmGZgF*um~lKY^q7Q^W>i|TBk9j)A>}Lz#z`L~X@!hWC|Anp6?W$EFw?5=!OA}N z#Lk)VB;-QuQ#)tzVL3Y+Nj#o{qEy4*MOwFGY~N1jMOv3*>~6fa+jaojku!Gs=DQrs zH266v$Ay9ICQ#_g8T%hl0DY|v)NLuidK_a1(8UJF*sh(2X+1+`0 z=u88($pxn822jr<7Sxf=m*YYYYg+46v~XVx{wqLOI2BCMWf6@5k%%#-Tnxz+Pt~%+ zO!aEZXNVNOHUqP2EcsT`40Jaw#|*#*nO*>_OJs`dg%&9^%XApYA}z@djLI`CEGW;k zC<8kyD`jl<$gLXGxr%3W(e3cD*j6&u1X^=Iz)%2F=4F^p+%4jU2bU~hP8K|>5UsIp zNq*ggIwdLBw1fRo>%PxoK8}>y8tamz)v)W&Fl?8GkJFZ*v1?x?@`z`)*9=O zq&0$$KO=%3)zHphky*wVM@nUlZIGmOzzydNxR#RGNLL%HJV!^aKtS;yaGO(ZEx>tIPX_ndfC$B^v18`}bBP5aVa0B8ON4f#|wwzVP>9X7(OB9ls1#G<_weW6gr za6`RbU+alQxFQ-4#WG<-=n-?SUT-v=V%`ar0S+0lG+c00#v;*pSPyiy z=`F22-VlRuQt5EmhafpK_s`QbR(IJMN?^^WyI5=MA!fZ9>`MZWG0lx(Q_e?U~h~^0(57zuPvDf z@rb!_AQ+7k2l2yQL(B_M_C?y;_DO%RUw?&tQjdLM#J=7Z)~-DB@`hE*ZS$v&c{VVc z!|qyxXJccB?a~W2c>Wm~d!DP9i#&M#nMv9<0co?ZJHRiCdibUL3cELA*KPB)sArjd z&H-BvOfFVeUlZtT(N{F->zkOK>Q5xoy_pEpTi5EbL};s?X1rifzXq%dRKf&ms<|4d z>qb1xxU)<=8c8Gv>hGxoj95yS0zCo`XDJqq54C54@pNa}80?JRVCe1jOxMA0 zO*O>7qNz$>-`Ahk+n2E6VMs9=fyUDZg2}B$G9{eHQoSN#o&FtY! zTA-<;LyXC_DLbg)Iid6PvFmsUSUrdY>X*o*c^y*0AyEcC;9xWz>eoYwcsh|uS^^0r zlF4;OD4j@R=degD5u{qB(niuq=z~cktY4P^|H2B0s(Ks=Czj@-L5Sou*4GLt`d%GO zC!@pMx0yJWAC{XjY>9(B)d@-dV0)uiW|c+jm&_a+Lja&Hr#{V)LyliH;b-gPweOZ4LHo!PwsWcSV zGnh=Id82q>M@q!O;5-6R1ioCNHw1Zo*77-kF0ZN-QobWVoJMjm5feI*An!t604PKU zEJiS(r3o9zibSd_*o&P6ZmJm+BN>#n3H1k)u-;%sg?lJSDin+vaspsdtc#nEVQt_# znq}CM#G=hk3~n!pBxyfPuZVV<>w(~~T$+4uwswGAZB>=}Kq@>H&(NGaBoh* zHcxxEwMJ%vu=afE;+?5y+#2NfIDXg3PA1GTtRg+szg3R}qcN5?1_mj0%SO8mZ!*x| zHN4xzegRvGcq)SPxQ7&sprtjiQXh{fM z%yVz2v}xB;cO_zBv(6M6?t1+GWEO~ZuJ#22dUNYKz021WSSd!9PYB{+hnYi(h0QbL zZuFFVbP%fuS0{FAwi~&pl|5YoGE;0|adDfYDa9uPixu6E<*iu9JaDfT&ksBbd3UR- zXJUTMAaSwsg#lhVaod5XKYUJud8}pD&KiHmXySJa=m>ZS5cbyj6^OblsJ<}U{JEr> z@rKDhl|XQM2yXD9L@YB9w{9VDZ_}YiATQokaO=*bjBqup=uZq76-F=_Gb((^FtkGg zAH0*nWYkDitn6%SsIIT~W#D18B9#nPU==)7-WqQe!y6pd-@N}Ywra(SrKRQFy_tAA zBW^pMnhfWvZmw$ZR@N>MsQ4_v-)sS?-O$0b;UaBTey-~PJh{dIlP`bx$A~6((Vey? zcgY?0CU@z6N0Yn!8#z9AS2+yb?L@fe+CR_W9X~6zupBVS>YspAjZF?DXZYDzf7TfC&yeKJ8C% z*p-i2QpGO5kd&->wX=ycw6g+J$4c16*IibK({}NSb^;vUXekH2%q_NM>mxr3UII9O z(W~g=hu(?stIvb$=fP9w!PO6Ue65aKYx=6d+9qE>U)$2sxw1=aOmxFdjeFMOrV~Ba zD$miny4^!)>_>Ql13nV+eDQ}Bc)Z6^flmQi;`LNQ)GxN+A6syEp{CSFha+ZB8V@$z++%nQHr!edliOg}#( zKL-^2I*Ri<3jR%6!Uq-nB>8_#!H*OFtb#YwxX&y2-Q?#D1wTvpTME97>ioWfKSTaM zQSdux(#|M&KlRxpy2`r!6Y4=DI%8h3+&hl!6U_z>lpQt&Uy|1Jf;nCib@!H*JukAnA*{=*9X3FY;af+tD; zu!8TR`oE^&@?Lmc!4HxD6AFF{@h27hb>eL_pK^X%Xxu^tUrqRI1@9t!fr4)&yk5b# zQopTG@VluF?Fv4V=A}o$A0t0u1;2{;K?Pq+eJJm5GT;5wKYy?2UrY5oq~LQ%{~s0n za>9=(_|25pzbp7s;y+XH1oh|tDtHCeA&2so@gJmlELHFx!aWM^p*U+5{6U(pH40u# zbqgx^?Su~~_z~i_EBF?w!(IhHN_mYbIRB9+$o^KrKO+4{6g))nJgwkw5`S31>#07k zD!7O0{*Hpz6aSHdr^(M(3VsR2Q%?1k^YuFMeg*HP`u8jNXXJmMg8z{4g9^Tz`sbGl zev8~66dZqog@=pAmvP2O&#U0g-9{fLKG_O8q%s!5x%ui-P|Z&2PJcUrO^L_Ydj+80qa$^zWg3 z<#U15UrqJ-siOZ5#q%2lk5N3oQ}8^BCzs^X|3T7|>s#W>NPn54{~+;x1uv#}`W5_f zs&h)gw^6>besbIsr1xD#{}B0kM8WT+d4Ea4=TKfBEBMnC=bsdOgz}w6^DpCBMEY|T zyqMx&sNghRtWLqNrZ_h$_@8K>xkbTU#6PUyZ&RE{6}*Y!`IUl~6Mu}Zm=3w%p?;?5 zyQnT-Sa2#O*FR&yu|^*fFMb~?KF6Ux{)h;V0#t%S)^iKz;0GTT9QF4SK3~CKBYcqs zN3xjeR%gM{PcF^ZQVWjc_0&Jj7991LlYXlON3xFm>lPgKhew6BgOxif*+^(`mqH^KfUDVrxqN^ z-%;IOwBV?JH|f7(!I2EnxNli-)c-fqKV`v@oPk0(Z1f5W%ZRGaAP7f|f`2GrmQe7e zRR0GQT)tO&ns6Kw|L{lLcszF=T>O$e+qb94{|kz~#9vWx`8n|Q^WbkQxcCna#@;;- zPSe0+r&i$c%g+I_ZXATu0L81~rKEs0rYRAKH?@5L-bgbqyj~aAen};bSkRlsZx+4b zU^>XWy(##~1V_V0Zw9`?j7Jh6<8-jMH)#w>4!%Girx}FrL;K(>6RS1+X2X#BFeLMa z5(5M9^9JUP!?%fE_=Xa`O@!}7$jIo|Bgx=^L5ci7FQs6QHIns}?iz`Z{UdQ%Z^_RB z0+)EB1n63Mi6FKRkMHJi9NJ!43E}ezr*JuQAPp^z0R)h-6e_N$uX#XVtj||2- zl)|XGTR>OE&^`xWn!-^jF6LR)-3XG2^7q#Y6KRk6&tNG*dn$Vu&f6}xRglhkPiZ9Mq literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/find_pitch_lags_FIX.c b/src/libopus/silk/fixed/find_pitch_lags_FIX.c new file mode 100644 index 00000000..7d9de29f --- /dev/null +++ b/src/libopus/silk/fixed/find_pitch_lags_FIX.c @@ -0,0 +1,143 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" +#include "../../celt/stack_alloc.h" +#include "../tuning_parameters.h" + +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +) +{ + opus_int buf_len, i, scale; + opus_int32 thrhld_Q13, res_nrg; + const opus_int16 *x_ptr; + VARDECL( opus_int16, Wsig ); + opus_int16 *Wsig_ptr; + opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ]; + opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ]; + opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ]; + SAVE_STACK; + + /******************************************/ + /* Set up buffer lengths etc based on Fs */ + /******************************************/ + buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length; + + /* Safety check */ + celt_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length ); + + /*************************************/ + /* Estimate LPC AR coefficients */ + /*************************************/ + + /* Calculate windowed signal */ + + ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 ); + + /* First LA_LTP samples */ + x_ptr = x + buf_len - psEnc->sCmn.pitch_LPC_win_length; + Wsig_ptr = Wsig; + silk_apply_sine_window( Wsig_ptr, x_ptr, 1, psEnc->sCmn.la_pitch ); + + /* Middle un - windowed samples */ + Wsig_ptr += psEnc->sCmn.la_pitch; + x_ptr += psEnc->sCmn.la_pitch; + silk_memcpy( Wsig_ptr, x_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) ); + + /* Last LA_LTP samples */ + Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + x_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ); + silk_apply_sine_window( Wsig_ptr, x_ptr, 2, psEnc->sCmn.la_pitch ); + + /* Calculate autocorrelation sequence */ + silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch ); + + /* Add white noise, as fraction of energy */ + auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1; + + /* Calculate the reflection coefficients using schur */ + res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Prediction gain */ + psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder ); + + /* Convert From 32 bit Q24 to 16 bit Q12 coefs */ + for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) { + A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) ); + } + + /* Do BWE */ + silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) ); + + /*****************************************/ + /* LPC analysis filtering */ + /*****************************************/ + silk_LPC_analysis_filter( res, x, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder, psEnc->sCmn.arch ); + + if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) { + /* Threshold for pitch estimator */ + thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 ); + thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) ); + thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 ); + thrhld_Q13 = silk_SAT16( thrhld_Q13 ); + + /*****************************************/ + /* Call pitch estimator */ + /*****************************************/ + if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex, + &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16, + (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, + psEnc->sCmn.arch) == 0 ) + { + psEnc->sCmn.indices.signalType = TYPE_VOICED; + } else { + psEnc->sCmn.indices.signalType = TYPE_UNVOICED; + } + } else { + silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) ); + psEnc->sCmn.indices.lagIndex = 0; + psEnc->sCmn.indices.contourIndex = 0; + psEnc->LTPCorr_Q15 = 0; + } + RESTORE_STACK; +} diff --git a/src/libopus/silk/fixed/find_pitch_lags_FIX.lo b/src/libopus/silk/fixed/find_pitch_lags_FIX.lo new file mode 100644 index 00000000..227482c9 --- /dev/null +++ b/src/libopus/silk/fixed/find_pitch_lags_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/find_pitch_lags_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/find_pitch_lags_FIX.o' + +# Name of the non-PIC object +non_pic_object='find_pitch_lags_FIX.o' + diff --git a/src/libopus/silk/fixed/find_pitch_lags_FIX.o b/src/libopus/silk/fixed/find_pitch_lags_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..9d37442e0e23060415612f51ff9e4bad7710560c GIT binary patch literal 30744 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 z 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 6; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] ); + } + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + /* Divide to Q16 */ + silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 ); + /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */ + invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 ); + + /* Limit inverse */ + invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 100 ); + + /* Square the inverted gains */ + silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) ); + + /* Invert the inverted and normalized gains */ + local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] ); + } + + ALLOC( LPC_in_pre, + psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder + + psEnc->sCmn.frame_length, opus_int16 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + VARDECL( opus_int32, xXLTP_Q17 ); + VARDECL( opus_int32, XXLTP_Q17 ); + + /**********/ + /* VOICED */ + /**********/ + celt_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 ); + + ALLOC( xXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER, opus_int32 ); + ALLOC( XXLTP_Q17, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 ); + + /* LTP analysis */ + silk_find_LTP_FIX( XXLTP_Q17, xXLTP_Q17, res_pitch, + psEncCtrl->pitchL, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Quantize LTP gain parameters */ + silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex, + &psEnc->sCmn.sum_log_gain_Q7, &psEncCtrl->LTPredCodGain_Q7, XXLTP_Q17, xXLTP_Q17, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.arch ); + + /* Control LTP scaling */ + silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding ); + + /* Create LTP residual */ + silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14, + psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder ); + + } else { + /************/ + /* UNVOICED */ + /************/ + /* Create signal with prepended subframes, scaled by inverse gains */ + x_ptr = x - psEnc->sCmn.predictLPCOrder; + x_pre_ptr = LPC_in_pre; + for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) { + silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ], + psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder ); + x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder; + x_ptr += psEnc->sCmn.subfr_length; + } + + silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) ); + psEncCtrl->LTPredCodGain_Q7 = 0; + psEnc->sCmn.sum_log_gain_Q7 = 0; + } + + /* Limit on total predictive coding gain */ + if( psEnc->sCmn.first_frame_after_reset ) { + minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 ); + } else { + minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */ + minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30, + silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ), + silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 ); + } + + /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */ + silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 ); + + /* Quantize LSFs */ + silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 ); + + /* Calculate residual energy using quantized LPC coefficients */ + silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains, + psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder, psEnc->sCmn.arch ); + + /* Copy to prediction struct for use in next frame for interpolation */ + silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) ); + RESTORE_STACK; +} diff --git a/src/libopus/silk/fixed/find_pred_coefs_FIX.lo b/src/libopus/silk/fixed/find_pred_coefs_FIX.lo new file mode 100644 index 00000000..330842e2 --- /dev/null +++ b/src/libopus/silk/fixed/find_pred_coefs_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/find_pred_coefs_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/find_pred_coefs_FIX.o' + +# Name of the non-PIC object +non_pic_object='find_pred_coefs_FIX.o' + diff --git a/src/libopus/silk/fixed/find_pred_coefs_FIX.o b/src/libopus/silk/fixed/find_pred_coefs_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..e3e2d06151ba8da0048af7e17431e2a3c84ace08 GIT binary patch literal 33464 zcmchAdwi6|)&FcZ34s7vE^-%whD+4k0|e!g%>_1gf!w%Q(TC0MCfT~#jk}u=5D6t< z-9jW*Q1Mb|t*x(B!B*>CiM4>OZLxTv+6%8@3sqaZRIx?*oilUJvrmSkzxVh4@q0cW z_BrP}XU?2CbLPyBum9uF-9zR#ou$TbgpnN zch*!AXx7d-67ibMDcKjAd`Rx(+0}=JvMzy&`_h-QBXu z-QCvHduB@fP({I?vk%3e>wqc+py}<3ZOPAMY}uX!7GylP3t?y1$5Wi$SHk_pNfq%w z9sNt?)&oyX0b62YD&hxFNpD3#Z+36Sb1!#&G^Oj5&3W|rlTdGpGy9j7@k6_pcn>&x z&p9gMuR1?J=kmVc&UoQWRmQ$IUA_NuxHI;>Sk-$b)7g96UXgv!)oG!;f%YV6V7<@^RBK#Hs{NtQXc?acag6!@#_gEZGR ziMzUgx);>Cx}WJm?cJ3{4oWvsGmRPH%Dt|xmoi=3Di8ZyMJkY; z86&nxgRpo%aEl!oTZe$_UETg;S36fbuW?@MG_Lu1W5$#U=-|`ypqn!4PIY_d}84{c7&V8>i1bvau|F)%O2ynG8SWQ>-6`2pG52(a`ylXJhY4~aA( zls_|GxNQrRc0X2&k?Hb&<_dh~n1OO%Ibc+_eg=gvm>oHK+_m*H*(GPZH#RzcT27^c zk1R9k=wIYS%Koi0etI|PbHc=MetxDR{!5rdN24+2YFBce*Nm02<2d{fj;O zW0&{E?v)>7Y5Y|zudp46A3XZi*5AcH%80)Uoso`v9v$~IIxhQ*qhB5U*W5QUZuth- z2)(|g1MczDr+jeBm?E~7Z|JVJVVIqUANAJSG#JQHdRZ?B=z;t^p5md*)+IL_Ay5n!S;>R(_YF*o8rgOy)RYEf=fOf3{ z;~*?C1yWc(E5p*gO%_#kZT`g}_FvU6RBCY?G9!!Y+q=WvR#c<-qz zK|X%u{ZC{RzW;#=s_t3fN|+V%@%D5bd`KKQA)s3-hc%o5%Bo+vVG8;XCpx<|SW^1%EOB6i={SM zIprEjr@^PNC(8;_Q)<@cgpfj}1prax^gURZlmefG%tZC7FuTBomU~UUWG3=alb<^h$iY2BWXIHOy)uj-~%|A(Y6DrGJJn(f@uQ$TWqYMcSe0FOgP` zNdF4yOog9AdL|}AkuGe=sKqolBrfqs$^CvCe5}MEL@|Q zA+{TVX;#co*^gGmI3yEO%t+gBpt%mkjIk{QW|LyZ+BO5TSux{mU7)Q?F_Ub!0duor zrrCZEVm*q$qMxa*+~pJ~{HvBAud`{9&nBpqPRS zf!X9xOd-y+Ztll(Ildmp)NADdJ(`wl}rud4$@KkF6wYOmLD*6tib$4I#$YDrRuFhI$67pbtA*}5KwW`dHx0kut1^ai9a zRP>EVPge9sq^Bsl6KU$tCZwk-{F_K$q>RI+q;Yn|-^o1telwascHAV#w|Zb>q7>Y0 z8Nj$@0Kbj&&~Z_BwQy|1@g^s4$Ee6sb-OW`cd8k83#!~XLNPmV^dBRp2bm{{xfShw zmYDA#^Bgg^q1XXpb|UiKl9=xz^8qn?kU34vUSvKc=6lGTA?EwYoF(Qyv`vgu4*3C=BolK#GHJy8 zQ2LpeA7P1ump?;+;JgHZAqF)yLEPe-XyIP@lzoFV40 zY-fxrc^R2a#QYMOEyTQn%+1978kz0H{05mGVqQgNCo!)fb0;yc*MZgd5cB3;kXH5* z^A?I78LKRK8=2RL`2#Y?i1{-ze<0>KGRKMeZ)8po^Ug`=+(}~IJp)YrIJHQj-(_CN zfc*9bI5ZvWq5n8rAdg<7)Fx9M`bw^33t>6HKA?UHH~~P1V;j~Q8L(kiJl9h>^u&E2 zELG&QgiXq2D72K(Q6e4F?+WIVq|_jhf)a9jFk&VaN~w01nkiBm&GKx7W%=z~K1HP5 zWR_owuq^)>myZ@HKQzlPLs*u-!R1p$%0aU{2Vq(M8J7O%j>z^CQ>TQ@=}Cld5p`mMT*ZXFGE)IL1h`$BC3dK&$#+ zM_7?pOI7HMG8To=E;P%pL0E|z51QWeU@96ti*PDh*^cI_Y!k8mh2~HHIBdmTE!j)Gv(+Th@R$;psKk?$H zbhdk74Hc6RvSlHOmtv=Vy$?Gb&kuNA*dc5)m{FqgK^vA$4hY+&*a5uo&q=~|85(N8 z_4LL*?50k|=HRBrWDR)y^76SLnbJ;0R4nlCVtp7wyKeYr()@&Fo80Wuq|KL zN6Cs^#9oA@cs)B_h>ziM!Ns=a$+sTcn0m3TKKa(ec&|yZvI@RZ>%;?(d-Pa;m!l>n26vvnJ)%*Ea4NWvoz2$C3Li4Yu* z5BOoAQG=98Za<>}5oP<%h-n}@SIOF=JrMTw_UK-?QP5J&RrdCtPH`FgJ|8NX%oV`E za*x?NH4QUYY8vjuqGb=4~dch=BhT+X+Rf)1Z zkQR0irVcxXT)qb$mD?L|wajlo(u-t)l=3ZsTcISIFpK>svKcihf&V}X*?dxmY#u{e zHl%n_ge@gsaRNT=7@@LE@kF8#MCPEdsxd{@*l*UD@)uKV%Fhz0tdW}b3?OMJTs#X^ z;5F*|COP`3Nsii>ARjWx3!Jl6C46X!*BoZYTw^n(M%`t?qrYZ>pE4!JJcHw=F53v( zwBe)D?ZYPyA7L9g$N`Fz#t8fH%hRt&uYw@3XNmOm1yBy|ArcN)DbocOroy30N)18+ z`Zh72Hp_9)LH>@0%#T39L##zdmwTp0Zr!R!ieE`%@|)b zDpRV@PxKKcNuvKSD-#`pDP#2+)-9F}E1nJ`Fe_K!c!Y*4-9pUn3xps5=k$SKL`o6> zg)`nZ6KxaAnVdiivrVjKGLxWW(fPsZJ zFPo@ia#E6l?4tejMrOE`Wbuiu-fZ(B)8slP?@v~>l^}EPfFtmNW|+JvRY9bYxI{1N zRPp(rwFKEj4U>x#CZF8MjMe0t^Gvo2*t_*-bj=<%`cg7liZWw08?OVRU9R>&ID z@LDDhk^7~unXwvP+n?db`!&4QG@M-w)*Ro+44aDn2Ce5CejJwd{;wSb+r%m+r_#uS z;U_jS!-EIyzIL9nIizF_-IGNA9@d5rx$uJ7z+|oInKs*=2Z%XJcdX0wP;=}%JNGa% z$^=_G&+{O(qMA#5>J30oS$`6#vWaV0D^Ci55-JpRzM_?^C{gQLy_W8qR5293Z(`fC zh6JxR{c|-32ZydrT&-(cO%`u3EwBAG4cAxZgstYd5EKbEQLQWb4mEo}DM}J+1=IMK zRlER`e`Q7bR|(9)^lJ%h9Mc~ruuP`Ml4aNi_wDbLOAuq4%}x?G3Z^;kP)@(TBpre# zvy>q^&&1XXrdemQz%!k$E%m&bt^L)6Q=wjy&!SQC>1YuV>%`;@CokTad=c+V_i!nG z^9nD!fcRzR@&8zrOF7)eiVb_Sb|#S1$+C(jrtlciwNA|F7m8QA1Og0fD<(OHYkYkcflX7~O*iV0@ zf^?Z=rgVtX=@a)b_&O{IDe%1m-zoh+hT>^qav^0U(Nrx#7Wc+;k26*NN}Gazcr zW)cf;J(Jw>|4oImFY(D%{l6{m*HIsCHv3Y;B=^NG+9G>&>lB!1T~h3YJW@v4B_KI=b6lCt|equH{nO$)1;Ao?y6o~PWLGle-1Bo8J`hyN0v_~OF5U@R zAW8B;<2zKq*_IdJnPlmHy8ln>bGGLCr32LG4E+KreueIwvGw*cDHBeo`(Bl6m!k-R|28*KCW^Eygq8?%dZ zf`L$5M^00yEw3REiz<;|pdqix>pfp&4%Y^aq^FNkfW7`;Oo;x!j}KP0c)XEtG`AUp zxGDsV`-zFhB7sno(HMqr>Nf`bJ`jPfMPojnzY%C~TWnpc6jm^NEj|bSg-kgF+7d{( zwJmCJ6>w(6AN91f2K^BOT59vgs9ET0Agpw>cw)^!!R&@sC5Ys@sNs)9f`MpEN%=!D zZ`kJt2LAZmM^((z5VZ6L+mP=eG~;Nrcmkom9B2R^cp_eG6m-=EnyMpVF9|`>yoRzZeERj-8}p7EA5ea3s3&_mD_Gj zw%MQVOl!Q>9^Gtr^dx0n(EUAoX5**l-bCfk;K!%<@elmiiXVCSQI8)B@#A`vT6{-x zvc2|7P?+0@R3lJ%tM)wKwbDLh^Y1(NrR@Xsj?Sd7*`VMbVij<=cBYM#Oj<4&8c6#t zSUNZ@mXtsGbh0fee^}bH0IyGb8sN6HOzc%IlADp52UI&&8}blPYkLZ0|8lW^H}&Z_wf=PpdTWK7cXF=x`HPgj(BT#`SHU zU?8^6Xz+x5QP4R{RC~PF`D1l~^?suzDrDTlG$_F+hR8Jm_!AB)gSHHR$S0!sx=OUU z6;u?fCgq%kH(f9Sg<*sn8==v)o=7XsOEkVM>aVC@B|_!Ro>0gij8=tW{z%9Z6n-zh zd(-arG*yLs{tgjsgV$-oO-2(2ea#%vfyG8^EF$1SR{SA`nGARqAhqsoA2 zvp*Pw7kGSrL(Zi_1-FF)kQG{H8-enQMZy~n#lme7)etlczV?G3W`S%|sL9hJJGnLz zi1}qV+d_!@eVO1A5n2@SwD_ad{)qCKsIIJ4ihTZP0ABUs9vScok!!tbzO^kFg%(;N zb2P}2D66WkQw_pcMxc3kb*LTOVe~1G?)7?te!~mz3Q3`1NLkI0ZZZ^X zNqT6g%2&d@$Q*evlg11qQ-uHo28KX+S%I;#sX1oU%*E_!$hVz@(c+0*=a0~k1)~jW zSfX{!o>o8fL5`>4E~~8t2E!%jfyS^5!bkeIH5>$6d>HOg(E_6_oFPwL46p)|qM=78 zwqLK}2*L-(d5(}~K$OTZP>oBdG8zj&3WwLc%EOrGJ7AVTIT%Sio+n(UJ|zkakteYGP3o#>%)3!UmM#l;N3bPOwn) zdey`Lfh7knBs~$W@CQBX{JsjmHxPv`iFQvUfa{Clf>{fhrBF_NT<>Ibz`ev0B<4zo z{h>kc`<|Piu$BV_j`5Yldvl-@93S(A+aM?*S42JSY8J_0>c{aC$3c=ao#G$8!ZTV; zfN<+NquuX~g(Hwf8iQdEsK@v11h%d+hh>-`Zej(qxi>WXOVmh19Jay!f|K0rVu96R z>4Y>?5BmcVUE!=y?nSe3(n3i3J5+6$)i^#iphY$uUYyocy zLU8!NDr@?cgSxb?#=1dJ`4zHpTPvjJs9*SCFXUN*+8|A1LdDrGeHMk;?++W{P;i|} zcr5{+vJp2NFu5ZXBlw1)A@!(Y1DI$`xIHZmJ`d>47tvO~A7nhuKnuCc6 z$FE01v$~3tZ(BoSgx<=Oo{jiDKIK;! zF*#Ro>}ipaYilA3U;`Hti>hi3$oSr@MWw5$0sw_A2p{gUt6+GpS$Q+8J z)d=Grh9JkK5yHf?t_=1PYKc)Vv?c)QBiZ34bt`I&y0%DrpgjzU1rw86gM=q2#lcr=13uVo zMc3kVNdyb-IKueeu82Y`;7X*{uwb+~&={i>C@_g)@^o9*3fWDZOR#E{m(_|YIWc5z zR$b|{W+(_24TI9E+`lNaZ`v%#hfSL59Ck!)RAjP%6%CRwt{k!hg+>8PQeX`c#2Aww zV5xv1sVOK@+e%p0|9;X0XJ z%4uH12+5UH7_DI#3EZ3{GBqByD9IV2umOo!DQST|sGT5$7j7z4dMc6gQ@&Px-s)BW zU7RIgx?sYr$LWJ>o{UeKm83dpA#N?eWo8DFDFGY6{q`(@+gWHHP~{VSiwWryvz!h? zs>Ce0G7xghx5E3EDpKo^T7*@Og*`T=+9Gu;R<~IKwgRD;n&fho!nH|F1YAcvMl+-~ z*cD4#RI*R>Fw|f~<$N^SWmNGx0y@gWk%;W390`nJHJI4zwa{(K05AYmv{k3vD&=Lq zm0IM=Uo7BTUUG9T&445a8}q0fELtsbVXO*yArHfbSVbjl6<|{$aIDoPHd+M}4O0XP zCk6~V3>!I2{}guCXfZHSX*% z!sQx)#~a9LV7iJO^l{zNTEka{%ep*qW#UZ2?TrsTf|~;KJcI|NfDaBamgR4jiez&R zVu117lXB(mufzFD!I+-aZmLj7*S9NQ6y-xW$Q8u!Hp5;Uev1H4Mv$YHh67Q*8xIj> z0S|ATKn?5=(3QqF!eFj4LAFM_2U#XV3mjd9dsda-3{1sRP!*#0FrK2q<%zV&jk>hR zoKtdZ0}DqL^;%BQ%2oB$WJLguf_zj&FE6TcR~oIswkVuhVS9u>hM?9Q&J%{gNfl!X z#zL)x6}UjjaY84{M1;1kt)jj93rJfv@I&;xPV2CTx^7cKAxiNE7dZu z7G{##Qd$We?rBe&We`X@gj`3O!R(Fh|raak||`Mb!$U-dX0ZRGx&vQcC4e zL6WCUzSNW0nAJDK3fznq$@4p(h2=6W`++l0%`+Gz3<}(X;IY#@Sr}1t0|aiwD`1o8 zgS|2??+^uQ?ZWuQq^`0t&KWQj`UD3S*c@XgaIA4c#S(i=wLyW6socoRSP_;}TWE#c zUhzzT-MvzeBVHB`!y(!XUD*qHY?ZUY{PhnJb=Kk;37&0WHk1S!hXz3+!XpYM19_nH zhwxh4!1<`uu`7y z&{Fku!X1Y63nv(_np;uGo*^%+upwL&&4)0sVHT8yw>kcw|)@ zC&Swof#XiF4YE88SG$qe?ZcU;LmfJ49|K1q1HujtO>&)rg9z-ze1#&fIo#sU^Lrve zf1WeqgV+h@!9&~#oR9s{yvn-jlET@uoo(;{HxEKK4@V-WAh#&DKy;W>N-QofzdUp1 z@&-7qw5dZuPEniW3N{v$te-i+_ue?{&ak zKA(3EcifazJ}lL>!+uM0cgptEimpNS5%wV8 zHxGdC8UTM}0Q{K&@LvyrzcT>-uL1C};F|vW1;0eoFFwFug>v2H`2s%Z`9y!o+*s^h zR_1gY%N8xFtE^WGA)Rv6Hrm_g5tDWApdM+`Q*D{p`tEEc1gm8K&sF&`yp&R^U;)9c zr$qGql>~8#A*=YwuZj1+iPbiRmV64H7vj$pf;h7=7r_r@$t#EcAcXh@7JQurA7jCH zS#X>qtmn7|A7{Z|rWAwv;mi4^{ADz?5XaY2SkE^tIKD>5`0W-P=OE*6Snvxi_+&~+ zsDH8rpGG*En_8xnARU)@Z6FD(T>((onZyq{?JOJx6Z z8vX;a^OqX_HtGMZh94yUEe&_mIDV|*Z5WVneW`Ay{bdx#Y2-idZw}cxO2cQ<_)gaF zM`>xz*6<*;Tdd)oWJiUD=g_#|?_lD^_9RoB_%ysniHVqoe?URHMZt}uF0z(^$?;-!|%t6aNVup8)$qV(C|$1^F9ra(l|b*;rw;!0~(%A zarlac7ZQI=!#9&Z`MWjT-*q&PPHXbZ$!}*hJe&HPM*d?x?~y&DHGC6|H@{WE@>9vr zxtjdl%AMj04Znlhb!qs&$)C$L{1ExSLBsz{{RwOM6XgF58or$tmbixhjpT3F@N?9! z`!swaq2W6T|475n(0t+VHnBbD2CCy zyZqfXcn4BmjMtK#7i&2F%nx4kH5`9=1h3T^{v!p8fQI)_-fq|MZxP<5;V)C(?$Pj9 z$^Z9i`1O>R9@Oxmr2h#Ge}d#+((t#bU$1KTbv!N_-pzT5{LTKnfX2hA;Y+ArOEkQQ z=G#>oKA&*EhQC01uGesKzqnDuPm>;=-)!eijV0rJ}i8vX{& z$1@r}p2kJ}Vr^o7!uj1n{$@KLBs+Ou%(#>Ad`-Tb^v~1q9b}J7!@s2bT(9ACDgUq0 z@X3_-f*SrZ$#-b@C*&WV-)#ROvZqIrf0W|v9u4;r|A2-EY2AEG!_&#{uV{FH?D0hJa zxin9M8g3*1@7C~Xq~~D`&!D{hl!g~mJp4k#S5O}KqlRy!@ja#Ce#8orVACy~88 zF0C}a85({a@sl*1&+XY79;S9@Yxps;qg=ypq;aX%@O6|ouF>!XG``=^@EPRKwHp2l z%2!)7{5#a{ts2fR0Df1)@1}nJSi`GH&yyP7Mg9GShI797ord2@ODIn+)^PllV7%%zd_39X z(eM!2AJXvSK!@ zH4Xoi;(wKf|A^*`U&DK-Ul9$zi2T;6;SW-Ow`=$~$^*MKd<~874>kO!6t_Rs@VjZ; z4`}$yWdE-%_b(tPRC@E=ira8P`)AKsyHU#;N= z`Ei4WUqO2B(Qw`uKC9s_$`60g@Yl$mvl_mX{H%UlIkC@7C%?_3_+tBiOn8HaXOaG! zHT+i;hmUA@EBQ_SHzN=Otp60r|6Y^-C;9CQ4ZoB8#?Mn(&pyJ{&z&dq&m#R3sNXFA zI>}$I;XkK%{UHExSQf>_4sHSJJ$8(7fb+ zJx~6csNsB`yh6k8BE5?=`~w=_>opvI5)!Ws8orq3<2@SA^WjGtK9MlP{V6zzAV)6 zyU8A22e{pNG+u@#{~67rpoSl&I9#XU&6E#s((s|wulqIp5sJg7H2m+>-(P6>Pbtn{ z)$m8C-9Ku07U8Ef9Di6AuYYRz8X9-}O)R|FKlhOzhHH2?`Hi1}l8VKTte$X*jt@^k_K$KEfj!KAI{#rQsnO z#}^34^hmCh{(VD}Ur*z4+=A0ok@D|Za2(nXDgOUq!BM_VO5=~ED}u-6b!z-83y$(v zP~J|bFUp`i;-3=ku;AEk2@1e9!Gfdw!=!(PhVwhUmsxPs^91?r3Jw2+#_LKA@1pU# zO2c!=4_*t7_S`}9tJ#8MyZraOhy_Ra<0QYV7U5kQ&fm}3X~9u+rfODvPs0foKO>yu z_6ySgf<+!fa|cy8WRa&(mL+dkaP))vpSEewBT0#@So|(i|zaq z=^3oyH(=v%jnr^{t~61@$I<$drQsgJa|q{gVL!~W$fHfA*eF~T7933(Pn}q*>3LjA z!>{~Xfz@R-5UNN>AzjWe?$1)gtH&` zHwm8BaQ?gLixxeo;yBs!ss%@TE~NSUmWG!R{;r1e`TRq|*&hC_f`3}%v0VoWz?H1N z7$?_dZ1-l;KTN~d&>{sDC@j&(ZMT6JDy}kI=eYrQ!UXxmLry zlqatyT=#?5B9C^Kk{==#9PNCM^lZ@d@ZUSPSmaSpE9u!`!BG$Yo%#+<&$}f5xQ5?I zar=7>-%WT5ei;ic?ia_^bvakp5*`L`o}LO9xvu804!N?yk_{QH#m-qr9z8n3@= z_ z{96>~uMB`6)o}g+$TtVT|D@r|$UpB4fS=Ovk7-;!9031R!+E^UX!v}JtFJVilCMX=u{6o!(4{5$~USd3x2<#4ZNg=t>buI9AgUE%qRMfqhsR+ChlpDkE z{^$DO4FZwd5RHo5NEjIuFMwYv&y_+xe?uF*N(?_50iu%jG&JCQU&O(0GxU-4!0RSW z@U|HhGiT9-zdpmo(3HsahFe3)o(XYFaP(qOsI;! zv-%pfmEs3nypL5}VjP&q@7ChhzLWvFH`geln#KpW*+^0v5|pOJbi(PlqAJ1Xdfgx@ zA$6wQWk8|M|84yOsEaxa;h*)|MD5>e1%YP!*^WxUn6`@Y_X8>^&bdsNEro*q{P$$7 zs^Q31ck~~c#O<^H(9OC|tkEzPKNG(OtGM%J4JhcZeomIEv6%ANK=s1|)Q=UZ8u?t2 z?s{9_0KC8cAHJb)ee6HxOuhg33&*-ntoZ|K|F~ADvEtSN>Tj8aT7>wH7Fc@y?I6>i z{b$I29w)RPmn7YOj4#xw`)SNv0O7ii&cTXH^p)*+01Eo6|CC$RxP&Xxo$K-aQL3+r ziFc{Kj&nW64^sU;ITo;!RNuvdbm#sv+zUj1{&Q?l5?24=63z7)M|> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWB( tmp1, silk_LSHIFT( tmp2, 1 ), rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWB( tmp2, silk_LSHIFT( tmp1, 1 ), rc ); + } + A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 ); + } +} diff --git a/src/libopus/silk/fixed/k2a_FIX.lo b/src/libopus/silk/fixed/k2a_FIX.lo new file mode 100644 index 00000000..7a39cd6f --- /dev/null +++ b/src/libopus/silk/fixed/k2a_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/k2a_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/k2a_FIX.o' + +# Name of the non-PIC object +non_pic_object='k2a_FIX.o' + diff --git a/src/libopus/silk/fixed/k2a_FIX.o b/src/libopus/silk/fixed/k2a_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..b3c43fc3fb910a72a09bdab684f635b35db5d93e GIT binary patch literal 7632 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 Jy>C9r{y)ggOmzSN literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/k2a_Q16_FIX.c b/src/libopus/silk/fixed/k2a_Q16_FIX.c new file mode 100644 index 00000000..357a3fe2 --- /dev/null +++ b/src/libopus/silk/fixed/k2a_Q16_FIX.c @@ -0,0 +1,54 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "../SigProc_FIX.h" + +/* Step up function, converts reflection coefficients to prediction coefficients */ +void silk_k2a_Q16( + opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */ + const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */ + const opus_int32 order /* I Prediction order */ +) +{ + opus_int k, n; + opus_int32 rc, tmp1, tmp2; + + for( k = 0; k < order; k++ ) { + rc = rc_Q16[ k ]; + for( n = 0; n < (k + 1) >> 1; n++ ) { + tmp1 = A_Q24[ n ]; + tmp2 = A_Q24[ k - n - 1 ]; + A_Q24[ n ] = silk_SMLAWW( tmp1, tmp2, rc ); + A_Q24[ k - n - 1 ] = silk_SMLAWW( tmp2, tmp1, rc ); + } + A_Q24[ k ] = -silk_LSHIFT( rc, 8 ); + } +} diff --git a/src/libopus/silk/fixed/k2a_Q16_FIX.lo b/src/libopus/silk/fixed/k2a_Q16_FIX.lo new file mode 100644 index 00000000..59a6439f --- /dev/null +++ b/src/libopus/silk/fixed/k2a_Q16_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/k2a_Q16_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/k2a_Q16_FIX.o' + +# Name of the non-PIC object +non_pic_object='k2a_Q16_FIX.o' + diff --git a/src/libopus/silk/fixed/k2a_Q16_FIX.o b/src/libopus/silk/fixed/k2a_Q16_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..23dfe4e01b963fc9dccdbdd96584f9da01f06c56 GIT binary patch literal 7592 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 U^zq}o&S!sy`u~zLq*}NC5AtwEhX4Qo literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/main_FIX.h b/src/libopus/silk/fixed/main_FIX.h new file mode 100644 index 00000000..27d28663 --- /dev/null +++ b/src/libopus/silk/fixed/main_FIX.h @@ -0,0 +1,244 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_FIX_H +#define SILK_MAIN_FIX_H + +#include "../SigProc_FIX.h" +#include "structs_FIX.h" +#include "../control.h" +#include "../main.h" +#include "../PLC.h" +#include "../debug.h" +#include "../../celt/entenc.h" + +#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \ + || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "fixed/arm/warped_autocorrelation_FIX_arm.h" +#endif + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +extern "C" +{ +#endif +#endif + +#define silk_encoder_state_Fxx silk_encoder_state_FIX +#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX +#define silk_encode_frame_Fxx silk_encode_frame_FIX + +#define QC 10 +#define QS 13 + +/*********************/ +/* Encoder Functions */ +/*********************/ + +/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */ +void silk_HP_variable_cutoff( + silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */ +); + +/* Encoder main function */ +void silk_encode_do_VAD_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int activity /* I Decision of Opus voice activity detector */ +); + +/* Encoder main function */ +opus_int silk_encode_frame_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ + opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */ + ec_enc *psRangeEnc, /* I/O compressor data structure */ + opus_int condCoding, /* I The type of conditional coding to use */ + opus_int maxBits, /* I If > 0: maximum number of output bits */ + opus_int useCBR /* I Flag to force constant-bitrate operation */ +); + +/* Initializes the Silk encoder state */ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +); + +/* Control the Silk encoder */ +opus_int silk_control_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl, /* I Control structure */ + const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */ + const opus_int channelNb, /* I Channel number */ + const opus_int force_fs_kHz +); + +/**************************/ +/* Noise shaping analysis */ +/**************************/ +/* Compute noise shaping coefficients and initial gain values */ +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +); + +/* Autocorrelations for a warped frequency axis */ +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +); + +#if !defined(OVERRIDE_silk_warped_autocorrelation_FIX) +#define silk_warped_autocorrelation_FIX(corr, scale, input, warping_Q16, length, order, arch) \ + ((void)(arch), silk_warped_autocorrelation_FIX_c(corr, scale, input, warping_Q16, length, order)) +#endif + +/* Calculation of LTP state scaling */ +void silk_LTP_scale_ctrl_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/**********************************************/ +/* Prediction Analysis */ +/**********************************************/ +/* Find pitch lags */ +void silk_find_pitch_lags_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + opus_int16 res[], /* O residual */ + const opus_int16 x[], /* I Speech signal */ + int arch /* I Run-time architecture */ +); + +/* Find LPC and LTP coefficients */ +void silk_find_pred_coefs_FIX( + silk_encoder_state_FIX *psEnc, /* I/O encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */ + const opus_int16 res_pitch[], /* I Residual from pitch analysis */ + const opus_int16 x[], /* I Speech signal */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* LPC analysis */ +void silk_find_LPC_FIX( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 NLSF_Q15[], /* O NLSFs */ + const opus_int16 x[], /* I Input signal */ + const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */ +); + +/* LTP analysis */ +void silk_find_LTP_FIX( + opus_int32 XXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Correlation matrix */ + opus_int32 xXLTP_Q17[ MAX_NB_SUBFR * LTP_ORDER ], /* O Correlation vector */ + const opus_int16 r_lpc[], /* I Residual signal after LPC */ + const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +void silk_LTP_analysis_filter_FIX( + opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */ + const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */ + const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */ + const opus_int subfr_length, /* I Length of each subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */ +); + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +); + +/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */ +opus_int32 silk_residual_energy16_covar_FIX( + const opus_int16 *c, /* I Prediction vector */ + const opus_int32 *wXX, /* I Correlation matrix */ + const opus_int32 *wXx, /* I Correlation vector */ + opus_int32 wxx, /* I Signal energy */ + opus_int D, /* I Dimension */ + opus_int cQ /* I Q value for c vector 0 - 15 */ +); + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/******************/ +/* Linear Algebra */ +/******************/ +/* Calculates correlation matrix X'*X */ +void silk_corrMatrix_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */ + opus_int32 *nrg, /* O Energy of x vector */ + opus_int *rshifts, /* O Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +/* Calculates correlation vector X'*t */ +void silk_corrVector_FIX( + const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */ + const opus_int16 *t, /* I Target vector [L] */ + const opus_int L, /* I Length of vectors */ + const opus_int order, /* I Max lag for correlation */ + opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */ + const opus_int rshifts, /* I Right shifts of correlations */ + int arch /* I Run-time architecture */ +); + +#ifndef FORCE_CPP_BUILD +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* FORCE_CPP_BUILD */ +#endif /* SILK_MAIN_FIX_H */ diff --git a/src/libopus/silk/fixed/noise_shape_analysis_FIX.c b/src/libopus/silk/fixed/noise_shape_analysis_FIX.c new file mode 100644 index 00000000..6714e705 --- /dev/null +++ b/src/libopus/silk/fixed/noise_shape_analysis_FIX.c @@ -0,0 +1,407 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" +#include "../../celt/stack_alloc.h" +#include "../tuning_parameters.h" + +/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */ +/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */ +/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */ +/* coefficient in an array of coefficients, for monic filters. */ +static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/ + const opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int order +) { + opus_int i; + opus_int32 gain_Q24; + + lambda_Q16 = -lambda_Q16; + gain_Q24 = coefs_Q24[ order - 1 ]; + for( i = order - 2; i >= 0; i-- ) { + gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 ); + } + gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 ); + return silk_INVERSE32_varQ( gain_Q24, 40 ); +} + +/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */ +/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */ +static OPUS_INLINE void limit_warped_coefs( + opus_int32 *coefs_Q24, + opus_int lambda_Q16, + opus_int32 limit_Q24, + opus_int order +) { + opus_int i, iter, ind = 0; + opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_Q16; + opus_int32 nom_Q16, den_Q24; + opus_int32 limit_Q20, maxabs_Q20; + + /* Convert to monic coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + limit_Q20 = silk_RSHIFT(limit_Q24, 4); + for( iter = 0; iter < 10; iter++ ) { + /* Find maximum absolute value */ + maxabs_Q24 = -1; + for( i = 0; i < order; i++ ) { + tmp = silk_abs_int32( coefs_Q24[ i ] ); + if( tmp > maxabs_Q24 ) { + maxabs_Q24 = tmp; + ind = i; + } + } + /* Use Q20 to avoid any overflow when multiplying by (ind + 1) later. */ + maxabs_Q20 = silk_RSHIFT(maxabs_Q24, 4); + if( maxabs_Q20 <= limit_Q20 ) { + /* Coefficients are within range - done */ + return; + } + + /* Convert back to true warped coefficients */ + for( i = 1; i < order; i++ ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + gain_Q16 = silk_INVERSE32_varQ( gain_Q16, 32 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + + /* Apply bandwidth expansion */ + chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ( + silk_SMULWB( maxabs_Q20 - limit_Q20, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ), + silk_MUL( maxabs_Q20, ind + 1 ), 22 ); + silk_bwexpander_32( coefs_Q24, order, chirp_Q16 ); + + /* Convert to monic warped coefficients */ + lambda_Q16 = -lambda_Q16; + for( i = order - 1; i > 0; i-- ) { + coefs_Q24[ i - 1 ] = silk_SMLAWB( coefs_Q24[ i - 1 ], coefs_Q24[ i ], lambda_Q16 ); + } + lambda_Q16 = -lambda_Q16; + nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 ); + den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_Q24[ 0 ], lambda_Q16 ); + gain_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 ); + for( i = 0; i < order; i++ ) { + coefs_Q24[ i ] = silk_SMULWW( gain_Q16, coefs_Q24[ i ] ); + } + } + silk_assert( 0 ); +} + +/* Disable MIPS version until it's updated. */ +#if 0 && defined(MIPSr1_ASM) +#include "mips/noise_shape_analysis_FIX_mipsr1.h" +#endif + +/**************************************************************/ +/* Compute noise shaping coefficients and initial gain values */ +/**************************************************************/ +#ifndef OVERRIDE_silk_noise_shape_analysis_FIX +void silk_noise_shape_analysis_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */ + const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */ + const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */ + int arch /* I Run-time architecture */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k, i, nSamples, nSegs, Qnrg, b_Q14, warping_Q16, scale = 0; + opus_int32 SNR_adj_dB_Q7, HarmShapeGain_Q16, Tilt_Q16, tmp32; + opus_int32 nrg, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7; + opus_int32 BWExp_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8; + opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ]; + opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 AR_Q24[ MAX_SHAPE_LPC_ORDER ]; + VARDECL( opus_int16, x_windowed ); + const opus_int16 *x_ptr, *pitch_res_ptr; + SAVE_STACK; + + /* Point to start of first LPC analysis block */ + x_ptr = x - psEnc->sCmn.la_shape; + + /****************/ + /* GAIN CONTROL */ + /****************/ + SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7; + + /* Input quality is the average of the quality in the lowest two VAD bands */ + psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ] + + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 ); + + /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */ + psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 - + SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 ); + + /* Reduce coding SNR during low speech activity */ + if( psEnc->sCmn.useCBR == 0 ) { + b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8; + b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 ); + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/ + silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/ + } + + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce gains for periodic signals */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 ); + } else { + /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */ + SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, + silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ), + SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 ); + } + + /*************************/ + /* SPARSENESS PROCESSING */ + /*************************/ + /* Set quantizer offset */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Initially set to 0; may be overruled in process_gains(..) */ + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */ + nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 ); + energy_variation_Q7 = 0; + log_energy_prev_Q7 = 0; + pitch_res_ptr = pitch_res; + nSegs = silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; + for( k = 0; k < nSegs; k++ ) { + silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples ); + nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/ + + log_energy_Q7 = silk_lin2log( nrg ); + if( k > 0 ) { + energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 ); + } + log_energy_prev_Q7 = log_energy_Q7; + pitch_res_ptr += nSamples; + } + + /* Set quantization offset depending on sparseness measure */ + if( energy_variation_Q7 > SILK_FIX_CONST( ENERGY_VARIATION_THRESHOLD_QNT_OFFSET, 7 ) * (nSegs-1) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /*******************************/ + /* Control bandwidth expansion */ + /*******************************/ + /* More BWE for signals with high prediction gain */ + strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ); + BWExp_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ), + silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */ + warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) ); + } else { + warping_Q16 = 0; + } + + /********************************************/ + /* Compute noise shaping AR coefs and gains */ + /********************************************/ + ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Apply window: sine slope followed by flat part followed by cosine slope */ + opus_int shift, slope_part, flat_part; + flat_part = psEnc->sCmn.fs_kHz * 3; + slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 ); + + silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part ); + shift = slope_part; + silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) ); + shift += flat_part; + silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part ); + + /* Update pointer: next LPC analysis block */ + x_ptr += psEnc->sCmn.subfr_length; + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Calculate warped auto correlation */ + silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder, arch ); + } else { + /* Calculate regular auto correlation */ + silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch ); + } + + /* Add white noise, as a fraction of energy */ + auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ), + SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) ); + + /* Calculate the reflection coefficients using schur */ + nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder ); + silk_assert( nrg >= 0 ); + + /* Convert reflection coefficients to prediction coefficients */ + silk_k2a_Q16( AR_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder ); + + Qnrg = -scale; /* range: -12...30*/ + silk_assert( Qnrg >= -12 ); + silk_assert( Qnrg <= 30 ); + + /* Make sure that Qnrg is an even number */ + if( Qnrg & 1 ) { + Qnrg -= 1; + nrg >>= 1; + } + + tmp32 = silk_SQRT_APPROX( nrg ); + Qnrg >>= 1; /* range: -6...15*/ + + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Adjust gain for warping */ + gain_mult_Q16 = warped_gain( AR_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder ); + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + if( psEncCtrl->Gains_Q16[ k ] < SILK_FIX_CONST( 0.25, 16 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + } else { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ); + if ( psEncCtrl->Gains_Q16[ k ] >= ( silk_int32_MAX >> 1 ) ) { + psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX; + } else { + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT32( psEncCtrl->Gains_Q16[ k ], 1 ); + } + } + silk_assert( psEncCtrl->Gains_Q16[ k ] > 0 ); + } + + /* Bandwidth expansion */ + silk_bwexpander_32( AR_Q24, psEnc->sCmn.shapingLPCOrder, BWExp_Q16 ); + + if( psEnc->sCmn.warping_Q16 > 0 ) { + /* Convert to monic warped prediction coefficients and limit absolute values */ + limit_warped_coefs( AR_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder ); + + /* Convert from Q24 to Q13 and store in int16 */ + for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) { + psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR_Q24[ i ], 11 ) ); + } + } else { + silk_LPC_fit( &psEncCtrl->AR_Q13[ k * MAX_SHAPE_LPC_ORDER ], AR_Q24, 13, 24, psEnc->sCmn.shapingLPCOrder ); + } + } + + /*****************/ + /* Gain tweaking */ + /*****************/ + /* Increase gains during low speech activity and put lower limit on gains */ + gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) ); + gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) ); + silk_assert( gain_mult_Q16 > 0 ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 ); + silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 ); + psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 ); + } + + + /************************************************/ + /* Control low-frequency shaping and noise tilt */ + /************************************************/ + /* Less low frequency shaping for noisy inputs */ + strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ), + SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) ); + strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 ); + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */ + /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/ + opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] ); + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 ); + psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + } + silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/ + Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) - + silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ), + silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) ); + } else { + b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/ + /* Pack two coefficients in one int32 */ + psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - + silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 ); + psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) ); + for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ]; + } + Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 ); + } + + /****************************/ + /* HARMONIC SHAPING CONTROL */ + /****************************/ + if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /* More harmonic noise shaping for high bitrates or noisy input */ + HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ), + SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ), + psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) ); + + /* Less harmonic noise shaping for less periodic signals */ + HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ), + silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) ); + } else { + HarmShapeGain_Q16 = 0; + } + + /*************************/ + /* Smooth over subframes */ + /*************************/ + for( k = 0; k < MAX_NB_SUBFR; k++ ) { + psShapeSt->HarmShapeGain_smth_Q16 = + silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + psShapeSt->Tilt_smth_Q16 = + silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) ); + + psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 ); + psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 ); + } + RESTORE_STACK; +} +#endif /* OVERRIDE_silk_noise_shape_analysis_FIX */ diff --git a/src/libopus/silk/fixed/noise_shape_analysis_FIX.lo b/src/libopus/silk/fixed/noise_shape_analysis_FIX.lo new file mode 100644 index 00000000..9c74371a --- /dev/null +++ b/src/libopus/silk/fixed/noise_shape_analysis_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/noise_shape_analysis_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/noise_shape_analysis_FIX.o' + +# Name of the non-PIC object +non_pic_object='noise_shape_analysis_FIX.o' + diff --git a/src/libopus/silk/fixed/noise_shape_analysis_FIX.o b/src/libopus/silk/fixed/noise_shape_analysis_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..423d350d0793a98496a5c85e92f892b7cb8f4234 GIT binary patch literal 57392 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 literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/pitch_analysis_core_FIX.c b/src/libopus/silk/fixed/pitch_analysis_core_FIX.c new file mode 100644 index 00000000..6e7ebffe --- /dev/null +++ b/src/libopus/silk/fixed/pitch_analysis_core_FIX.c @@ -0,0 +1,721 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +/*********************************************************** +* Pitch analyser function +********************************************************** */ +#include "../SigProc_FIX.h" +#include "../pitch_est_defines.h" +#include "../../celt/stack_alloc.h" +#include "../debug.h" +#include "../../celt/pitch.h" + +#define SCRATCH_SIZE 22 +#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 ) +#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 ) +#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 ) +#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 ) +#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 ) +#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 ) +#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ ) +#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) ) +#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 ) +#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 ) +#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN ) + +typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ]; + +/************************************************************/ +/* Internally used functions */ +/************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +); + +/*************************************************************/ +/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */ +/*************************************************************/ +opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */ + const opus_int16 *frame_unscaled, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */ + opus_int *pitch_out, /* O 4 pitch lag values */ + opus_int16 *lagIndex, /* O Lag Index */ + opus_int8 *contourIndex, /* O Pitch contour Index */ + opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */ + opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */ + const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */ + const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */ + const opus_int Fs_kHz, /* I Sample frequency (kHz) */ + const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */ + const opus_int nb_subfr, /* I number of 5 ms subframes */ + int arch /* I Run-time architecture */ +) +{ + VARDECL( opus_int16, frame_8kHz_buf ); + VARDECL( opus_int16, frame_4kHz ); + VARDECL( opus_int16, frame_scaled ); + opus_int32 filt_state[ 6 ]; + const opus_int16 *frame, *frame_8kHz; + opus_int i, k, d, j; + VARDECL( opus_int16, C ); + VARDECL( opus_int32, xcorr32 ); + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 cross_corr, normalizer, energy, energy_basis, energy_target; + opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp, shift; + VARDECL( opus_int16, d_comp ); + opus_int32 sum, threshold, lag_counter; + opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new; + opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new; + VARDECL( silk_pe_stage3_vals, energies_st3 ); + VARDECL( silk_pe_stage3_vals, cross_corr_st3 ); + opus_int frame_length, frame_length_8kHz, frame_length_4kHz; + opus_int sf_length; + opus_int min_lag; + opus_int max_lag; + opus_int32 contour_bias_Q15, diff; + opus_int nb_cbk_search, cbk_size; + opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13; + const opus_int8 *Lag_CB_ptr; + SAVE_STACK; + + /* Check for valid sampling frequency */ + celt_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 ); + + /* Check for valid complexity setting */ + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) ); + silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) ); + + /* Set up frame lengths max / min lag for the sampling frequency */ + frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz; + frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4; + frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8; + sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz; + min_lag = PE_MIN_LAG_MS * Fs_kHz; + max_lag = PE_MAX_LAG_MS * Fs_kHz - 1; + + /* Downscale input if necessary */ + silk_sum_sqr_shift( &energy, &shift, frame_unscaled, frame_length ); + shift += 3 - silk_CLZ32( energy ); /* at least two bits headroom */ + ALLOC( frame_scaled, frame_length, opus_int16 ); + if( shift > 0 ) { + shift = silk_RSHIFT( shift + 1, 1 ); + for( i = 0; i < frame_length; i++ ) { + frame_scaled[ i ] = silk_RSHIFT( frame_unscaled[ i ], shift ); + } + frame = frame_scaled; + } else { + frame = frame_unscaled; + } + + ALLOC( frame_8kHz_buf, ( Fs_kHz == 8 ) ? 1 : frame_length_8kHz, opus_int16 ); + /* Resample from input sampled at Fs_kHz to 8 kHz */ + if( Fs_kHz == 16 ) { + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) ); + silk_resampler_down2( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else if( Fs_kHz == 12 ) { + silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) ); + silk_resampler_down2_3( filt_state, frame_8kHz_buf, frame, frame_length ); + frame_8kHz = frame_8kHz_buf; + } else { + celt_assert( Fs_kHz == 8 ); + frame_8kHz = frame; + } + + /* Decimate again to 4 kHz */ + silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */ + ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 ); + silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz ); + + /* Low-pass filter */ + for( i = frame_length_4kHz - 1; i > 0; i-- ) { + frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] ); + } + + + /****************************************************************************** + * FIRST STAGE, operating in 4 khz + ******************************************************************************/ + ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 ); + ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 ); + silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) ); + target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ]; + for( k = 0; k < nb_subfr >> 1; k++ ) { + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_4kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + basis_ptr = target_ptr - MIN_LAG_4KHZ; + + /* Check that we are within range of the array */ + celt_assert( basis_ptr >= frame_4kHz ); + celt_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch ); + + /* Calculate first vector products before loop */ + cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ]; + normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ); + normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ) ); + normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) ); + + matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + + /* From now on normalizer is computed recursively */ + for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) { + basis_ptr--; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_4kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz ); + + cross_corr = xcorr32[ MAX_LAG_4KHZ - d ]; + + /* Add contribution of new sample and remove contribution from oldest sample */ + normalizer = silk_ADD32( normalizer, + silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) - + silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) ); + + matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) = + (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */ + } + /* Update target pointer */ + target_ptr += SF_LENGTH_8KHZ; + } + + /* Combine two subframes into single correlation measure and apply short-lag bias */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ) + + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } else { + /* Only short-lag bias */ + for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) { + sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */ + sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */ + C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */ + } + } + + /* Sort */ + length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 ); + celt_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH ); + silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ, + length_d_srch ); + + /* Escape if correlation is very low already here */ + Cmax = (opus_int)C[ 0 ]; /* Q14 */ + if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) { + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + threshold = silk_SMULWB( search_thres1_Q16, Cmax ); + for( i = 0; i < length_d_srch; i++ ) { + /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */ + if( C[ i ] > threshold ) { + d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 ); + } else { + length_d_srch = i; + break; + } + } + celt_assert( length_d_srch > 0 ); + + ALLOC( d_comp, D_COMP_STRIDE, opus_int16 ); + for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) { + d_comp[ i - D_COMP_MIN ] = 0; + } + for( i = 0; i < length_d_srch; i++ ) { + d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1; + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += + d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ]; + } + + length_d_srch = 0; + for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) { + if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) { + d_srch[ length_d_srch ] = i; + length_d_srch++; + } + } + + /* Convolution */ + for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) { + d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ] + + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ]; + } + + length_d_comp = 0; + for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) { + if( d_comp[ i - D_COMP_MIN ] > 0 ) { + d_comp[ length_d_comp ] = i - 2; + length_d_comp++; + } + } + + /********************************************************************************** + ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation + *************************************************************************************/ + + /********************************************************************************* + * Find energy of each subframe projected onto its history, for a range of delays + *********************************************************************************/ + silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) ); + + target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ]; + for( k = 0; k < nb_subfr; k++ ) { + + /* Check that we are within range of the array */ + celt_assert( target_ptr >= frame_8kHz ); + celt_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ, arch ), 1 ); + for( j = 0; j < length_d_comp; j++ ) { + d = d_comp[ j ]; + basis_ptr = target_ptr - d; + + /* Check that we are within range of the array */ + silk_assert( basis_ptr >= frame_8kHz ); + silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz ); + + cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + if( cross_corr > 0 ) { + energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ, arch ); + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = + (opus_int16)silk_DIV32_varQ( cross_corr, + silk_ADD32( energy_target, + energy_basis ), + 13 + 1 ); /* Q13 */ + } else { + matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0; + } + } + target_ptr += SF_LENGTH_8KHZ; + } + + /* search over lag range and lags codebook */ + /* scale factor for lag codebook, as a function of center lag */ + + CCmax = silk_int32_MIN; + CCmax_b = silk_int32_MIN; + + CBimax = 0; /* To avoid returning undefined lag values */ + lag = -1; /* To check if lag with strong enough correlation has been found */ + + if( prevLag > 0 ) { + if( Fs_kHz == 12 ) { + prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 ); + } else if( Fs_kHz == 16 ) { + prevLag = silk_RSHIFT( prevLag, 1 ); + } + prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag ); + } else { + prevLag_log2_Q7 = 0; + } + silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) ); + /* Set up stage 2 codebook based on number of subframes */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + cbk_size = PE_NB_CBKS_STAGE2_EXT; + Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ]; + if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) { + /* If input is 8 khz use a larger codebook here because it is last stage */ + nb_cbk_search = PE_NB_CBKS_STAGE2_EXT; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE2; + } + } else { + cbk_size = PE_NB_CBKS_STAGE2_10MS; + Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE2_10MS; + } + + for( k = 0; k < length_d_srch; k++ ) { + d = d_srch[ k ]; + for( j = 0; j < nb_cbk_search; j++ ) { + CC[ j ] = 0; + for( i = 0; i < nb_subfr; i++ ) { + opus_int d_subfr; + /* Try all codebooks */ + d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size ); + CC[ j ] = CC[ j ] + + (opus_int32)matrix_ptr( C, i, + d_subfr - ( MIN_LAG_8KHZ - 2 ), + CSTRIDE_8KHZ ); + } + } + /* Find best codebook */ + CCmax_new = silk_int32_MIN; + CBimax_new = 0; + for( i = 0; i < nb_cbk_search; i++ ) { + if( CC[ i ] > CCmax_new ) { + CCmax_new = CC[ i ]; + CBimax_new = i; + } + } + + /* Bias towards shorter lags */ + lag_log2_Q7 = silk_lin2log( d ); /* Q7 */ + silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) ); + silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) ); + CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */ + + /* Bias towards previous lag */ + silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) ); + if( prevLag > 0 ) { + delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7; + silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) ); + delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 ); + prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */ + prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) ); + CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */ + } + + if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */ + CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */ + silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */ + ) { + CCmax_b = CCmax_new_b; + CCmax = CCmax_new; + lag = d; + CBimax = CBimax_new; + } + } + + if( lag == -1 ) { + /* No suitable candidate found */ + silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) ); + *LTPCorr_Q15 = 0; + *lagIndex = 0; + *contourIndex = 0; + RESTORE_STACK; + return 1; + } + + /* Output normalized correlation */ + *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 ); + silk_assert( *LTPCorr_Q15 >= 0 ); + + if( Fs_kHz > 8 ) { + /* Search in original signal */ + + CBimax_old = CBimax; + /* Compensate for decimation */ + silk_assert( lag == silk_SAT16( lag ) ); + if( Fs_kHz == 12 ) { + lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 ); + } else if( Fs_kHz == 16 ) { + lag = silk_LSHIFT( lag, 1 ); + } else { + lag = silk_SMULBB( lag, 3 ); + } + + lag = silk_LIMIT_int( lag, min_lag, max_lag ); + start_lag = silk_max_int( lag - 2, min_lag ); + end_lag = silk_min_int( lag + 2, max_lag ); + lag_new = lag; /* to avoid undefined lag */ + CBimax = 0; /* to avoid undefined lag */ + + CCmax = silk_int32_MIN; + /* pitch lags according to second stage */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ]; + } + + /* Set up codebook parameters according to complexity setting and frame length */ + if( nb_subfr == PE_MAX_NB_SUBFR ) { + nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + } else { + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + } + + /* Calculate the correlations and energies needed in stage 3 */ + ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals ); + silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch ); + + lag_counter = 0; + silk_assert( lag == silk_SAT16( lag ) ); + contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag ); + + target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ]; + energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length, arch ), 1 ); + for( d = start_lag; d <= end_lag; d++ ) { + for( j = 0; j < nb_cbk_search; j++ ) { + cross_corr = 0; + energy = energy_target; + for( k = 0; k < nb_subfr; k++ ) { + cross_corr = silk_ADD32( cross_corr, + matrix_ptr( cross_corr_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + energy = silk_ADD32( energy, + matrix_ptr( energies_st3, k, j, + nb_cbk_search )[ lag_counter ] ); + silk_assert( energy >= 0 ); + } + if( cross_corr > 0 ) { + CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */ + /* Reduce depending on flatness of contour */ + diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */ + silk_assert( diff == silk_SAT16( diff ) ); + CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */ + } else { + CCmax_new = 0; + } + + if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) { + CCmax = CCmax_new; + lag_new = d; + CBimax = j; + } + } + lag_counter++; + } + + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz ); + } + *lagIndex = (opus_int16)( lag_new - min_lag); + *contourIndex = (opus_int8)CBimax; + } else { /* Fs_kHz == 8 */ + /* Save Lags */ + for( k = 0; k < nb_subfr; k++ ) { + pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size ); + pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 ); + } + *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ ); + *contourIndex = (opus_int8)CBimax; + } + celt_assert( *lagIndex >= 0 ); + /* return as voiced */ + RESTORE_STACK; + return 0; +} + +/*********************************************************************** + * Calculates the correlations used in stage 3 search. In order to cover + * the whole lag codebook for all the searched offset lags (lag +- 2), + * the following correlations are needed in each sub frame: + * + * sf1: lag range [-8,...,7] total 16 correlations + * sf2: lag range [-4,...,4] total 9 correlations + * sf3: lag range [-3,....4] total 8 correltions + * sf4: lag range [-6,....8] total 15 correlations + * + * In total 48 correlations. The direct implementation computed in worst + * case 4*12*5 = 240 correlations, but more likely around 120. + ***********************************************************************/ +static void silk_P_Ana_calc_corr_st3( + silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */ + const opus_int16 frame[], /* I vector to correlate */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of a 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr; + opus_int i, j, k, lag_counter, lag_low, lag_high; + opus_int nb_cbk_search, delta, idx, cbk_size; + VARDECL( opus_int32, scratch_mem ); + VARDECL( opus_int32, xcorr32 ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */ + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the correlations for each subframe */ + lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 ); + celt_assert(lag_high-lag_low+1 <= SCRATCH_SIZE); + celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch ); + for( j = lag_low; j <= lag_high; j++ ) { + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ]; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} + +/********************************************************************/ +/* Calculate the energies for first two subframes. The energies are */ +/* calculated recursively. */ +/********************************************************************/ +static void silk_P_Ana_calc_energy_st3( + silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */ + const opus_int16 frame[], /* I vector to calc energy in */ + opus_int start_lag, /* I lag offset to search around */ + opus_int sf_length, /* I length of one 5 ms subframe */ + opus_int nb_subfr, /* I number of subframes */ + opus_int complexity, /* I Complexity setting */ + int arch /* I Run-time architecture */ +) +{ + const opus_int16 *target_ptr, *basis_ptr; + opus_int32 energy; + opus_int k, i, j, lag_counter; + opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff; + VARDECL( opus_int32, scratch_mem ); + const opus_int8 *Lag_range_ptr, *Lag_CB_ptr; + SAVE_STACK; + + celt_assert( complexity >= SILK_PE_MIN_COMPLEX ); + celt_assert( complexity <= SILK_PE_MAX_COMPLEX ); + + if( nb_subfr == PE_MAX_NB_SUBFR ) { + Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ]; + nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ]; + cbk_size = PE_NB_CBKS_STAGE3_MAX; + } else { + celt_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1); + Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ]; + Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ]; + nb_cbk_search = PE_NB_CBKS_STAGE3_10MS; + cbk_size = PE_NB_CBKS_STAGE3_10MS; + } + ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 ); + + target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; + for( k = 0; k < nb_subfr; k++ ) { + lag_counter = 0; + + /* Calculate the energy for first lag */ + basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) ); + energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length, arch ); + silk_assert( energy >= 0 ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + + lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 ); + for( i = 1; i < lag_diff; i++ ) { + /* remove part outside new window */ + energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] ); + silk_assert( energy >= 0 ); + + /* add part that comes into window */ + energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) ); + silk_assert( energy >= 0 ); + silk_assert( lag_counter < SCRATCH_SIZE ); + scratch_mem[ lag_counter ] = energy; + lag_counter++; + } + + delta = matrix_ptr( Lag_range_ptr, k, 0, 2 ); + for( i = 0; i < nb_cbk_search; i++ ) { + /* Fill out the 3 dim array that stores the correlations for */ + /* each code_book vector for each start lag */ + idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta; + for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) { + silk_assert( idx + j < SCRATCH_SIZE ); + silk_assert( idx + j < lag_counter ); + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] = + scratch_mem[ idx + j ]; + silk_assert( + matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 ); + } + } + target_ptr += sf_length; + } + RESTORE_STACK; +} diff --git a/src/libopus/silk/fixed/pitch_analysis_core_FIX.lo b/src/libopus/silk/fixed/pitch_analysis_core_FIX.lo new file mode 100644 index 00000000..46ccdff3 --- /dev/null +++ b/src/libopus/silk/fixed/pitch_analysis_core_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/pitch_analysis_core_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/pitch_analysis_core_FIX.o' + +# Name of the non-PIC object +non_pic_object='pitch_analysis_core_FIX.o' + diff --git a/src/libopus/silk/fixed/pitch_analysis_core_FIX.o b/src/libopus/silk/fixed/pitch_analysis_core_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..351cae6a3810007fa7d7b14546341829f45633e3 GIT binary patch literal 59144 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 literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/process_gains_FIX.c b/src/libopus/silk/fixed/process_gains_FIX.c new file mode 100644 index 00000000..f8dc2385 --- /dev/null +++ b/src/libopus/silk/fixed/process_gains_FIX.c @@ -0,0 +1,117 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" +#include "../tuning_parameters.h" + +/* Processing of gains */ +void silk_process_gains_FIX( + silk_encoder_state_FIX *psEnc, /* I/O Encoder state */ + silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +) +{ + silk_shape_state_FIX *psShapeSt = &psEnc->sShape; + opus_int k; + opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10; + + /* Gain reduction when LTP coding gain is high */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */ + s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) ); + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 ); + } + } + + /* Limit the quantized signal */ + /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */ + InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin( + silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length ); + + for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) { + /* Soft limit on ratio residual energy and squared gains */ + ResNrg = psEncCtrl->ResNrg[ k ]; + ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 ); + if( psEncCtrl->ResNrgQ[ k ] > 0 ) { + ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] ); + } else { + if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) { + ResNrgPart = silk_int32_MAX; + } else { + ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] ); + } + } + gain = psEncCtrl->Gains_Q16[ k ]; + gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) ); + if( gain_squared < silk_int16_MAX ) { + /* recalculate with higher precision */ + gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain ); + silk_assert( gain_squared > 0 ); + gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */ + gain = silk_min( gain, silk_int32_MAX >> 8 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */ + } else { + gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */ + gain = silk_min( gain, silk_int32_MAX >> 16 ); + psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */ + } + } + + /* Save unquantized gains and gain Index */ + silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); + psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex; + + /* Quantize gains */ + silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16, + &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr ); + + /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */ + if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) { + if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) { + psEnc->sCmn.indices.quantOffsetType = 0; + } else { + psEnc->sCmn.indices.quantOffsetType = 1; + } + } + + /* Quantizer boundary adjustment */ + quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ]; + psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 ) + + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 ) + + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 ); + + silk_assert( psEncCtrl->Lambda_Q10 > 0 ); + silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) ); +} diff --git a/src/libopus/silk/fixed/process_gains_FIX.lo b/src/libopus/silk/fixed/process_gains_FIX.lo new file mode 100644 index 00000000..80571ccf --- /dev/null +++ b/src/libopus/silk/fixed/process_gains_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/process_gains_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/process_gains_FIX.o' + +# Name of the non-PIC object +non_pic_object='process_gains_FIX.o' + diff --git a/src/libopus/silk/fixed/process_gains_FIX.o b/src/libopus/silk/fixed/process_gains_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..d443070f37d72065b94f47aa77b6fa630fe8b9bc GIT binary patch literal 28664 zcmb_^3w)H-(f4_>$+8g4g&+h(6C_|Li~}b(*BNh~=-prAo$2m92BLj6y~knX zY`4*uy735f-*BS4!+8CgzLRT(SmRB7_E=@_?|Z(=n*6!D_vnGw-ESW6IlLAueg_8c z`NT-w@F-}m?A^2Lx*b9sI9cmGS=)P}7WKk(+{Wv>`aqBS8Za2dQWuU@yzBf-?bNISxLR_;?tOHX(s^_D%)!t*(ftS%( znCpHy$ca54x!k=&YkKx1*35h}b;GWceSJ0Fw`w*&lk)`FRonYX^`4ItWF%65wIOqy z5JfLnZ+>;2k0bX3yLHosZkXPl<1V*j zea;OqbkFW}YgfN0ePFns20$D+3Zv-wZ@LbJHa{)?r>}2MpQC4=@n)a&q*?~Y4&nlM z1!tZ5+|kYDeYL$G)oi|MePXrOsD>C;_wI$zzNlu~>;9&C=Iil8M}7?QsafmLCu(Fd zw`li~RWK~%3QQYX+y@}+uS4J0F)fbNgY6H%k^=X`6o7@eEs4kn49O80)0JkI;+97dQX2c@LY_Z6(cU$CHPib;! z=6Z`9`=};|m3#)IGavjVH4dAW38eEvi=TcB+v_ZTMgq29Vew@XkPlh>%rk%-x-~iX zLAVbKloX5P$%-s070KU``IC&@ks6NPpCFP^{Y(A)8GwpHBY9F7Y)U~U`8*_vp3)1V znF^n}7VrmCrA!|B)nzCqADQ9A6yShq#1vx7NMeeR$t0#2nQ_FFAd^kZG-Ps!nZ5ru=&<3?aMDrTbbHi%&X2L*Wsu7O(>lP{UO6jLCX2NhE&nI{xeY~(?o zrxjBoZQHGw>Bcq~=XsGKb^lm~A#?a$I7#KoyOAXN9-J-|QfhZ^A zvP83G_z}fuO7y21%@8ATBpLeQ7a52vdX9~DOZrR{O!+>JsmP7}WUoc0jzvR~o8Ti6 zO2;VSJfSMS6PPCqQI&uMp|^NC~-~ z(hH6uoursTmlGQlQ zXgAU-+Uey;t3{Vy@mrwPqD!wtI#>0bi$$y~v#wU8S0Ox0!Sj%=RdhAdOBG#%Qwu87 z5SFG=O*x=>2bp?t2_R!frq3S@yN>E#hb9rd0Ckb6^;G~5S27KVr;(1vKcSB5^o2Vu z9gDC&k&eZ(R;hkVkWN(eB}h9JeJOUOaW2C`M=n{4IJx94 zx?;9q^mh=m6`7}rxe4ukhL|59^DHqxM6un(Y(wUGVs1v}C1QSrcD+i>Ey%n<%&jQ) zHZiv$bC8%HBlA8nwZRBJ&wB+mSg+%w5QQLCoFA94F=;WWFKh zUbIb&P!9Piwj>gBA2Kdt?w5Wh<^gO;Bj!P5MiTQ7GMU6YjLbM<9ziCXm`9PxA?7h; za*6pFjx&{*$B`){<_Q#=M$FHVDI?|=$jl<iH8H=!wNp>bQ^+hK z=IPrZLzWTq>$`zzC+0V(pqrST$XrFtv+sg}b;Rt#bm<}Hxu1iA^~CJKRNqR>-aXK= zgP7-0+ZP!s3j5xImgB^{B*z)0T3$wG9Wk#Uv!0k&k=aPhYslO{%zk9H67wc9+lYA^ znOli@rw**XgP8YjhO%-OF@Hd@H%2Q9{)o)m#JrEpL1I2Y=6zy5MCLk&3_Cx>aYJog@jY^v=b?7U(lU)Sc0nP#SOTY~P zIvmHa_ZS8TX2t7%s)ioA6NIITDO$pia;XZvK%*HV8Ov{j<`bmU5aC1#c{~`Ai;Yrh zg_g<{PLI_-8DZIelWxxv&TFjpDG1BIK!g;sVJ{4iv{-$mpFPwX<_B@1T`{%lS zm~eh%wdW%&+tZ;&O8b+A(*Ro8Ux2V|FVgJ^!imLPwHG2R+ZXHhp;Ak_aJnt2Vr-OB zS8FMkmTI%4O0ZE%-K(XP-(AAF*^-)$jcV{xBxQ&Fx`RVFcUkRa2+Q`r>-JlO^G{a$ z`3Ngj7xa^}`pMZyN(BXw_0r-r;miVB^|}yY*}g!x8^U>!)jkJd*&f#IlZDf?+RG7E zsw&Zuik!P&k9wc(l_;DyTcTA6ORX>H_9Wqa(rTZFux$T}Zik$F$7-)eShgp@DO%3T zDV$$g?H41gOsSRO-2-c|P>VwNv#s{|2rJP#B$Hd=<1+XswSwq(flhMGgjM2P2BZ>Q zfD($Vm%Xt4CR?v-to8 zazs!Qvikb5F*yKI4{NDJ?apnMR690GsW%2nfv(?JQUPpC#u1Ndsdd8nq17Hlcx+n6 zl$r2g2R;)bV=C@iMCakYt4@X)`ADmiVTOD$FkBruGYSRt9sS1mjOjO8N=mV|sz;!V z8K^sR95@8DpN}%R#9V-N{H5`#Wftmxb-XIE+d)be<<}Evl-ZR4jeg$9D8Ch+I+dyN zIfCf9XTpf;%$HGxb-P~4%)>Fd6 zL`g}YG+vW#Cql9CxU^vWPJ+h&ToVrvp~id>xa{mq-9z0IE}V_l6>50WLF%K$65Qjz z)cTIt^-VOW&%|U+oT;@?=kxTukoOX3H0>P)YXnINl;`QsVvaN} zO@r>^TL>P%SQE8GOx2!T4M3i;&~eohjy$6|;VQuMbz3jA6=-G~FcqK_g}b&+RKj^i zgQM%#vi>gHQGb#P>sOKs*Dh>+Ko_Exgn77<9O&JmZsLkpi3Ishqd2&lD7iKiC`x3% zGRIrkClC?|Gf_nm%ASuH{NV@mUVxdxBB1ithA`_n!M!GREB_r99a#l*ZF=7Y?IboD= zq@168L2?av+mR!ZlP`pJ&_N`e<&)sxE}NZ`1WFA-9&DH)xuK(t^T6Z)aq0Ypf9@ z4(-@GLr(;rqBEc;_BfMNfb~knsPW*V(HTa+4VnEGqn0t!RD4ATLe@}cTiY8c(zfL(P%6jy(IY(>AUesq9_B! z&P@gsmgqF#p;#w_9P$&9$M#9~o8PTLkyAch87}0d95e=sr(PSHU z0I5e#6!BZjwrfs@AyL5Auw8T7lpz?D3DBScZGsZloQ{W5tvT%&B|E?tU=|P%p?iWT z+}_|&Ogr5Xqh{--WtNeQA?mF*BDCrquu0$rBHI2w%kA~sNr5(V5JmT?{%}B6M1ojl z(fD-^yv`Ca;aWS^_0BoN`ufJkg)2M9l|AX4Ig{ezT+40vwOy6J$`tMNQCvc#HCqqa(W%Mguw$#L&kackD(djt(KoNjvG>eZ;pzgSSSCJ$Rs zqb84@Ubk-g((2W$Nu6ASSj64d6@tO?mU!{IwSePc(DQuk34$3vw#tsz>~ z>Efad{!irwajq^VFH&5R#cC>i#W~wG_zE?`uE!mt`~S`oIc4wEBF~XXqJXEK?V9V? zy-<@{mlEV7;xm+5v2ez=UAp?)AW60nplhmLusY4G<+i?wyINVQZRh&ED!#LEI9 z2oF>s(&c&-?g@_NF~>Pu6O$a(vl0zQ*`r8Z4AjgeD_v_h>~aiuU3*PrWpwsqH*JYW zhTxg2(C8y>30;nMkGvuJg$qh zHF{!!a8pOD-E1fm^DvbbhE|vj@NGCuXS1%hsmiP|JigL?F}|kC`jto?sxh%53q3d{NLjUDSKL%l)yYz-qtQ5fw6FAb-j* z=^*450IyF_8H{E6Lp~9$ZLWvWJ3+-X5v>fgwp!duPoxu*7!8g`{gus2M5vz%Alnvd^K{5*tc(O=emRkN z2ywqJ8zwD6RS{2zKU(jPD6fe6xs6JZ&mRp${61~J*%~#gSF7PW*Lu()sjhU@Dmg#8)kC?D7{V`#-20d+2h*VcY+!Km5#r&Nz zE)Au^G{L@-Vu+*60lQW?Yg56t<&ER21t@B(tl&V{$l;hur_?J^QC?&&ZflR34Ksz= z;fXBwN67iXXp3@iw5i?G=?5!iWX#&~#ztT;%s~%~gKZFY>8Z|e5X|slYDPr|#7($E zo~9UJMHWRt#C+;nq2k{ei$KI?h|WOF+Ya%T0ab&WkbzJ*0wJ@*-{I|CrDWztV*w~! zfpDlIjODExQXH&_#&Gq>`PM_SiDplv%^$;rFk3olTK*8`6V^k7p=2uuLsE3e<JbGU`vJi(hR$# zh%RzhQh>k~T%VA${%)lN7BB|I3LRFYs6QycY&mTorVb_{)r7e+PkdmPy^P8r)-^TQ zcSuzyp{m9^q0C18!Utyq&wSJd<<<%rw@^eo{eD<19&aqrg#{kA4zo1?ZVrRDJ3YQ48WGngPxj`B z2dW@0AG5aJbej#uQ2x=g5pO#* zz$O#Zwci#g2zKc-Xi+27dm=I6uCLKWHr~=2(fNt_7x8<1%CitNxjHcLv~|c`vOfi4 zu;xTnO`{2w-5VA2>K0~K6cuI9$e*5Hn4Q-Vi--KP+x+0^fEQS_ayFb0^Gc^>=e1?$ zEhx^;Ywd!i))K&7b9Q?G4q_p|U~PMs=Rx_5`Mt4lBo7L0I0PL|)1X{}t09W(A9fm* zMlmR5GApQxr+)!ZJ%mzS5so%{TCf(vu*G0%7nICE7?@JABot|D!hpaD zpvrVNS{sX6!ELw(VPA+@NdY{hVXz7^L3rCe5z*v_vT4fA0Cqh{C_L$?S-{$hdOc9h zq|q%NsQ$SB(LR8=6b!F4@xZPms()j)w&6su>geIJqY!^H(#Tt#`KsF6!X7H2hw0sD!9 zU<)y+uF7MJLI>8(qCz-*safF+)cHhK57_>o3ggxxEiX2UVEF=TiXf((`~XV@#G;|7 zM4cC5%af-jR7D-2c$;cqIw+cT<>q`iLV}1a=yEVD_ml{O*#}+JZWL~k<)(sGJcLH> zvcl|yf-cW0{lyy}Kd9=Np|A->St-GzhO`B|i7QkU5x%1p!K|i>W?U$^!O0|)%S7%i z(i%K-fP3sI*CjRMp&8G8P|5hw5envDFjPq_kc$JMTD2bzDpjIR#cG>Xix6nROhQEIE}WLQMuI2E}1ua>i{Jc;YdVIPWl?N zRD}zCV6KGRpcUSMrynQ^up?42mGZLIN-c78pQehyJSYb>AulWqIL@l%f-N5o7Xm}3 zj;7HXSSYx}QMf-AI4wB5VST6Uu?O9Xc(kG;r2G!sj5;1c=G5cS4AW39N_@D0iUaXe zK}SDHFX|M+O4wA_X!^==ca{%8*_i*B#6FxQZtK?L2|lj`eDHi>+s>w|{IgaLCZS$2 zQVtFj@VKL3EUD@c1V}g#_1EHAzC7TeiP9F1J~6KhgCR<}${Xkm+q-O2bHEiU%Yi)E zVoj{}L^|YwT6)w`pL1Xt%k`BXaKbp#y0MK?ZQs?;0sTxO5nH06StP}h7=WI4@R+?nwCw5~-o&3D(O$r!Wmhq!+4g5!|*g}WnR?X zh))r4w#H&&l_^@{c!G{Pd(XML2wcOBWM=0#IOW3%b5uWwwi1fpeoT>vIG;c)`qfXQbh zoQry{uMNXXI(Q)Ps+AIj$`$g$CKbYyx%ILFj-Y}npj=`q1qL3Lp$NfYnKBD}L7MQ{ z6ZV5u@U#P=gh|0kD-eSD$TZ-a5v48coU+P-lyr$K8T~H-zy)yHfCoKw+AzKG2s|_d z<4{wf!gPTP^obds9J%hC_$dN{uLibX+txWixI_e6sJ0(Zm*X%jAh zcYzUjs`N(-<~G%r6_=K}AE&=yD0p-F zdEa0X4tzg5$mPKIu7g|-dGHN5B#GDe53f3tNb)L z{$YJE`9-I}@sB8j$!|Cf4$I=y*YR=zp3)%9d9@45-L>X|s;Z{B&8qg(d0D?pwLhcb zZl)jQq{aq(svGQ~O)Yr+HVG_+uTaZR%t`e#Uijs@y!Mex5yxm~{A(KyU$3$7ZhB{q zH(X;{elDdh>cLoP9A4zh3o}g92n?4fd;tvZxR9=(l!fm{%S+??$oc9UYyI*alsfRG zEqS52*6Vzr^;a2D5B}4a{<5Lg|2`R|zxAeZN2=<9d4!k7$C81UDcHi_r=^AYf|r(m zh4h3JY~h{c-zdWi$T8~}ew_S(d54$Q-w5Ad!fUI#S@>^J0Ir{?n}rw9(!Gb_qse)X zG5j#u|1`r*vhxLoUrG93VfZIx|2qu7l;Zd|hR>&xcbwtse;$Cp*pUCUAKJ*y6o!9E z@g2kP>xU}EISj9)aSIr}mh6CEJIPCrJBQ}AfZ?f>Cnm#noWcyhpLUbA44*(H{$+;G zpm@E@@H;6kA2U2o^Zh%+7gFB-55srRyoS&?dcMO*&q#*u70O1L<_^$(6~Qhcr(TKUWR`__`?j}LUDYY;g^!Xb~1b}<>5Yt ze?#&I7~Vqu{D9%dD2{(+cozBX7{e22z7F!Aj+cw#n9A@LvS%E_@#kT9O=kG*3Kpdd z@1$`n82($z+j@p?CqG}#@J%$ID;a)({J)an-=%fEp5fn;{7np>NpZQ8;ghNUJi_pi zShHoc5L57oiL^s1ruNA0)pWX87Z@9{yC0n)RN;kQw|{=x7$G_S82ZqmGlP~PddL@6#A41bdJWHB6mgfFit4A=3P z!SMaGUsN#sdKz~D!*3-0moYp>>$HvG9}&Ne;X_EzgA6~L@?;0Y<)Vj~?PhpB)#ZZ> z|1QPl5W{tyI?C`0^24_bFVpLX@<_+!yTp%X_&>>>9EQ&#dx{wTG>vy5!^>#h>2dV9 zA5&bGFnRTV#0lYN_;m7TgyCDMUae*Ld>Z!#hTlT*x{cxOG_U&^o=kdv$?z*^zPlNY zzdyq3HHLSRKmWk+)x;lW_%pPQzF_z|imyTIM*DLq`5}ejE0j6nEQXtO&dg=_T+09H z496el<5kY^(KN3G41a;_U&`HjOk-=O?C&hU{WpG1DbW+aD`A4V{I292A= z@Jk4v%J9RKpEDUgk=A1s!?#iXH!(a+>tz|kJ851W48M^4wwmERG~e$t{5^{AHimDd z_}E!Br) z$}c_NofP-Q49_8dtz`ITgx|t&{EraudWzv`guln|N6DUJ4DTU7kEXk}^AOoNgW>DR zpO-WI8(ps${ut%qLk!pNn|3fGG`KOQJ0iA!8r+Qwa$(}PAzJ=tc zGyDU}=Y-p{@e`b~o$?y>QaXiD1l7I3TK8n`M`3%35?5Sh; z`xGzzcLQzDJ(MSHO#WNSL-oJB_W#{P?+4c~`Oj#+cQJf9#cKz{|4#GW&G1c>=dUt6 zp!1F4e3_B_P!I`ZcZhPRX7enU8x zM}nju-(>PXqIL2|8%|43%719XF|;K#um85;D8E5U3-J#dj`Hag-xD?*<%dz-K54^I z-XK4_=!*~79p$&^eTw0eXmVq1IO<8Fe9E!msOJijpKQZXK9~GiV#87X8j>%w;V8eH z)>pX=NBLJsex40S`Fkji4K^I*_1_y7*>IHC`LoQ1qx>q;pW?LHoP|3KkY&h!C z^80N#%3n$H?=f8c&;CMu$nYmf{s`fGzMtFVaolC_53g@*IF5Ue^d!+A@^yadF9oD9 zT+b`RhTHXzCtTZ8PI*3=$#0d`!2ell!_l5xihDWJqknXIu}vPw-A#HH+HlmP{|=R#UK?)L6SU!|N6W_8hjta^^c8Tx9P`mvng-?WW#aXKhwMpGkgNo&!Y^lBK%9jwV(BKP&)iS zKzM1~typmm!~4jdN`}`^J@gTdamRXy{~aSU#$HN#k!3-b3SS zdG?7I`f9$<6Z44tmS|MuOVsCYiNmkS;77sGCTUMg3;uS%-V8s$9l(3wE7EQ7 zqXg=qIh#WKX})d-D@49G+|dEQZx{I?_;pu4{9+7#-37n)BDMZ@^}}77+yBcg8#<%U zw7<2kIYj91Rcbs<6Ldcd?wIOxh}XByaz%9$fN6l^P+1a`R$>z2lx`#~#Md0477DW^ zHx($<$;JP-{Y#-Q*NMt?|3|c;2*Sl>ivSyJ{-4tPUz#Yp$?ryD9`pI57}tqC?x!y$ zA5TE8|KhR>p^0NCeP@>HbF&^$v8Tw^13sAjPqeEJ%cvj54^?S(+AV&-1{=R5S9L5@ zH|vwjE`yfA#!m~VF1kOCkF|r39|Mf*#GYOnU;no{h~dR$zds0ua=)C6pF-%ri!1Kb z{?|goVD`@;`?a6Ye%y+<{XYZ@ZPN1uQeK-evEh1vp1%~=Kfay^{!dkd^`CZ;>hT@j zk?y*mzCS?ynV7hO`g2_O)A%#gpQWi-M*Z8hAl>!+HT)D1gZXdCApS#F=>FQTXb&G7 xb-zU8r%@wrE4Wqj{zC!dwF4k=(2bu$V0`QspFbWW2J7ER_P=QF3^ecme*ku*A(#LF literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/regularize_correlations_FIX.c b/src/libopus/silk/fixed/regularize_correlations_FIX.c new file mode 100644 index 00000000..dcaac56c --- /dev/null +++ b/src/libopus/silk/fixed/regularize_correlations_FIX.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" + +/* Add noise to matrix diagonal */ +void silk_regularize_correlations_FIX( + opus_int32 *XX, /* I/O Correlation matrices */ + opus_int32 *xx, /* I/O Correlation values */ + opus_int32 noise, /* I Noise to add */ + opus_int D /* I Dimension of XX */ +) +{ + opus_int i; + for( i = 0; i < D; i++ ) { + matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise ); + } + xx[ 0 ] += noise; +} diff --git a/src/libopus/silk/fixed/regularize_correlations_FIX.lo b/src/libopus/silk/fixed/regularize_correlations_FIX.lo new file mode 100644 index 00000000..5e873c65 --- /dev/null +++ b/src/libopus/silk/fixed/regularize_correlations_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/regularize_correlations_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/regularize_correlations_FIX.o' + +# Name of the non-PIC object +non_pic_object='regularize_correlations_FIX.o' + diff --git a/src/libopus/silk/fixed/regularize_correlations_FIX.o b/src/libopus/silk/fixed/regularize_correlations_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..da672465f75156b35180e7181c1aa9de133fcf74 GIT binary patch literal 11384 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 0 ); + celt_assert( D <= 16 ); + celt_assert( cQ > 0 ); + celt_assert( cQ < 16 ); + + lshifts = 16 - cQ; + Qxtra = lshifts; + + c_max = 0; + for( i = 0; i < D; i++ ) { + c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) ); + } + Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 ); + + w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] ); + Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 ); + Qxtra = silk_max_int( Qxtra, 0 ); + for( i = 0; i < D; i++ ) { + cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra ); + silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */ + } + lshifts -= Qxtra; + + /* Compute wxx - 2 * wXx * c */ + tmp = 0; + for( i = 0; i < D; i++ ) { + tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] ); + } + nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */ + + /* Add c' * wXX * c, assuming wXX is symmetric */ + tmp2 = 0; + for( i = 0; i < D; i++ ) { + tmp = 0; + pRow = &wXX[ i * D ]; + for( j = i + 1; j < D; j++ ) { + tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] ); + } + tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] ); + tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] ); + } + nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */ + + /* Keep one bit free always, because we add them for LSF interpolation */ + if( nrg < 1 ) { + nrg = 1; + } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) { + nrg = silk_int32_MAX >> 1; + } else { + nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */ + } + return nrg; + +} diff --git a/src/libopus/silk/fixed/residual_energy16_FIX.lo b/src/libopus/silk/fixed/residual_energy16_FIX.lo new file mode 100644 index 00000000..1bcfabe8 --- /dev/null +++ b/src/libopus/silk/fixed/residual_energy16_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/residual_energy16_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/residual_energy16_FIX.o' + +# Name of the non-PIC object +non_pic_object='residual_energy16_FIX.o' + diff --git a/src/libopus/silk/fixed/residual_energy16_FIX.o b/src/libopus/silk/fixed/residual_energy16_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..4524d65e9f111ecc8cbf0c000b97ef35be9bdb1a GIT binary patch literal 18976 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 wU4UmH1}HH6w^;ns%VTn+a literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/residual_energy_FIX.c b/src/libopus/silk/fixed/residual_energy_FIX.c new file mode 100644 index 00000000..f8abd232 --- /dev/null +++ b/src/libopus/silk/fixed/residual_energy_FIX.c @@ -0,0 +1,98 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" +#include "../../celt/stack_alloc.h" + +/* Calculates residual energies of input subframes where all subframes have LPC_order */ +/* of preceding samples */ +void silk_residual_energy_FIX( + opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */ + opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */ + const opus_int16 x[], /* I Input signal */ + opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */ + const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */ + const opus_int subfr_length, /* I Subframe length */ + const opus_int nb_subfr, /* I Number of subframes */ + const opus_int LPC_order, /* I LPC order */ + int arch /* I Run-time architecture */ +) +{ + opus_int offset, i, j, rshift, lz1, lz2; + opus_int16 *LPC_res_ptr; + VARDECL( opus_int16, LPC_res ); + const opus_int16 *x_ptr; + opus_int32 tmp32; + SAVE_STACK; + + x_ptr = x; + offset = LPC_order + subfr_length; + + /* Filter input to create the LPC residual for each frame half, and measure subframe energies */ + ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 ); + celt_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr ); + for( i = 0; i < nb_subfr >> 1; i++ ) { + /* Calculate half frame LPC residual signal including preceding samples */ + silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order, arch ); + + /* Point to first subframe of the just calculated LPC residual signal */ + LPC_res_ptr = LPC_res + LPC_order; + for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) { + /* Measure subframe energy */ + silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length ); + + /* Set Q values for the measured energy */ + nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift; + + /* Move to next subframe */ + LPC_res_ptr += offset; + } + /* Move to next frame half */ + x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset; + } + + /* Apply the squared subframe gains */ + for( i = 0; i < nb_subfr; i++ ) { + /* Fully upscale gains and energies */ + lz1 = silk_CLZ32( nrgs[ i ] ) - 1; + lz2 = silk_CLZ32( gains[ i ] ) - 1; + + tmp32 = silk_LSHIFT32( gains[ i ], lz2 ); + + /* Find squared gains */ + tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/ + + /* Scale energies */ + nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/ + nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32; + } + RESTORE_STACK; +} diff --git a/src/libopus/silk/fixed/residual_energy_FIX.lo b/src/libopus/silk/fixed/residual_energy_FIX.lo new file mode 100644 index 00000000..e84657cd --- /dev/null +++ b/src/libopus/silk/fixed/residual_energy_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/residual_energy_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/residual_energy_FIX.o' + +# Name of the non-PIC object +non_pic_object='residual_energy_FIX.o' + diff --git a/src/libopus/silk/fixed/residual_energy_FIX.o b/src/libopus/silk/fixed/residual_energy_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..1fa2cc6253320804ef5c80f25870fbc62a400a55 GIT binary patch literal 16904 zcmbVT33Qyrk?wyEd1P6KEim!{9uuD!9V5%~fv=G*GXlxhX>5c2do=S)8hbP&&tYT& zHqUzAcp?OLLK4EVF-bN+60!l3-Q@_09gby59wG49N61^kk^>U5OANt*N5EUvUG>ke z)+otKzo+@DzN)USs;=(-=l@4Xnp?NH3`1};#CnnE7!@M4HcxMqgTF0gx^T1GVtv^xz_%kDC=Z*Z<7+YKX;%m8| zhVBTy_Jc^$ZM^2<;@%^=Zv0*D( zo3hfeXf_--t%Q~8KV)uc*-;abO7Ia*r>#^bmQ48j!m+p&UE^QkPxPAUY;Rx6zka>ugn#ohAgPP6(eYTVThx5?7v=r2FMnfVh2A5O=%e z#pChD5*gv$0#K1J3ZLFilp00wDZINS?L*q_ksYKZ&w`^;Ae9udFb0Ss7o9?(%L|`` zEJ5>1xOB)Sm;DEjZl6Q%7DSZZ7?M+bMLu*vLf)$DZF1J_HaYtqo1F7KCX1?aHaYu2 zCZ{a_J&@iS$d|M@rJ)K)?|PeG@h6mTwfU7Ul<%?mRi8jUVe_j?fh_Xvgip6ePKMhj zFEV4rzcn!KV)zp;``%mX7Gf&WzH3@kxK}Y#jecMT6f;f6F{GFZ$z&8W z!*~un7*@KLfQBim5h!1%eTu1*%ma$4H>#n}!-`oheLJm~6~+jR^Q4dq!*{2ghAQ9P7^F(&mysm;D;O?K z!#!I7u7G*11FXpRb(q~!tU`3V43`k1IGYmvETfg897S^KeH#qK6}{0x2PIvBic>#@ zV=D4^p3K=~$!v6_bO(IA3!2k~_f76lG6xY_JMIcubESvC(fL41A8!`k=|D^K(-tB; zBUIY+EL>&qrQ5M+iM|GDm%?`-?NRhjq>B{23%jZWm0p_zT-9mmb%?7vE!~Z@U+M2b zdWoV3XBbJv4?_;*S7GWuWi{&oi{kbi#Ls-hE7f}|9Wfq`1 zKD4#!Q7E-mvX+mv<^!T~u^fd`Yd32dQp+d2SK3-DP^daIA}Ko@=MHY+9k%7G5SH@$ zSpEg!y~CETL0Fl(B2TW(lk1R_27b#1DunlEcCYmaOL;LIM$%V9ct5b^8xfZBr7T}6 zyt9B-qc$O|$jz8YMK&L2t0wpI2=6vqbqm7M>JgTEg*R!-uS8hNPq7?o@-|x@LRiXw z!15yD{kAQ?3Ss3+tDN5Fp`3rmsxbYp*zz`nmFiX`OZ~9LTnK+M7oh3|y2!U0*VAku zmFhOsP-MI8h4QN%y{@q39SAGcF6j$y0S6tbeYU(CVWqkqGpNXG

    19`?*)S@ZM#s z?nGE7h-=`UO8E{lxfRM2WNo^C?-)7AdQ^NNNU=aCIPLcjv-W&;Eef_TWo8f<@Ua+L{TfQW$cI&2eOf zX0gIVUR)6r#&lz0S!Id4Y);v9W5yJ$7uQVTE?ZM_MM(?PwtImnDOnG4xQ`$b)~R=q zKw(ii2$7hA1l&r@Y)Wz zAkqtg^{Ggao#~KPLH*`OLTMGS4&_-6DJaj*ONE%z0A4rD!d`PPHUgEMM$bh%N_NT| zT1eWK6K%f9>igln6WMTkYPy;E(7#7cJ zsr1Vs7UtuC$*vKYr$m|35@K;4;DUf_f@nkZFnNm&nM^)zL%W&8(+8VdoP6^zGmjAH z5$_s3r**>yu)$0R!r zQM^_#itYkY>?ssQ_bHBoT{gs?iJmG1&N?hwaA`b~f9YI&|-R;)uZG^3qeflf~$y60zUx9uzN=?3+WIp(48q zJD6m*ec}*}$_QuKVMmW9szu`xb*ENSlDE+nG2L6lbX%_zQ0C~z^gZouDbq*fV)HzJ`Ll;vQqez??;f&Kiw8J zwaAFtY&umNkM-8}Mx!!%d(d5c)P240 zgsY+4b!n9^u=3%QiEfjO;fvLS_q+w+d4WX|RFi^->Mg;k8Fpz78?7iCAAUHP~pzHf`Pl zP=BI7JSf$!PsK8pRLmw2x1xS9s(KA&<7q2x4p}L)SB~1$(%ofttWeTa7&^wSgH}9k zvcT+%hx^kamN?jv4JR^P8EdF3c7tVhGz!xMyUXjr^G!_w^P2vFjM=eTn1kWeek+w$ zCgbT|6>g-hG$v!BAfw|iR-(}=jZPEu! z9Jm6hOJ*}N5$W(jl?OTMP%IM}FeAxCCYenspZem-FeN6Pu~Jsj97Y+F>7pgau21g1dk%7s|G&aDM{lOP+ zP*92f%z%s_Wrd^4f5?NJK3u6H3{gOB;C>>&!(omjJ7}g4q+qSY`ZD6mtv&utfq;Ky z&5D{jfAwG{o3PgP<7>cJ1Xwh*4))6G#s+_NzrT80y}!EeU@Q$gPCS-5v~C~XcM2Y>3@T4JG4Br!S1g zRg4g8C#)>!K)r`ppkBegP|=Kw0L( z97?9uew1IXc<#{3FcV30dvLST#m!327^gt4ynIU216Dk)mX6E_O|lNt3ejQO<8*kr z+RW8%rIr|M>bTODt4o8rP=%;vnRkreVhi)2^oduz+=6jVB_Y?I%rfkOa6H#8Xfkq+kPyDuzxN6x{7j8^&TZcDbFoO-kS#0AEj3#+tKpDVMulnojf>H?n$oq_X zf%m0QGnsH)$QsGtaDZ31(?EU68w1$3ATeeH4)aJdo*jgv1EzuY9604n6{1`daCB$W zRiy0GOctQ+qV!Uduykg0O9_WvJ{WMN8AGjH=eE#`Mu{1#Oh!>A31QG55}j^ zS4FgswZJ%6I#wz_83t1Q`~|LvW3_IgrNtG;_#Enlv0!8TIJ~jM1}{=%L$~a2t3WSR zu+(>M12qmD$9;`DU7_LMqH&uv{6Tugu~)deRb^e@&f0g`yMZ?{+u79K9|4DY<(eQfm|6>gwAbKqa{okzNFHl@#8orbC@6_-X z%KyC@&S&O#HT+((e@4Ui5dWNp-%tF{HN2e0eN)3{68@fsUre}*>VoHM0paBuzL4r< zu7)3>JY1&XvuR!e8s1NK)@eBRZ_)6}X&!qtd@t3{?HZ21%fj|W4L?iceoe#6$j*Zr zZc$v1Yxn}kw!#9#Yw`%wp@po!CKMKD`!>3ao zAJXuT2>-r@cTk@HOT*7o-lkI=oc}wB=Y5OuWt9I8P5;Ma|A2@H_7j_8oq(}i^wnblh4a_8a_hv64CJWWIv(dUnc!qHT-j=|1TPTFZuI`hJT;% zCpG*f!hfRSzbE`{4fjxemQ$WM-anF`wHm&U>TQjN^L=)+hW~(gOT)V<-eVfxM&o`> z!}+D!QyRXO_~$kJRjP+SX!vc!f2iTJsje1Le4K|v#0NB7{a1((9U6W;<@Y)bUq!1q&ZhtG9B=NX?*`aY@)#(zfpK&6J$ zbcste{1WnWvxYxLcJ^ubugLEc8vY%cmj^VwnDY6UhCfGnJ3}~zLnfrFFKhZ^H16vT zoFJ+Hh6Bg%S?we|>%b9uT51dNv4$U{e7Z4_&^Vu$P##JhING^@oSosoaoiu0-MJ1N z^`9dB`3@ZQ&k?@NfunvKjjR4&An(sc%G-K}KH8}uJFOZ%i|p*u@V7}n>cDZ_w@Ckh zhCf2{cv!=|R6ipQ9Q|oQW6@pD?I1h&UMQ_GWfuuPb64_-(%840oFfB^|nmI zUzgfK?9=e~2v`3Wgun1p>*XS{^R%YVzaDx~!}tKkHT<(MpJ7!#6D zP~J9a_!{zOn})wk_0u&8zDvXLpN_EYnFO~qoX^YHBzQu@FQd9jO@dQ+GG3<9AO3#B z`9}=fjTEz6JhM`1F zBsn+;KkX1T33v-z18;WWEiAm1C9~Fm*_R3rS`_8qfAK?C%$+mWXl)~YK;ybqTz(#y zp92Jz*hU8Ex`Yb*KH~A&C60q@92@*jShhv*i8z&=0^#%Oag%1lQa8`3_XKG3@9iIe zzBqop(Jg$x@R&cGBOagg z*8!Mr6ML@aNBvqJbzO6^{`7$M2HJPgCN{l)vH*s9-ysLd@PGDu5 zfeQ=TGqhhSE*~rVaUTef*89J*K=rtcJJOZ=@%2H#nRcpr7CN~+t?NEb{k1X^KI$LJ zca;>!&+r)_3gvHaf&Af8;QpLf^hX~XZMW0-8%c=o6$= 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Check for invalid input */ + if( c[ 0 ] <= 0 ) { + silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) ); + return 0; + } + + k = 0; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 ); + } else { + rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 ); + } + k++; + break; + } + + /* Get reflection coefficient: divide two Q30 values and get result in Q31 */ + rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 ); + + /* Save the output */ + rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 ); + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1_Q30 = C[ n + k + 1 ][ 0 ]; + Ctmp2_Q30 = C[ n ][ 1 ]; + + /* Multiply and add the highest int32 */ + C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 ); + C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 ); + } + } + + for(; k < order; k++ ) { + rc_Q16[ k ] = 0; + } + + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/src/libopus/silk/fixed/schur64_FIX.lo b/src/libopus/silk/fixed/schur64_FIX.lo new file mode 100644 index 00000000..644480e0 --- /dev/null +++ b/src/libopus/silk/fixed/schur64_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/schur64_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/schur64_FIX.o' + +# Name of the non-PIC object +non_pic_object='schur64_FIX.o' + diff --git a/src/libopus/silk/fixed/schur64_FIX.o b/src/libopus/silk/fixed/schur64_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..94d69ae9b4a4d53e85820df76dbe035716cc6b8e GIT binary patch literal 13272 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 0 && order <= SILK_MAX_ORDER_LPC ); + + /* Get number of leading zeros */ + lz = silk_CLZ32( c[ 0 ] ); + + /* Copy correlations and adjust level to Q30 */ + k = 0; + if( lz < 2 ) { + /* lz must be 1, so shift one to the right */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 ); + } while( ++k <= order ); + } else if( lz > 2 ) { + /* Shift to the left */ + lz -= 2; + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz ); + } while( ++k <= order ); + } else { + /* No need to shift */ + do { + C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ]; + } while( ++k <= order ); + } + + for( k = 0; k < order; k++ ) { + /* Check that we won't be getting an unstable rc, otherwise stop here. */ + if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) { + if ( C[ k + 1 ][ 0 ] > 0 ) { + rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 ); + } else { + rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 ); + } + k++; + break; + } + + /* Get reflection coefficient */ + rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) ); + + /* Clip (shouldn't happen for properly conditioned inputs) */ + rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 ); + + /* Store */ + rc_Q15[ k ] = (opus_int16)rc_tmp_Q15; + + /* Update correlations */ + for( n = 0; n < order - k; n++ ) { + Ctmp1 = C[ n + k + 1 ][ 0 ]; + Ctmp2 = C[ n ][ 1 ]; + C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 ); + C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 ); + } + } + + for(; k < order; k++ ) { + rc_Q15[ k ] = 0; + } + + /* return residual energy */ + return silk_max_32( 1, C[ 0 ][ 1 ] ); +} diff --git a/src/libopus/silk/fixed/schur_FIX.lo b/src/libopus/silk/fixed/schur_FIX.lo new file mode 100644 index 00000000..f98ce3dc --- /dev/null +++ b/src/libopus/silk/fixed/schur_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/schur_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/schur_FIX.o' + +# Name of the non-PIC object +non_pic_object='schur_FIX.o' + diff --git a/src/libopus/silk/fixed/schur_FIX.o b/src/libopus/silk/fixed/schur_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..36c8f8b045637687e81d7360398059e091a2fc84 GIT binary patch literal 10528 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 literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/structs_FIX.h b/src/libopus/silk/fixed/structs_FIX.h new file mode 100644 index 00000000..ae87241e --- /dev/null +++ b/src/libopus/silk/fixed/structs_FIX.h @@ -0,0 +1,116 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_FIX_H +#define SILK_STRUCTS_FIX_H + +#include "../typedef.h" +#include "../main.h" +#include "../structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/********************************/ +/* Noise shaping analysis state */ +/********************************/ +typedef struct { + opus_int8 LastGainIndex; + opus_int32 HarmBoost_smth_Q16; + opus_int32 HarmShapeGain_smth_Q16; + opus_int32 Tilt_smth_Q16; +} silk_shape_state_FIX; + +/********************************/ +/* Encoder state FIX */ +/********************************/ +typedef struct { + silk_encoder_state sCmn; /* Common struct, shared with floating-point code */ + silk_shape_state_FIX sShape; /* Shape state */ + + /* Buffer for find pitch and noise shape analysis */ + silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */ + opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */ + opus_int32 resNrgSmth; +} silk_encoder_state_FIX; + +/************************/ +/* Encoder control FIX */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; + opus_int pitchL[ MAX_NB_SUBFR ]; + + /* Noise shaping parameters */ + /* Testing */ + silk_DWORD_ALIGN opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ]; + opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */ + opus_int Tilt_Q14[ MAX_NB_SUBFR ]; + opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ]; + opus_int Lambda_Q10; + opus_int input_quality_Q14; + opus_int coding_quality_Q14; + + /* measures */ + opus_int32 predGain_Q16; + opus_int LTPredCodGain_Q7; + opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */ + opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */ + + /* Parameters for CBR mode */ + opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ]; + opus_int8 lastGainIndexPrev; +} silk_encoder_control_FIX; + +/************************/ +/* Encoder Super Struct */ +/************************/ +typedef struct { + silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ]; + stereo_enc_state sStereo; + opus_int32 nBitsUsedLBRR; + opus_int32 nBitsExceeded; + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int nPrevChannelsInternal; + opus_int timeSinceSwitchAllowed_ms; + opus_int allowBandwidthSwitch; + opus_int prev_decode_only_middle; +} silk_encoder; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/silk/fixed/vector_ops_FIX.c b/src/libopus/silk/fixed/vector_ops_FIX.c new file mode 100644 index 00000000..74876f32 --- /dev/null +++ b/src/libopus/silk/fixed/vector_ops_FIX.c @@ -0,0 +1,102 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "../SigProc_FIX.h" +#include "../../celt/pitch.h" + +/* Copy and multiply a vector by a constant */ +void silk_scale_copy_vector16( + opus_int16 *data_out, + const opus_int16 *data_in, + opus_int32 gain_Q16, /* I Gain in Q16 */ + const opus_int dataSize /* I Length */ +) +{ + opus_int i; + opus_int32 tmp32; + + for( i = 0; i < dataSize; i++ ) { + tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] ); + data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 ); + } +} + +/* Multiply a vector by a constant */ +void silk_scale_vector32_Q26_lshift_18( + opus_int32 *data1, /* I/O Q0/Q18 */ + opus_int32 gain_Q26, /* I Q26 */ + opus_int dataSize /* I length */ +) +{ + opus_int i; + + for( i = 0; i < dataSize; i++ ) { + data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */ + } +} + +/* sum = for(i=0;i6, memory access can be reduced by half. */ +opus_int32 silk_inner_prod_aligned( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int len, /* I vector lengths */ + int arch /* I Run-time architecture */ +) +{ +#ifdef FIXED_POINT + return celt_inner_prod(inVec1, inVec2, len, arch); +#else + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +#endif +} + +opus_int64 silk_inner_prod16_aligned_64_c( + const opus_int16 *inVec1, /* I input vector 1 */ + const opus_int16 *inVec2, /* I input vector 2 */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int64 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] ); + } + return sum; +} diff --git a/src/libopus/silk/fixed/vector_ops_FIX.lo b/src/libopus/silk/fixed/vector_ops_FIX.lo new file mode 100644 index 00000000..1e7ba8fc --- /dev/null +++ b/src/libopus/silk/fixed/vector_ops_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/vector_ops_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/vector_ops_FIX.o' + +# Name of the non-PIC object +non_pic_object='vector_ops_FIX.o' + diff --git a/src/libopus/silk/fixed/vector_ops_FIX.o b/src/libopus/silk/fixed/vector_ops_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..bc0f42d662f6092fcc1b02fa25a998aea832e9c1 GIT binary patch literal 10680 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 RDrE1QqD+2~vs8j^|6lADqrU(E literal 0 HcmV?d00001 diff --git a/src/libopus/silk/fixed/warped_autocorrelation_FIX.c b/src/libopus/silk/fixed/warped_autocorrelation_FIX.c new file mode 100644 index 00000000..7ef3a7ef --- /dev/null +++ b/src/libopus/silk/fixed/warped_autocorrelation_FIX.c @@ -0,0 +1,92 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../../config.h" +//#endif + +#include "main_FIX.h" + +#if defined(MIPSr1_ASM) +#include "mips/warped_autocorrelation_FIX_mipsr1.h" +#endif + + +/* Autocorrelations for a warped frequency axis */ +#ifndef OVERRIDE_silk_warped_autocorrelation_FIX_c +void silk_warped_autocorrelation_FIX_c( + opus_int32 *corr, /* O Result [order + 1] */ + opus_int *scale, /* O Scaling of the correlation vector */ + const opus_int16 *input, /* I Input data to correlate */ + const opus_int warping_Q16, /* I Warping coefficient */ + const opus_int length, /* I Length of input */ + const opus_int order /* I Correlation order (even) */ +) +{ + opus_int n, i, lsh; + opus_int32 tmp1_QS, tmp2_QS; + opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + + /* Order must be even */ + celt_assert( ( order & 1 ) == 0 ); + silk_assert( 2 * QS - QC >= 0 ); + + /* Loop over samples */ + for( n = 0; n < length; n++ ) { + tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS ); + /* Loop over allpass sections */ + for( i = 0; i < order; i += 2 ) { + /* Output of allpass section */ + tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 ); + state_QS[ i ] = tmp1_QS; + corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + /* Output of allpass section */ + tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 ); + state_QS[ i + 1 ] = tmp2_QS; + corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + state_QS[ order ] = tmp1_QS; + corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC ); + } + + lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35; + lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC ); + *scale = -( QC + lsh ); + silk_assert( *scale >= -30 && *scale <= 12 ); + if( lsh >= 0 ) { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) ); + } + } else { + for( i = 0; i < order + 1; i++ ) { + corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) ); + } + } + silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ +} +#endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */ diff --git a/src/libopus/silk/fixed/warped_autocorrelation_FIX.lo b/src/libopus/silk/fixed/warped_autocorrelation_FIX.lo new file mode 100644 index 00000000..2e032966 --- /dev/null +++ b/src/libopus/silk/fixed/warped_autocorrelation_FIX.lo @@ -0,0 +1,12 @@ +# silk/fixed/warped_autocorrelation_FIX.lo - a libtool object file +# Generated by libtool (GNU libtool) 2.4.6 +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object='.libs/warped_autocorrelation_FIX.o' + +# Name of the non-PIC object +non_pic_object='warped_autocorrelation_FIX.o' + diff --git a/src/libopus/silk/fixed/warped_autocorrelation_FIX.o b/src/libopus/silk/fixed/warped_autocorrelation_FIX.o new file mode 100644 index 0000000000000000000000000000000000000000..500bd7e1e785c68daa27d3ec6035dc987c4821d8 GIT binary patch literal 15936 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 double_step_size_threshold ) { + ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 ); + } + + ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT ); + + /* Accumulate deltas */ + if( ind[ k ] > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold; + *prev_ind = silk_min_int( *prev_ind, N_LEVELS_QGAIN - 1 ); + } else { + *prev_ind += ind[ k ]; + } + + /* Shift to make non-negative */ + ind[ k ] -= MIN_DELTA_GAIN_QUANT; + } + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k, ind_tmp, double_step_size_threshold; + + for( k = 0; k < nb_subfr; k++ ) { + if( k == 0 && conditional == 0 ) { + /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */ + *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 ); + } else { + /* Delta index */ + ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT; + + /* Accumulate deltas */ + double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind; + if( ind_tmp > double_step_size_threshold ) { + *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold; + } else { + *prev_ind += ind_tmp; + } + } + *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 ); + + /* Scale and convert to linear scale */ + gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */ + } +} + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +) +{ + opus_int k; + opus_int32 gainsID; + + gainsID = 0; + for( k = 0; k < nb_subfr; k++ ) { + gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 ); + } + + return gainsID; +} diff --git a/src/libopus/silk/init_decoder.c b/src/libopus/silk/init_decoder.c new file mode 100644 index 00000000..9d72341e --- /dev/null +++ b/src/libopus/silk/init_decoder.c @@ -0,0 +1,57 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/************************/ +/* Init Decoder State */ +/************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +) +{ + /* Clear the entire encoder state, except anything copied */ + silk_memset( psDec, 0, sizeof( silk_decoder_state ) ); + + /* Used to deactivate LSF interpolation */ + psDec->first_frame_after_reset = 1; + psDec->prev_gain_Q16 = 65536; + psDec->arch = opus_select_arch(); + + /* Reset CNG state */ + silk_CNG_Reset( psDec ); + + /* Reset PLC state */ + silk_PLC_Reset( psDec ); + + return(0); +} + diff --git a/src/libopus/silk/init_encoder.c b/src/libopus/silk/init_encoder.c new file mode 100644 index 00000000..2ffad48f --- /dev/null +++ b/src/libopus/silk/init_encoder.c @@ -0,0 +1,64 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#ifdef FIXED_POINT +#include "fixed/main_FIX.h" +#else +#include "main_FLP.h" +#endif +#include "tuning_parameters.h" +#include "../celt/cpu_support.h" + +/*********************************/ +/* Initialize Silk Encoder state */ +/*********************************/ +opus_int silk_init_encoder( + silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */ + int arch /* I Run-time architecture */ +) +{ + opus_int ret = 0; + + /* Clear the entire encoder state */ + silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) ); + + psEnc->sCmn.arch = arch; + + psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 ); + psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15; + + /* Used to deactivate LSF interpolation, pitch prediction */ + psEnc->sCmn.first_frame_after_reset = 1; + + /* Initialize Silk VAD */ + ret += silk_VAD_Init( &psEnc->sCmn.sVAD ); + + return ret; +} diff --git a/src/libopus/silk/inner_prod_aligned.c b/src/libopus/silk/inner_prod_aligned.c new file mode 100644 index 00000000..cdaeaf85 --- /dev/null +++ b/src/libopus/silk/inner_prod_aligned.c @@ -0,0 +1,47 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +opus_int32 silk_inner_prod_aligned_scale( + const opus_int16 *const inVec1, /* I input vector 1 */ + const opus_int16 *const inVec2, /* I input vector 2 */ + const opus_int scale, /* I number of bits to shift */ + const opus_int len /* I vector lengths */ +) +{ + opus_int i; + opus_int32 sum = 0; + for( i = 0; i < len; i++ ) { + sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale ); + } + return sum; +} diff --git a/src/libopus/silk/interpolate.c b/src/libopus/silk/interpolate.c new file mode 100644 index 00000000..6be988f9 --- /dev/null +++ b/src/libopus/silk/interpolate.c @@ -0,0 +1,51 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +) +{ + opus_int i; + + celt_assert( ifact_Q2 >= 0 ); + celt_assert( ifact_Q2 <= 4 ); + + for( i = 0; i < d; i++ ) { + xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 ); + } +} diff --git a/src/libopus/silk/lin2log.c b/src/libopus/silk/lin2log.c new file mode 100644 index 00000000..87513677 --- /dev/null +++ b/src/libopus/silk/lin2log.c @@ -0,0 +1,46 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */ +/* Convert input to a log scale */ +opus_int32 silk_lin2log( + const opus_int32 inLin /* I input in linear scale */ +) +{ + opus_int32 lz, frac_Q7; + + silk_CLZ_FRAC( inLin, &lz, &frac_Q7 ); + + /* Piece-wise parabolic approximation */ + return silk_ADD_LSHIFT32( silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 ), 31 - lz, 7 ); +} + diff --git a/src/libopus/silk/log2lin.c b/src/libopus/silk/log2lin.c new file mode 100644 index 00000000..ea847bfb --- /dev/null +++ b/src/libopus/silk/log2lin.c @@ -0,0 +1,58 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +/* Approximation of 2^() (very close inverse of silk_lin2log()) */ +/* Convert input to a linear scale */ +opus_int32 silk_log2lin( + const opus_int32 inLog_Q7 /* I input on log scale */ +) +{ + opus_int32 out, frac_Q7; + + if( inLog_Q7 < 0 ) { + return 0; + } else if ( inLog_Q7 >= 3967 ) { + return silk_int32_MAX; + } + + out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) ); + frac_Q7 = inLog_Q7 & 0x7F; + if( inLog_Q7 < 2048 ) { + /* Piece-wise parabolic approximation */ + out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 ); + } else { + /* Piece-wise parabolic approximation */ + out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ); + } + return out; +} diff --git a/src/libopus/silk/macros.h b/src/libopus/silk/macros.h new file mode 100644 index 00000000..22022f9b --- /dev/null +++ b/src/libopus/silk/macros.h @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MACROS_H +#define SILK_MACROS_H + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "../opus_types.h" +#include "../opus_defines.h" +#include "../celt/arch.h" + +/* This is an OPUS_INLINE header file for general platform. */ + +/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMULWB(a32, b32) ((opus_int32)(((a32) * (opus_int64)((opus_int16)(b32))) >> 16)) +#else +#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16)) +#endif + +/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */ +#if OPUS_FAST_INT64 +#define silk_SMLAWB(a32, b32, c32) ((opus_int32)((a32) + (((b32) * (opus_int64)((opus_int16)(c32))) >> 16))) +#else +#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16))) +#endif + +/* (a32 * (b32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWT(a32, b32) ((opus_int32)(((a32) * (opus_int64)((b32) >> 16)) >> 16)) +#else +#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16)) +#endif + +/* a32 + (b32 * (c32 >> 16)) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMLAWT(a32, b32, c32) ((opus_int32)((a32) + (((b32) * ((opus_int64)(c32) >> 16)) >> 16))) +#else +#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16)) +#endif + +/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */ +#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32))) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */ +#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))) + +/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */ +#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16)) + +/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */ +#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16)) + +/* a64 + (b32 * c32) */ +#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32)))) + +/* (a32 * b32) >> 16 */ +#if OPUS_FAST_INT64 +#define silk_SMULWW(a32, b32) ((opus_int32)(((opus_int64)(a32) * (b32)) >> 16)) +#else +#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)) +#endif + +/* a32 + ((b32 * c32) >> 16) */ +#if OPUS_FAST_INT64 +#define silk_SMLAWW(a32, b32, c32) ((opus_int32)((a32) + (((opus_int64)(b32) * (c32)) >> 16))) +#else +#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16)) +#endif + +/* add/subtract with output saturated */ +#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \ + ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \ + ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) ) + +#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \ + (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \ + ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) ) + +#if defined(MIPSr1_ASM) +#include "mips/macros_mipsr1.h" +#endif + +#include "../celt/ecintrin.h" +#ifndef OVERRIDE_silk_CLZ16 +static OPUS_INLINE opus_int32 silk_CLZ16(opus_int16 in16) +{ + return 32 - EC_ILOG(in16<<16|0x8000); +} +#endif + +#ifndef OVERRIDE_silk_CLZ32 +static OPUS_INLINE opus_int32 silk_CLZ32(opus_int32 in32) +{ + return in32 ? 32 - EC_ILOG(in32) : 32; +} +#endif + +/* Row based */ +#define matrix_ptr(Matrix_base_adr, row, column, N) \ + (*((Matrix_base_adr) + ((row)*(N)+(column)))) +#define matrix_adr(Matrix_base_adr, row, column, N) \ + ((Matrix_base_adr) + ((row)*(N)+(column))) + +/* Column based */ +#ifndef matrix_c_ptr +# define matrix_c_ptr(Matrix_base_adr, row, column, M) \ + (*((Matrix_base_adr) + ((row)+(M)*(column)))) +#endif + +#ifdef OPUS_ARM_INLINE_ASM +#include "arm/macros_armv4.h" +#endif + +#ifdef OPUS_ARM_INLINE_EDSP +#include "arm/macros_armv5e.h" +#endif + +#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR +#include "arm/macros_arm64.h" +#endif + +#endif /* SILK_MACROS_H */ + diff --git a/src/libopus/silk/main.h b/src/libopus/silk/main.h new file mode 100644 index 00000000..8d9f560c --- /dev/null +++ b/src/libopus/silk/main.h @@ -0,0 +1,476 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_MAIN_H +#define SILK_MAIN_H + +#include "SigProc_FIX.h" +#include "define.h" +#include "structs.h" +#include "tables.h" +#include "PLC.h" +#include "control.h" +#include "debug.h" +#include "../celt/entenc.h" +#include "../celt/entdec.h" + +#if defined(OPUS_X86_MAY_HAVE_SSE4_1) +#include "x86/main_sse.h" +#endif + +#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)) +#include "arm/NSQ_del_dec_arm.h" +#endif + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +); + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +); + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +); + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +); + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +); + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +); + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +); + +/* Encodes signs of excitation */ +void silk_encode_signs( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + const opus_int8 pulses[], /* I pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Decodes signs of excitation */ +void silk_decode_signs( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* I/O pulse signal */ + opus_int length, /* I length of input */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I Quantization offset type */ + const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */ +); + +/* Check encoder control struct */ +opus_int check_control_input( + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control internal sampling rate */ +opus_int silk_control_audio_bandwidth( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + silk_EncControlStruct *encControl /* I Control structure */ +); + +/* Control SNR of redidual quantizer */ +opus_int silk_control_SNR( + silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */ + opus_int32 TargetRate_bps /* I Target max bitrate (bps) */ +); + +/***************/ +/* Shell coder */ +/***************/ + +/* Encode quantization indices of excitation */ +void silk_encode_pulses( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int signalType, /* I Signal type */ + const opus_int quantOffsetType, /* I quantOffsetType */ + opus_int8 pulses[], /* I quantization indices */ + const opus_int frame_length /* I Frame length */ +); + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +); + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +); + +/* Gain scalar quantization with hysteresis, uniform on log scale */ +void silk_gains_quant( + opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */ + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Gains scalar dequantization, uniform on log scale */ +void silk_gains_dequant( + opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + opus_int8 *prev_ind, /* I/O last index in previous frame */ + const opus_int conditional, /* I first gain is delta coded if 1 */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Compute unique identifier of gain indices vector */ +opus_int32 silk_gains_ID( /* O returns unique identifier of gains */ + const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */ + const opus_int nb_subfr /* I number of subframes */ +); + +/* Interpolate two vectors */ +void silk_interpolate( + opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */ + const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */ + const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */ + const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */ + const opus_int d /* I number of parameters */ +); + +/* LTP tap quantizer */ +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_gain_dB_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +); + +/* Entropy constrained matrix-weighted VQ, for a single input data vector */ +void silk_VQ_WMat_EC_c( + opus_int8 *ind, /* O index of best codebook vector */ + opus_int32 *res_nrg_Q15, /* O best residual energy */ + opus_int32 *rate_dist_Q8, /* O best total bitrate */ + opus_int *gain_Q7, /* O sum of absolute LTP coefficients */ + const opus_int32 *XX_Q17, /* I correlation matrix */ + const opus_int32 *xX_Q17, /* I correlation vector */ + const opus_int8 *cb_Q7, /* I codebook */ + const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */ + const opus_uint8 *cl_Q5, /* I code length for each codebook vector */ + const opus_int subfr_len, /* I number of samples per subframe */ + const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + const opus_int L /* I number of vectors in codebook */ +); + +#if !defined(OVERRIDE_silk_VQ_WMat_EC) +#define silk_VQ_WMat_EC(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L, arch) \ + ((void)(arch),silk_VQ_WMat_EC_c(ind, res_nrg_Q15, rate_dist_Q8, gain_Q7, XX_Q17, xX_Q17, cb_Q7, cb_gain_Q7, cl_Q5, subfr_len, max_gain_Q7, L)) +#endif + +/************************************/ +/* Noise shaping quantization (NSQ) */ +/************************************/ + +void silk_NSQ_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ) +#define silk_NSQ(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/* Noise shaping using delayed decision */ +void silk_NSQ_del_dec_c( + const silk_encoder_state *psEncC, /* I Encoder State */ + silk_nsq_state *NSQ, /* I/O NSQ state */ + SideInfoIndices *psIndices, /* I/O Quantization Indices */ + const opus_int16 x16[], /* I Input */ + opus_int8 pulses[], /* O Quantized pulse signal */ + const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */ + const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */ + const opus_int16 AR_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */ + const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */ + const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */ + const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */ + const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */ + const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */ + const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */ + const opus_int LTP_scale_Q14 /* I LTP state scaling */ +); + +#if !defined(OVERRIDE_silk_NSQ_del_dec) +#define silk_NSQ_del_dec(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14, arch) \ + ((void)(arch),silk_NSQ_del_dec_c(psEncC, NSQ, psIndices, x16, pulses, PredCoef_Q12, LTPCoef_Q14, AR_Q13, \ + HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, pitchL, Lambda_Q10, LTP_scale_Q14)) +#endif + +/************/ +/* Silk VAD */ +/************/ +/* Initialize the Silk VAD */ +opus_int silk_VAD_Init( /* O Return value, 0 if success */ + silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */ +); + +/* Get speech activity level in Q8 */ +opus_int silk_VAD_GetSA_Q8_c( /* O Return value, 0 if success */ + silk_encoder_state *psEncC, /* I/O Encoder state */ + const opus_int16 pIn[] /* I PCM input */ +); + +#if !defined(OVERRIDE_silk_VAD_GetSA_Q8) +#define silk_VAD_GetSA_Q8(psEnC, pIn, arch) ((void)(arch),silk_VAD_GetSA_Q8_c(psEnC, pIn)) +#endif + +/* Low-pass filter with variable cutoff frequency based on */ +/* piece-wise linear interpolation between elliptic filters */ +/* Start by setting transition_frame_no = 1; */ +void silk_LP_variable_cutoff( + silk_LP_state *psLP, /* I/O LP filter state */ + opus_int16 *frame, /* I/O Low-pass filtered output signal */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* NLSF Quantizer */ +/******************/ +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +); + +opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */ + const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */ + const opus_int nSurvivors, /* I Max survivors after first stage */ + const opus_int signalType /* I Signal type: 0/1/2 */ +); + +/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */ +void silk_NLSF_VQ( + opus_int32 err_Q26[], /* O Quantization errors [K] */ + const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */ + const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */ + const opus_int16 pWght_Q9[], /* I Codebook weights [K*LPC_order] */ + const opus_int K, /* I Number of codebook vectors */ + const opus_int LPC_order /* I Number of LPCs */ +); + +/* Delayed-decision quantizer for NLSF residuals */ +opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */ + opus_int8 indices[], /* O Quantization indices [ order ] */ + const opus_int16 x_Q10[], /* I Input [ order ] */ + const opus_int16 w_Q5[], /* I Weights [ order ] */ + const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */ + const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */ + const opus_uint8 ec_rates_Q5[], /* I Rates [] */ + const opus_int quant_step_size_Q16, /* I Quantization step size */ + const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */ + const opus_int32 mu_Q20, /* I R/D tradeoff */ + const opus_int16 order /* I Number of input values */ +); + +/* Unpack predictor values and indices for entropy coding tables */ +void silk_NLSF_unpack( + opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */ + opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */ + const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */ + const opus_int CB1_index /* I Index of vector in first LSF codebook */ +); + +/***********************/ +/* NLSF vector decoder */ +/***********************/ +void silk_NLSF_decode( + opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */ + opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */ + const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */ +); + +/****************************************************/ +/* Decoder Functions */ +/****************************************************/ +opus_int silk_init_decoder( + silk_decoder_state *psDec /* I/O Decoder state pointer */ +); + +/* Set decoder sampling rate */ +opus_int silk_decoder_set_fs( + silk_decoder_state *psDec, /* I/O Decoder state pointer */ + opus_int fs_kHz, /* I Sampling frequency (kHz) */ + opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */ +); + +/****************/ +/* Decode frame */ +/****************/ +opus_int silk_decode_frame( + silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pOut[], /* O Pointer to output speech frame */ + opus_int32 *pN, /* O Pointer to size of output frame */ + opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */ + opus_int condCoding, /* I The type of conditional coding to use */ + int arch /* I Run-time architecture */ +); + +/* Decode indices from bitstream */ +void silk_decode_indices( + silk_decoder_state *psDec, /* I/O State */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Decode parameters from payload */ +void silk_decode_parameters( + silk_decoder_state *psDec, /* I/O State */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +/* Core decoder. Performs inverse NSQ operation LTP + LPC */ +void silk_decode_core( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I Decoder control */ + opus_int16 xq[], /* O Decoded speech */ + const opus_int16 pulses[ MAX_FRAME_LENGTH ], /* I Pulse signal */ + int arch /* I Run-time architecture */ +); + +/* Decode quantization indices of excitation (Shell coding) */ +void silk_decode_pulses( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int16 pulses[], /* O Excitation signal */ + const opus_int signalType, /* I Sigtype */ + const opus_int quantOffsetType, /* I quantOffsetType */ + const opus_int frame_length /* I Frame length */ +); + +/******************/ +/* CNG */ +/******************/ + +/* Reset CNG */ +void silk_CNG_Reset( + silk_decoder_state *psDec /* I/O Decoder state */ +); + +/* Updates CNG estimate, and applies the CNG when packet was lost */ +void silk_CNG( + silk_decoder_state *psDec, /* I/O Decoder state */ + silk_decoder_control *psDecCtrl, /* I/O Decoder control */ + opus_int16 frame[], /* I/O Signal */ + opus_int length /* I Length of residual */ +); + +/* Encoding of various parameters */ +void silk_encode_indices( + silk_encoder_state *psEncC, /* I/O Encoder state */ + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int FrameIndex, /* I Frame number */ + opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */ + opus_int condCoding /* I The type of conditional coding to use */ +); + +#endif diff --git a/src/libopus/silk/pitch_est_defines.h b/src/libopus/silk/pitch_est_defines.h new file mode 100644 index 00000000..e1e4b5d7 --- /dev/null +++ b/src/libopus/silk/pitch_est_defines.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_PE_DEFINES_H +#define SILK_PE_DEFINES_H + +#include "SigProc_FIX.h" + +/********************************************************/ +/* Definitions for pitch estimator */ +/********************************************************/ + +#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */ + +#define PE_MAX_NB_SUBFR 4 +#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */ + +#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS ) + +#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS ) +#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ ) +#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 ) +#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 ) + +#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */ +#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */ +#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ ) +#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ ) + +#define PE_D_SRCH_LENGTH 24 + +#define PE_NB_STAGE3_LAGS 5 + +#define PE_NB_CBKS_STAGE2 3 +#define PE_NB_CBKS_STAGE2_EXT 11 + +#define PE_NB_CBKS_STAGE3_MAX 34 +#define PE_NB_CBKS_STAGE3_MID 24 +#define PE_NB_CBKS_STAGE3_MIN 16 + +#define PE_NB_CBKS_STAGE3_10MS 12 +#define PE_NB_CBKS_STAGE2_10MS 3 + +#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */ +#define PE_FLATCONTOUR_BIAS 0.05f + +#define SILK_PE_MIN_COMPLEX 0 +#define SILK_PE_MID_COMPLEX 1 +#define SILK_PE_MAX_COMPLEX 2 + +/* Tables for 20 ms frames */ +extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ]; +extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ]; +extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ]; +extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ]; + +/* Tables for 10 ms frames */ +extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ]; +extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ]; +extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ]; + +#endif + diff --git a/src/libopus/silk/pitch_est_tables.c b/src/libopus/silk/pitch_est_tables.c new file mode 100644 index 00000000..660c3d6a --- /dev/null +++ b/src/libopus/silk/pitch_est_tables.c @@ -0,0 +1,99 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "typedef.h" +#include "pitch_est_defines.h" + +const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] = +{ + {0, 1, 0}, + {0, 0, 1} +}; + +const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] = +{ + { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3}, + { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3} +}; + +const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] = +{ + {-3, 7}, + {-2, 7} +}; + +const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] = +{ + {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1}, + {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0}, + {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0}, + {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1} +}; + +const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] = +{ + {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9}, + {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3}, + {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3}, + {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9} +}; + +const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] = +{ + /* Lags to search for low number of stage3 cbks */ + { + {-5,8}, + {-1,6}, + {-1,6}, + {-4,10} + }, + /* Lags to search for middle number of stage3 cbks */ + { + {-6,10}, + {-2,6}, + {-1,6}, + {-5,10} + }, + /* Lags to search for max number of stage3 cbks */ + { + {-9,12}, + {-3,7}, + {-2,7}, + {-7,13} + } +}; + +const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] = +{ + PE_NB_CBKS_STAGE3_MIN, + PE_NB_CBKS_STAGE3_MID, + PE_NB_CBKS_STAGE3_MAX +}; diff --git a/src/libopus/silk/process_NLSFs.c b/src/libopus/silk/process_NLSFs.c new file mode 100644 index 00000000..a9b606af --- /dev/null +++ b/src/libopus/silk/process_NLSFs.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Limit, stabilize, convert and quantize NLSFs */ +void silk_process_NLSFs( + silk_encoder_state *psEncC, /* I/O Encoder state */ + opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */ + opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */ + const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */ +) +{ + opus_int i, doInterpolate; + opus_int NLSF_mu_Q20; + opus_int16 i_sqr_Q15; + opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ]; + opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ]; + + silk_assert( psEncC->speech_activity_Q8 >= 0 ); + silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) ); + celt_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) ); + + /***********************/ + /* Calculate mu values */ + /***********************/ + /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */ + NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 ); + if( psEncC->nb_subfr == 2 ) { + /* Multiply by 1.5 for 10 ms packets */ + NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 ); + } + + celt_assert( NLSF_mu_Q20 > 0 ); + silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) ); + + /* Calculate NLSF weights */ + silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights for interpolated NLSFs */ + doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 ); + if( doInterpolate ) { + /* Calculate the interpolated NLSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Calculate first half NLSF weights for the interpolated NLSFs */ + silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder ); + + /* Update NLSF weights with contribution from first half */ + i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 ); + for( i = 0; i < psEncC->predictLPCOrder; i++ ) { + pNLSFW_QW[ i ] = silk_ADD16( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), silk_RSHIFT( + silk_SMULBB( pNLSFW0_temp_QW[ i ], i_sqr_Q15 ), 16) ); + silk_assert( pNLSFW_QW[ i ] >= 1 ); + } + } + + silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW, + NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType ); + + /* Convert quantized NLSFs back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + if( doInterpolate ) { + /* Calculate the interpolated, quantized LSF vector for the first half */ + silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15, + psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder ); + + /* Convert back to LPC coefficients */ + silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder, psEncC->arch ); + + } else { + /* Copy LPC coefficients for first half from second half */ + celt_assert( psEncC->predictLPCOrder <= MAX_LPC_ORDER ); + silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) ); + } +} diff --git a/src/libopus/silk/quant_LTP_gains.c b/src/libopus/silk/quant_LTP_gains.c new file mode 100644 index 00000000..f8dc4c3a --- /dev/null +++ b/src/libopus/silk/quant_LTP_gains.c @@ -0,0 +1,132 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "tuning_parameters.h" + +void silk_quant_LTP_gains( + opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O Quantized LTP gains */ + opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */ + opus_int8 *periodicity_index, /* O Periodicity Index */ + opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */ + opus_int *pred_gain_dB_Q7, /* O LTP prediction gain */ + const opus_int32 XX_Q17[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Correlation matrix in Q18 */ + const opus_int32 xX_Q17[ MAX_NB_SUBFR*LTP_ORDER ], /* I Correlation vector in Q18 */ + const opus_int subfr_len, /* I Number of samples per subframe */ + const opus_int nb_subfr, /* I Number of subframes */ + int arch /* I Run-time architecture */ +) +{ + opus_int j, k, cbk_size; + opus_int8 temp_idx[ MAX_NB_SUBFR ]; + const opus_uint8 *cl_ptr_Q5; + const opus_int8 *cbk_ptr_Q7; + const opus_uint8 *cbk_gain_ptr_Q7; + const opus_int32 *XX_Q17_ptr, *xX_Q17_ptr; + opus_int32 res_nrg_Q15_subfr, res_nrg_Q15, rate_dist_Q7_subfr, rate_dist_Q7, min_rate_dist_Q7; + opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7; + opus_int gain_Q7; + + /***************************************************/ + /* iterate over different codebooks with different */ + /* rates/distortions, and choose best */ + /***************************************************/ + min_rate_dist_Q7 = silk_int32_MAX; + best_sum_log_gain_Q7 = 0; + for( k = 0; k < 3; k++ ) { + /* Safety margin for pitch gain control, to take into account factors + such as state rescaling/rewhitening. */ + opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 ); + + cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ]; + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ]; + cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ]; + cbk_size = silk_LTP_vq_sizes[ k ]; + + /* Set up pointers to first subframe */ + XX_Q17_ptr = XX_Q17; + xX_Q17_ptr = xX_Q17; + + res_nrg_Q15 = 0; + rate_dist_Q7 = 0; + sum_log_gain_tmp_Q7 = *sum_log_gain_Q7; + for( j = 0; j < nb_subfr; j++ ) { + max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 ) + + SILK_FIX_CONST( 7, 7 ) ) - gain_safety; + silk_VQ_WMat_EC( + &temp_idx[ j ], /* O index of best codebook vector */ + &res_nrg_Q15_subfr, /* O residual energy */ + &rate_dist_Q7_subfr, /* O best weighted quantization error + mu * rate */ + &gain_Q7, /* O sum of absolute LTP coefficients */ + XX_Q17_ptr, /* I correlation matrix */ + xX_Q17_ptr, /* I correlation vector */ + cbk_ptr_Q7, /* I codebook */ + cbk_gain_ptr_Q7, /* I codebook effective gains */ + cl_ptr_Q5, /* I code length for each codebook vector */ + subfr_len, /* I number of samples per subframe */ + max_gain_Q7, /* I maximum sum of absolute LTP coefficients */ + cbk_size, /* I number of vectors in codebook */ + arch /* I Run-time architecture */ + ); + + res_nrg_Q15 = silk_ADD_POS_SAT32( res_nrg_Q15, res_nrg_Q15_subfr ); + rate_dist_Q7 = silk_ADD_POS_SAT32( rate_dist_Q7, rate_dist_Q7_subfr ); + sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7 + + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 )); + + XX_Q17_ptr += LTP_ORDER * LTP_ORDER; + xX_Q17_ptr += LTP_ORDER; + } + + if( rate_dist_Q7 <= min_rate_dist_Q7 ) { + min_rate_dist_Q7 = rate_dist_Q7; + *periodicity_index = (opus_int8)k; + silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) ); + best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7; + } + } + + cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ]; + for( j = 0; j < nb_subfr; j++ ) { + for( k = 0; k < LTP_ORDER; k++ ) { + B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 ); + } + } + + if( nb_subfr == 2 ) { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 1 ); + } else { + res_nrg_Q15 = silk_RSHIFT32( res_nrg_Q15, 2 ); + } + + *sum_log_gain_Q7 = best_sum_log_gain_Q7; + *pred_gain_dB_Q7 = (opus_int)silk_SMULBB( -3, silk_lin2log( res_nrg_Q15 ) - ( 15 << 7 ) ); +} diff --git a/src/libopus/silk/resampler.c b/src/libopus/silk/resampler.c new file mode 100644 index 00000000..a2f05b0b --- /dev/null +++ b/src/libopus/silk/resampler.c @@ -0,0 +1,215 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +/* + * Matrix of resampling methods used: + * Fs_out (kHz) + * 8 12 16 24 48 + * + * 8 C UF U UF UF + * 12 AF C UF U UF + * Fs_in (kHz) 16 D AF C UF UF + * 24 AF D AF C U + * 48 AF AF AF D C + * + * C -> Copy (no resampling) + * D -> Allpass-based 2x downsampling + * U -> Allpass-based 2x upsampling + * UF -> Allpass-based 2x upsampling followed by FIR interpolation + * AF -> AR2 filter followed by FIR interpolation + */ + +#include "resampler_private.h" + +/* Tables with delay compensation values to equalize total delay for different modes */ +static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = { +/* in \ out 8 12 16 */ +/* 8 */ { 6, 0, 3 }, +/* 12 */ { 0, 7, 3 }, +/* 16 */ { 0, 1, 10 }, +/* 24 */ { 0, 2, 6 }, +/* 48 */ { 18, 10, 12 } +}; + +static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = { +/* in \ out 8 12 16 24 48 */ +/* 8 */ { 4, 0, 2, 0, 0 }, +/* 12 */ { 0, 9, 4, 7, 4 }, +/* 16 */ { 0, 3, 12, 7, 7 } +}; + +/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */ +#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 ) + +#define USE_silk_resampler_copy (0) +#define USE_silk_resampler_private_up2_HQ_wrapper (1) +#define USE_silk_resampler_private_IIR_FIR (2) +#define USE_silk_resampler_private_down_FIR (3) + +/* Initialize/reset the resampler state for a given pair of input/output sampling rates */ +opus_int silk_resampler_init( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */ + opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */ + opus_int forEnc /* I If 1: encoder; if 0: decoder */ +) +{ + opus_int up2x; + + /* Clear state */ + silk_memset( S, 0, sizeof( silk_resampler_state_struct ) ); + + /* Input checking */ + if( forEnc ) { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } else { + if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 ) || + ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) { + celt_assert( 0 ); + return -1; + } + S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ]; + } + + S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 ); + S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 ); + + /* Number of samples processed per batch */ + S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS; + + /* Find resampler with the right sampling ratio */ + up2x = 0; + if( Fs_Hz_out > Fs_Hz_in ) { + /* Upsample */ + if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */ + /* Special case: directly use 2x upsampler */ + S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper; + } else { + /* Default resampler */ + S->resampler_function = USE_silk_resampler_private_IIR_FIR; + up2x = 1; + } + } else if ( Fs_Hz_out < Fs_Hz_in ) { + /* Downsample */ + S->resampler_function = USE_silk_resampler_private_down_FIR; + if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */ + S->FIR_Fracs = 3; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_3_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */ + S->FIR_Fracs = 2; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0; + S->Coefs = silk_Resampler_2_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1; + S->Coefs = silk_Resampler_1_2_COEFS; + } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_3_COEFS; + } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_4_COEFS; + } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */ + S->FIR_Fracs = 1; + S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2; + S->Coefs = silk_Resampler_1_6_COEFS; + } else { + /* None available */ + celt_assert( 0 ); + return -1; + } + } else { + /* Input and output sampling rates are equal: copy */ + S->resampler_function = USE_silk_resampler_copy; + } + + /* Ratio of input/output samples */ + S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 ); + /* Make sure the ratio is rounded up */ + while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) { + S->invRatio_Q16++; + } + + return 0; +} + +/* Resampler: convert from one sampling rate to another */ +/* Input and output sampling rate are at most 48000 Hz */ +opus_int silk_resampler( + silk_resampler_state_struct *S, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int nSamples; + + /* Need at least 1 ms of input data */ + celt_assert( inLen >= S->Fs_in_kHz ); + /* Delay can't exceed the 1 ms of buffering */ + celt_assert( S->inputDelay <= S->Fs_in_kHz ); + + nSamples = S->Fs_in_kHz - S->inputDelay; + + /* Copy to delay buffer */ + silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) ); + + switch( S->resampler_function ) { + case USE_silk_resampler_private_up2_HQ_wrapper: + silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_IIR_FIR: + silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + case USE_silk_resampler_private_down_FIR: + silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz ); + silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz ); + break; + default: + silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) ); + silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) ); + } + + /* Copy to delay buffer */ + silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) ); + + return 0; +} diff --git a/src/libopus/silk/resampler_down2.c b/src/libopus/silk/resampler_down2.c new file mode 100644 index 00000000..bb5d0116 --- /dev/null +++ b/src/libopus/silk/resampler_down2.c @@ -0,0 +1,74 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "resampler_rom.h" + +/* Downsample by a factor 2 */ +void silk_resampler_down2( + opus_int32 *S, /* I/O State vector [ 2 ] */ + opus_int16 *out, /* O Output signal [ floor(len/2) ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 ); + opus_int32 in32, out32, Y, X; + + celt_assert( silk_resampler_down2_0 > 0 ); + celt_assert( silk_resampler_down2_1 < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len2; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 ); + + /* All-pass section for even input sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 ); + out32 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 ); + + /* All-pass section for odd input sample, and add to output of previous section */ + Y = silk_SUB32( in32, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_down2_0 ); + out32 = silk_ADD32( out32, S[ 1 ] ); + out32 = silk_ADD32( out32, X ); + S[ 1 ] = silk_ADD32( in32, X ); + + /* Add, convert back to int16 and store to output */ + out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) ); + } +} + diff --git a/src/libopus/silk/resampler_down2_3.c b/src/libopus/silk/resampler_down2_3.c new file mode 100644 index 00000000..d8ce95c6 --- /dev/null +++ b/src/libopus/silk/resampler_down2_3.c @@ -0,0 +1,103 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "../celt/stack_alloc.h" + +#define ORDER_FIR 4 + +/* Downsample by a factor 2/3, low quality */ +void silk_resampler_down2_3( + opus_int32 *S, /* I/O State vector [ 6 ] */ + opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */ + const opus_int16 *in, /* I Input signal [ inLen ] */ + opus_int32 inLen /* I Number of input samples */ +) +{ + opus_int32 nSamplesIn, counter, res_Q6; + VARDECL( opus_int32, buf ); + opus_int32 *buf_ptr; + SAVE_STACK; + + ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + while( 1 ) { + nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in, + silk_Resampler_2_3_COEFS_LQ, nSamplesIn ); + + /* Interpolate filtered signal */ + buf_ptr = buf; + counter = nSamplesIn; + while( counter > 2 ) { + /* Inner product */ + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + + buf_ptr += 3; + counter -= 3; + } + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/src/libopus/silk/resampler_private.h b/src/libopus/silk/resampler_private.h new file mode 100644 index 00000000..422a7d9d --- /dev/null +++ b/src/libopus/silk/resampler_private.h @@ -0,0 +1,88 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_PRIVATE_H +#define SILK_RESAMPLER_PRIVATE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "SigProc_FIX.h" +#include "resampler_structs.h" +#include "resampler_rom.h" + +/* Number of input samples to process in the inner loop */ +#define RESAMPLER_MAX_BATCH_SIZE_MS 10 +#define RESAMPLER_MAX_FS_KHZ 48 +#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ ) + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Description: Hybrid IIR/FIR polyphase implementation of resampling */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Upsample by a factor 2, high quality */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +); + +/* Second order AR filter */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +); + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_PRIVATE_H */ diff --git a/src/libopus/silk/resampler_private_AR2.c b/src/libopus/silk/resampler_private_AR2.c new file mode 100644 index 00000000..0aed3807 --- /dev/null +++ b/src/libopus/silk/resampler_private_AR2.c @@ -0,0 +1,55 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Second order AR filter with single delay elements */ +void silk_resampler_private_AR2( + opus_int32 S[], /* I/O State vector [ 2 ] */ + opus_int32 out_Q8[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + const opus_int16 A_Q14[], /* I AR coefficients, Q14 */ + opus_int32 len /* I Signal length */ +) +{ + opus_int32 k; + opus_int32 out32; + + for( k = 0; k < len; k++ ) { + out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 ); + out_Q8[ k ] = out32; + out32 = silk_LSHIFT( out32, 2 ); + S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] ); + S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] ); + } +} + diff --git a/src/libopus/silk/resampler_private_IIR_FIR.c b/src/libopus/silk/resampler_private_IIR_FIR.c new file mode 100644 index 00000000..867a15ce --- /dev/null +++ b/src/libopus/silk/resampler_private_IIR_FIR.c @@ -0,0 +1,107 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "../celt/stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL( + opus_int16 *out, + opus_int16 *buf, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q15; + opus_int16 *buf_ptr; + opus_int32 table_index; + + /* Interpolate upsampled signal and store in output array */ + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 ); + buf_ptr = &buf[ index_Q16 >> 16 ]; + + res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] ); + res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] ); + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) ); + } + return out; +} +/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */ +void silk_resampler_private_IIR_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int16, buf ); + SAVE_STACK; + + ALLOC( buf, 2 * S->batchSize + RESAMPLER_ORDER_FIR_12, opus_int16 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Upsample 2x */ + silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */ + out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 ); + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 0 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i16, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) ); + RESTORE_STACK; +} diff --git a/src/libopus/silk/resampler_private_down_FIR.c b/src/libopus/silk/resampler_private_down_FIR.c new file mode 100644 index 00000000..274284fb --- /dev/null +++ b/src/libopus/silk/resampler_private_down_FIR.c @@ -0,0 +1,194 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" +#include "../celt/stack_alloc.h" + +static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL( + opus_int16 *out, + opus_int32 *buf, + const opus_int16 *FIR_Coefs, + opus_int FIR_Order, + opus_int FIR_Fracs, + opus_int32 max_index_Q16, + opus_int32 index_increment_Q16 +) +{ + opus_int32 index_Q16, res_Q6; + opus_int32 *buf_ptr; + opus_int32 interpol_ind; + const opus_int16 *interpol_ptr; + + switch( FIR_Order ) { + case RESAMPLER_DOWN_ORDER_FIR0: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Fractional part gives interpolation coefficients */ + interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs ); + + /* Inner product */ + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ]; + res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] ); + interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ]; + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR1: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + case RESAMPLER_DOWN_ORDER_FIR2: + for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) { + /* Integer part gives pointer to buffered input */ + buf_ptr = buf + silk_RSHIFT( index_Q16, 16 ); + + /* Inner product */ + res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] ); + res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] ); + + /* Scale down, saturate and store in output array */ + *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) ); + } + break; + default: + celt_assert( 0 ); + } + return out; +} + +/* Resample with a 2nd order AR filter followed by FIR interpolation */ +void silk_resampler_private_down_FIR( + void *SS, /* I/O Resampler state */ + opus_int16 out[], /* O Output signal */ + const opus_int16 in[], /* I Input signal */ + opus_int32 inLen /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + opus_int32 nSamplesIn; + opus_int32 max_index_Q16, index_increment_Q16; + VARDECL( opus_int32, buf ); + const opus_int16 *FIR_Coefs; + SAVE_STACK; + + ALLOC( buf, S->batchSize + S->FIR_Order, opus_int32 ); + + /* Copy buffered samples to start of buffer */ + silk_memcpy( buf, S->sFIR.i32, S->FIR_Order * sizeof( opus_int32 ) ); + + FIR_Coefs = &S->Coefs[ 2 ]; + + /* Iterate over blocks of frameSizeIn input samples */ + index_increment_Q16 = S->invRatio_Q16; + while( 1 ) { + nSamplesIn = silk_min( inLen, S->batchSize ); + + /* Second-order AR filter (output in Q8) */ + silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn ); + + max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 ); + + /* Interpolate filtered signal */ + out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order, + S->FIR_Fracs, max_index_Q16, index_increment_Q16 ); + + in += nSamplesIn; + inLen -= nSamplesIn; + + if( inLen > 1 ) { + /* More iterations to do; copy last part of filtered signal to beginning of buffer */ + silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + } else { + break; + } + } + + /* Copy last part of filtered signal to the state for the next call */ + silk_memcpy( S->sFIR.i32, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) ); + RESTORE_STACK; +} diff --git a/src/libopus/silk/resampler_private_up2_HQ.c b/src/libopus/silk/resampler_private_up2_HQ.c new file mode 100644 index 00000000..f5fd6de3 --- /dev/null +++ b/src/libopus/silk/resampler_private_up2_HQ.c @@ -0,0 +1,113 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" +#include "resampler_private.h" + +/* Upsample by a factor 2, high quality */ +/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */ +/* notch filter just above Nyquist. */ +void silk_resampler_private_up2_HQ( + opus_int32 *S, /* I/O Resampler state [ 6 ] */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + opus_int32 k; + opus_int32 in32, out32_1, out32_2, Y, X; + + silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 ); + silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 ); + silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 ); + + /* Internal variables and state are in Q10 format */ + for( k = 0; k < len; k++ ) { + /* Convert to Q10 */ + in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 ); + + /* First all-pass section for even output sample */ + Y = silk_SUB32( in32, S[ 0 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] ); + out32_1 = silk_ADD32( S[ 0 ], X ); + S[ 0 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for even output sample */ + Y = silk_SUB32( out32_1, S[ 1 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] ); + out32_2 = silk_ADD32( S[ 1 ], X ); + S[ 1 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for even output sample */ + Y = silk_SUB32( out32_2, S[ 2 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] ); + out32_1 = silk_ADD32( S[ 2 ], X ); + S[ 2 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + + /* First all-pass section for odd output sample */ + Y = silk_SUB32( in32, S[ 3 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] ); + out32_1 = silk_ADD32( S[ 3 ], X ); + S[ 3 ] = silk_ADD32( in32, X ); + + /* Second all-pass section for odd output sample */ + Y = silk_SUB32( out32_1, S[ 4 ] ); + X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] ); + out32_2 = silk_ADD32( S[ 4 ], X ); + S[ 4 ] = silk_ADD32( out32_1, X ); + + /* Third all-pass section for odd output sample */ + Y = silk_SUB32( out32_2, S[ 5 ] ); + X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] ); + out32_1 = silk_ADD32( S[ 5 ], X ); + S[ 5 ] = silk_ADD32( out32_2, X ); + + /* Apply gain in Q15, convert back to int16 and store to output */ + out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) ); + } +} + +void silk_resampler_private_up2_HQ_wrapper( + void *SS, /* I/O Resampler state (unused) */ + opus_int16 *out, /* O Output signal [ 2 * len ] */ + const opus_int16 *in, /* I Input signal [ len ] */ + opus_int32 len /* I Number of input samples */ +) +{ + silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS; + silk_resampler_private_up2_HQ( S->sIIR, out, in, len ); +} diff --git a/src/libopus/silk/resampler_rom.c b/src/libopus/silk/resampler_rom.c new file mode 100644 index 00000000..a684bcd2 --- /dev/null +++ b/src/libopus/silk/resampler_rom.c @@ -0,0 +1,96 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +/* Filter coefficients for IIR/FIR polyphase resampling * + * Total size: 179 Words (358 Bytes) */ + +#include "resampler_private.h" + +/* Matlab code for the notch filter coefficients: */ +/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */ +/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */ +/* const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; */ + +/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -20694, -13867, + -49, 64, 17, -157, 353, -496, 163, 11047, 22205, + -39, 6, 91, -170, 186, 23, -896, 6336, 19928, + -19, -36, 102, -89, -24, 328, -951, 2568, 15909, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = { + -14457, -14019, + 64, 128, -122, 36, 310, -768, 584, 9267, 17733, + 12, 128, 18, -142, 288, -117, -865, 4123, 14459, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = { + 616, -14323, + -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 16102, -15162, + -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 22500, -15099, + 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = { + 27540, -15257, + 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455, +}; + +silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = { + -2797, -6507, + 4697, 10739, + 1567, 8276, +}; + +/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */ +silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = { + { 189, -600, 617, 30567 }, + { 117, -159, -1070, 29704 }, + { 52, 221, -2392, 28276 }, + { -4, 529, -3350, 26341 }, + { -48, 758, -3956, 23973 }, + { -80, 905, -4235, 21254 }, + { -99, 972, -4222, 18278 }, + { -107, 967, -3957, 15143 }, + { -103, 896, -3487, 11950 }, + { -91, 773, -2865, 8798 }, + { -71, 611, -2143, 5784 }, + { -46, 425, -1375, 2996 }, +}; diff --git a/src/libopus/silk/resampler_rom.h b/src/libopus/silk/resampler_rom.h new file mode 100644 index 00000000..490b3388 --- /dev/null +++ b/src/libopus/silk/resampler_rom.h @@ -0,0 +1,68 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_FIX_RESAMPLER_ROM_H +#define SILK_FIX_RESAMPLER_ROM_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "typedef.h" +#include "resampler_structs.h" + +#define RESAMPLER_DOWN_ORDER_FIR0 18 +#define RESAMPLER_DOWN_ORDER_FIR1 24 +#define RESAMPLER_DOWN_ORDER_FIR2 36 +#define RESAMPLER_ORDER_FIR_12 8 + +/* Tables for 2x downsampler */ +static const opus_int16 silk_resampler_down2_0 = 9872; +static const opus_int16 silk_resampler_down2_1 = 39809 - 65536; + +/* Tables for 2x upsampler, high quality */ +static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 }; +static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 }; + +/* Tables with IIR and FIR coefficients for fractional downsamplers */ +extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ]; +extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ]; +extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ]; +extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ]; + +/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */ +extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ]; + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_FIX_RESAMPLER_ROM_H */ diff --git a/src/libopus/silk/resampler_structs.h b/src/libopus/silk/resampler_structs.h new file mode 100644 index 00000000..9e9457d1 --- /dev/null +++ b/src/libopus/silk/resampler_structs.h @@ -0,0 +1,60 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_RESAMPLER_STRUCTS_H +#define SILK_RESAMPLER_STRUCTS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SILK_RESAMPLER_MAX_FIR_ORDER 36 +#define SILK_RESAMPLER_MAX_IIR_ORDER 6 + +typedef struct _silk_resampler_state_struct{ + opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */ + union{ + opus_int32 i32[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + opus_int16 i16[ SILK_RESAMPLER_MAX_FIR_ORDER ]; + } sFIR; + opus_int16 delayBuf[ 48 ]; + opus_int resampler_function; + opus_int batchSize; + opus_int32 invRatio_Q16; + opus_int FIR_Order; + opus_int FIR_Fracs; + opus_int Fs_in_kHz; + opus_int Fs_out_kHz; + opus_int inputDelay; + const opus_int16 *Coefs; +} silk_resampler_state_struct; + +#ifdef __cplusplus +} +#endif +#endif /* SILK_RESAMPLER_STRUCTS_H */ + diff --git a/src/libopus/silk/shell_coder.c b/src/libopus/silk/shell_coder.c new file mode 100644 index 00000000..d8c1d704 --- /dev/null +++ b/src/libopus/silk/shell_coder.c @@ -0,0 +1,151 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* shell coder; pulse-subframe length is hardcoded */ + +static OPUS_INLINE void combine_pulses( + opus_int *out, /* O combined pulses vector [len] */ + const opus_int *in, /* I input vector [2 * len] */ + const opus_int len /* I number of OUTPUT samples */ +) +{ + opus_int k; + for( k = 0; k < len; k++ ) { + out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ]; + } +} + +static OPUS_INLINE void encode_split( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int p_child1, /* I pulse amplitude of first child subframe */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + } +} + +static OPUS_INLINE void decode_split( + opus_int16 *p_child1, /* O pulse amplitude of first child subframe */ + opus_int16 *p_child2, /* O pulse amplitude of second child subframe */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int p, /* I pulse amplitude of current subframe */ + const opus_uint8 *shell_table /* I table of shell cdfs */ +) +{ + if( p > 0 ) { + p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 ); + p_child2[ 0 ] = p - p_child1[ 0 ]; + } else { + p_child1[ 0 ] = 0; + p_child2[ 0 ] = 0; + } +} + +/* Shell encoder, operates on one shell code frame of 16 pulses */ +void silk_shell_encoder( + ec_enc *psRangeEnc, /* I/O compressor data structure */ + const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */ +) +{ + opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + /* tree representation per pulse-subframe */ + combine_pulses( pulses1, pulses0, 8 ); + combine_pulses( pulses2, pulses1, 4 ); + combine_pulses( pulses3, pulses2, 2 ); + combine_pulses( pulses4, pulses3, 1 ); + + encode_split( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 ); + + encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 ); + + encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 ); + + encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 ); + encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 ); + encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 ); +} + + +/* Shell decoder, operates on one shell code frame of 16 pulses */ +void silk_shell_decoder( + opus_int16 *pulses0, /* O data: nonnegative pulse amplitudes */ + ec_dec *psRangeDec, /* I/O Compressor data structure */ + const opus_int pulses4 /* I number of pulses per pulse-subframe */ +) +{ + opus_int16 pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ]; + + /* this function operates on one shell code frame of 16 pulses */ + silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 ); + + decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 ); + + decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 ); + + decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 ); + + decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 ); + + decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 ); + decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 ); + decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 ); +} diff --git a/src/libopus/silk/sigm_Q15.c b/src/libopus/silk/sigm_Q15.c new file mode 100644 index 00000000..8afdcb90 --- /dev/null +++ b/src/libopus/silk/sigm_Q15.c @@ -0,0 +1,77 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif +#include + +/* Approximate sigmoid function */ + +#include "SigProc_FIX.h" + +/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */ +static const opus_int32 sigm_LUT_slope_Q10[ 6 ] PROGMEM = { + 237, 153, 73, 30, 12, 7 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */ +static const opus_int32 sigm_LUT_pos_Q15[ 6 ] PROGMEM = { + 16384, 23955, 28861, 31213, 32178, 32548 +}; +/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */ +static const opus_int32 sigm_LUT_neg_Q15[ 6 ] PROGMEM = { + 16384, 8812, 3906, 1554, 589, 219 +}; + +opus_int silk_sigm_Q15( + opus_int in_Q5 /* I */ +) +{ + opus_int ind; + + if( in_Q5 < 0 ) { + /* Negative input */ + in_Q5 = -in_Q5; + if( in_Q5 >= 6 * 32 ) { + return 0; /* Clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } else { + /* Positive input */ + if( in_Q5 >= 6 * 32 ) { + return 32767; /* clip */ + } else { + /* Linear interpolation of look up table */ + ind = silk_RSHIFT( in_Q5, 5 ); + return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) ); + } + } +} + diff --git a/src/libopus/silk/sort.c b/src/libopus/silk/sort.c new file mode 100644 index 00000000..2aeea6ef --- /dev/null +++ b/src/libopus/silk/sort.c @@ -0,0 +1,154 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +/* Insertion sort (fast for already almost sorted arrays): */ +/* Best case: O(n) for an already sorted array */ +/* Worst case: O(n^2) for an inversely sorted array */ +/* */ +/* Shell short: https://en.wikipedia.org/wiki/Shell_sort */ + +#include "SigProc_FIX.h" + +void silk_insertion_sort_increasing( + opus_int32 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int32 value; + opus_int i, j; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value < a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} + +#ifdef FIXED_POINT +/* This function is only used by the fixed-point build */ +void silk_insertion_sort_decreasing_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + opus_int *idx, /* O Index vector for the sorted elements */ + const opus_int L, /* I Vector length */ + const opus_int K /* I Number of correctly sorted positions */ +) +{ + opus_int i, j; + opus_int value; + + /* Safety checks */ + celt_assert( K > 0 ); + celt_assert( L > 0 ); + celt_assert( L >= K ); + + /* Write start indices in index vector */ + for( i = 0; i < K; i++ ) { + idx[ i ] = i; + } + + /* Sort vector elements by value, decreasing order */ + for( i = 1; i < K; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + + /* If less than L values are asked for, check the remaining values, */ + /* but only spend CPU to ensure that the K first values are correct */ + for( i = K; i < L; i++ ) { + value = a[ i ]; + if( value > a[ K - 1 ] ) { + for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + idx[ j + 1 ] = idx[ j ]; /* Shift index */ + } + a[ j + 1 ] = value; /* Write value */ + idx[ j + 1 ] = i; /* Write index */ + } + } +} +#endif + +void silk_insertion_sort_increasing_all_values_int16( + opus_int16 *a, /* I/O Unsorted / Sorted vector */ + const opus_int L /* I Vector length */ +) +{ + opus_int value; + opus_int i, j; + + /* Safety checks */ + celt_assert( L > 0 ); + + /* Sort vector elements by value, increasing order */ + for( i = 1; i < L; i++ ) { + value = a[ i ]; + for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) { + a[ j + 1 ] = a[ j ]; /* Shift value */ + } + a[ j + 1 ] = value; /* Write value */ + } +} diff --git a/src/libopus/silk/stereo_LR_to_MS.c b/src/libopus/silk/stereo_LR_to_MS.c new file mode 100644 index 00000000..f19acbb9 --- /dev/null +++ b/src/libopus/silk/stereo_LR_to_MS.c @@ -0,0 +1,229 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" +#include "../celt/stack_alloc.h" + +/* Convert Left/Right stereo signal to adaptive Mid/Side representation */ +void silk_stereo_LR_to_MS( + stereo_enc_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */ + opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */ + opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */ + opus_int32 total_rate_bps, /* I Total bitrate */ + opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */ + opus_int toMono, /* I Last frame before a stereo->mono transition */ + opus_int fs_kHz, /* I Sample rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13; + opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24; + VARDECL( opus_int16, side ); + VARDECL( opus_int16, LP_mid ); + VARDECL( opus_int16, HP_mid ); + VARDECL( opus_int16, LP_side ); + VARDECL( opus_int16, HP_side ); + opus_int16 *mid = &x1[ -2 ]; + SAVE_STACK; + + ALLOC( side, frame_length + 2, opus_int16 ); + /* Convert to basic mid/side signals */ + for( n = 0; n < frame_length + 2; n++ ) { + sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ]; + diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ]; + mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 ); + side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) ); + } + + /* Buffering */ + silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* LP and HP filter mid signal */ + ALLOC( LP_mid, frame_length, opus_int16 ); + ALLOC( HP_mid, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 ); + LP_mid[ n ] = sum; + HP_mid[ n ] = mid[ n + 1 ] - sum; + } + + /* LP and HP filter side signal */ + ALLOC( LP_side, frame_length, opus_int16 ); + ALLOC( HP_side, frame_length, opus_int16 ); + for( n = 0; n < frame_length; n++ ) { + sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + (opus_int32)side[ n + 2 ], side[ n + 1 ], 1 ), 2 ); + LP_side[ n ] = sum; + HP_side[ n ] = side[ n + 1 ] - sum; + } + + /* Find energies and predictors */ + is10msFrame = frame_length == 10 * fs_kHz; + smooth_coef_Q16 = is10msFrame ? + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) : + SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 ); + smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 ); + + pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 ); + pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 ); + /* Ratio of the norms of residual and mid signals */ + frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 ); + frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) ); + + /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */ + total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */ + if( total_rate_bps < 1 ) { + total_rate_bps = 1; + } + min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 600 ); + silk_assert( min_mid_rate_bps < 32767 ); + /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */ + frac_3_Q16 = silk_MUL( 3, frac_Q16 ); + mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 ); + /* If Mid bitrate below minimum, reduce stereo width */ + if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) { + mid_side_rates_bps[ 0 ] = min_mid_rate_bps; + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */ + width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps, + silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 ); + width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) ); + } else { + mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ]; + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } + + /* Smoother */ + state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 ); + + /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */ + *mid_only_flag = 0; + if( toMono ) { + /* Last frame before stereo->mono transition; collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + silk_stereo_quant_pred( pred_Q13, ix ); + } else if( state->width_prev_Q14 == 0 && + ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) ) + { + /* Code as panned-mono; previous frame already had zero width */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + mid_side_rates_bps[ 0 ] = total_rate_bps; + mid_side_rates_bps[ 1 ] = 0; + *mid_only_flag = 1; + } else if( state->width_prev_Q14 != 0 && + ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) ) + { + /* Transition to zero-width stereo */ + /* Scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + /* Collapse stereo width */ + width_Q14 = 0; + pred_Q13[ 0 ] = 0; + pred_Q13[ 1 ] = 0; + } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) { + /* Full-width stereo coding */ + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = SILK_FIX_CONST( 1, 14 ); + } else { + /* Reduced-width stereo coding; scale down and quantize predictors */ + pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 ); + pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 ); + silk_stereo_quant_pred( pred_Q13, ix ); + width_Q14 = state->smth_width_Q14; + } + + /* Make sure to keep on encoding until the tapered output has been transmitted */ + if( *mid_only_flag == 1 ) { + state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz; + if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) { + *mid_only_flag = 0; + } else { + /* Limit to avoid wrapping around */ + state->silent_side_len = 10000; + } + } else { + state->silent_side_len = 0; + } + + if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) { + mid_side_rates_bps[ 1 ] = 1; + mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]); + } + + /* Interpolate predictors and subtract prediction from side channel */ + pred0_Q13 = -state->pred_prev_Q13[ 0 ]; + pred1_Q13 = -state->pred_prev_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 ); + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + w_Q24 += deltaw_Q24; + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + + pred0_Q13 = -pred_Q13[ 0 ]; + pred1_Q13 = -pred_Q13[ 1 ]; + w_Q24 = silk_LSHIFT( width_Q14, 10 ); + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + (opus_int32)mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ]; + state->width_prev_Q14 = (opus_int16)width_Q14; + RESTORE_STACK; +} diff --git a/src/libopus/silk/stereo_MS_to_LR.c b/src/libopus/silk/stereo_MS_to_LR.c new file mode 100644 index 00000000..e6e94b1d --- /dev/null +++ b/src/libopus/silk/stereo_MS_to_LR.c @@ -0,0 +1,85 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Convert adaptive Mid/Side representation to Left/Right stereo signal */ +void silk_stereo_MS_to_LR( + stereo_dec_state *state, /* I/O State */ + opus_int16 x1[], /* I/O Left input signal, becomes mid signal */ + opus_int16 x2[], /* I/O Right input signal, becomes side signal */ + const opus_int32 pred_Q13[], /* I Predictors */ + opus_int fs_kHz, /* I Samples rate (kHz) */ + opus_int frame_length /* I Number of samples */ +) +{ + opus_int n, denom_Q16, delta0_Q13, delta1_Q13; + opus_int32 sum, diff, pred0_Q13, pred1_Q13; + + /* Buffering */ + silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) ); + silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) ); + silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) ); + + /* Interpolate predictors and add prediction to side channel */ + pred0_Q13 = state->pred_prev_Q13[ 0 ]; + pred1_Q13 = state->pred_prev_Q13[ 1 ]; + denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz ); + delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 ); + delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 ); + for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) { + pred0_Q13 += delta0_Q13; + pred1_Q13 += delta1_Q13; + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + pred0_Q13 = pred_Q13[ 0 ]; + pred1_Q13 = pred_Q13[ 1 ]; + for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) { + sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */ + sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */ + sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */ + x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) ); + } + state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ]; + state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ]; + + /* Convert to left/right signals */ + for( n = 0; n < frame_length; n++ ) { + sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ]; + diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ]; + x1[ n + 1 ] = (opus_int16)silk_SAT16( sum ); + x2[ n + 1 ] = (opus_int16)silk_SAT16( diff ); + } +} diff --git a/src/libopus/silk/stereo_decode_pred.c b/src/libopus/silk/stereo_decode_pred.c new file mode 100644 index 00000000..513d4d37 --- /dev/null +++ b/src/libopus/silk/stereo_decode_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Decode mid/side predictors */ +void silk_stereo_decode_pred( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int32 pred_Q13[] /* O Predictors */ +) +{ + opus_int n, ix[ 2 ][ 3 ]; + opus_int32 low_Q13, step_Q13; + + /* Entropy decoding */ + n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 ); + ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 ); + ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ]; + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 ); + ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 ); + } + + /* Dequantize */ + for( n = 0; n < 2; n++ ) { + ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ]; + low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 ); + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} + +/* Decode mid-only flag */ +void silk_stereo_decode_mid_only( + ec_dec *psRangeDec, /* I/O Compressor data structure */ + opus_int *decode_only_mid /* O Flag that only mid channel has been coded */ +) +{ + /* Decode flag that only mid channel is coded */ + *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/src/libopus/silk/stereo_encode_pred.c b/src/libopus/silk/stereo_encode_pred.c new file mode 100644 index 00000000..19c1c760 --- /dev/null +++ b/src/libopus/silk/stereo_encode_pred.c @@ -0,0 +1,62 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Entropy code the mid/side quantization indices */ +void silk_stereo_encode_pred( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */ +) +{ + opus_int n; + + /* Entropy coding */ + n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ]; + celt_assert( n < 25 ); + ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 ); + for( n = 0; n < 2; n++ ) { + celt_assert( ix[ n ][ 0 ] < 3 ); + celt_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 ); + ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 ); + } +} + +/* Entropy code the mid-only flag */ +void silk_stereo_encode_mid_only( + ec_enc *psRangeEnc, /* I/O Compressor data structure */ + opus_int8 mid_only_flag +) +{ + /* Encode flag that only mid channel is coded */ + ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 ); +} diff --git a/src/libopus/silk/stereo_find_predictor.c b/src/libopus/silk/stereo_find_predictor.c new file mode 100644 index 00000000..0a53ad36 --- /dev/null +++ b/src/libopus/silk/stereo_find_predictor.c @@ -0,0 +1,79 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Find least-squares prediction gain for one signal based on another and quantize it */ +opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */ + opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */ + const opus_int16 x[], /* I Basis signal */ + const opus_int16 y[], /* I Target signal */ + opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */ + opus_int length, /* I Number of samples */ + opus_int smooth_coef_Q16 /* I Smoothing coefficient */ +) +{ + opus_int scale, scale1, scale2; + opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10; + + /* Find predictor */ + silk_sum_sqr_shift( &nrgx, &scale1, x, length ); + silk_sum_sqr_shift( &nrgy, &scale2, y, length ); + scale = silk_max_int( scale1, scale2 ); + scale = scale + ( scale & 1 ); /* make even */ + nrgy = silk_RSHIFT32( nrgy, scale - scale2 ); + nrgx = silk_RSHIFT32( nrgx, scale - scale1 ); + nrgx = silk_max_int( nrgx, 1 ); + corr = silk_inner_prod_aligned_scale( x, y, scale, length ); + pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 ); + pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 ); + pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 ); + + /* Faster update for signals with large prediction parameters */ + smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) ); + + /* Smoothed mid and residual norms */ + silk_assert( smooth_coef_Q16 < 32768 ); + scale = silk_RSHIFT( scale, 1 ); + mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ], + smooth_coef_Q16 ); + /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */ + nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 ); + nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 ); + mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ], + smooth_coef_Q16 ); + + /* Ratio of smoothed residual and mid norms */ + *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 ); + *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 ); + + return pred_Q13; +} diff --git a/src/libopus/silk/stereo_quant_pred.c b/src/libopus/silk/stereo_quant_pred.c new file mode 100644 index 00000000..4ad28653 --- /dev/null +++ b/src/libopus/silk/stereo_quant_pred.c @@ -0,0 +1,73 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "main.h" + +/* Quantize mid/side predictors */ +void silk_stereo_quant_pred( + opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */ + opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */ +) +{ + opus_int i, j, n; + opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0; + + /* Quantize */ + for( n = 0; n < 2; n++ ) { + /* Brute-force search over quantization levels */ + err_min_Q13 = silk_int32_MAX; + for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) { + low_Q13 = silk_stereo_pred_quant_Q13[ i ]; + step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13, + SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) ); + for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) { + lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 ); + err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 ); + if( err_Q13 < err_min_Q13 ) { + err_min_Q13 = err_Q13; + quant_pred_Q13 = lvl_Q13; + ix[ n ][ 0 ] = i; + ix[ n ][ 1 ] = j; + } else { + /* Error increasing, so we're past the optimum */ + goto done; + } + } + } + done: + ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 ); + ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3; + pred_Q13[ n ] = quant_pred_Q13; + } + + /* Subtract second from first predictor (helps when actually applying these) */ + pred_Q13[ 0 ] -= pred_Q13[ 1 ]; +} diff --git a/src/libopus/silk/structs.h b/src/libopus/silk/structs.h new file mode 100644 index 00000000..02a0ed1a --- /dev/null +++ b/src/libopus/silk/structs.h @@ -0,0 +1,329 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_STRUCTS_H +#define SILK_STRUCTS_H + +#include "typedef.h" +#include "SigProc_FIX.h" +#include "define.h" +#include "../celt/entenc.h" +#include "../celt/entdec.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/************************************/ +/* Noise shaping quantization state */ +/************************************/ +typedef struct { + opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */ + opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ]; + opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ]; + opus_int32 sLF_AR_shp_Q14; + opus_int32 sDiff_shp_Q14; + opus_int lagPrev; + opus_int sLTP_buf_idx; + opus_int sLTP_shp_buf_idx; + opus_int32 rand_seed; + opus_int32 prev_gain_Q16; + opus_int rewhite_flag; +} silk_nsq_state; + +/********************************/ +/* VAD state */ +/********************************/ +typedef struct { + opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */ + opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */ + opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */ + opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */ + opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */ + opus_int16 HPstate; /* State of differentiator in the lowest band */ + opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */ + opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */ + opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */ + opus_int32 counter; /* Frame counter used in the initial phase */ +} silk_VAD_state; + +/* Variable cut-off low-pass filter state */ +typedef struct { + opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */ + opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */ + opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */ + opus_int32 saved_fs_kHz; /* If non-zero, holds the last sampling rate before a bandwidth switching reset. */ +} silk_LP_state; + +/* Structure containing NLSF codebook */ +typedef struct { + const opus_int16 nVectors; + const opus_int16 order; + const opus_int16 quantStepSize_Q16; + const opus_int16 invQuantStepSize_Q6; + const opus_uint8 *CB1_NLSF_Q8; + const opus_int16 *CB1_Wght_Q9; + const opus_uint8 *CB1_iCDF; + const opus_uint8 *pred_Q8; + const opus_uint8 *ec_sel; + const opus_uint8 *ec_iCDF; + const opus_uint8 *ec_Rates_Q5; + const opus_int16 *deltaMin_Q15; +} silk_NLSF_CB_struct; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; + opus_int32 mid_side_amp_Q0[ 4 ]; + opus_int16 smth_width_Q14; + opus_int16 width_prev_Q14; + opus_int16 silent_side_len; + opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ]; + opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ]; +} stereo_enc_state; + +typedef struct { + opus_int16 pred_prev_Q13[ 2 ]; + opus_int16 sMid[ 2 ]; + opus_int16 sSide[ 2 ]; +} stereo_dec_state; + +typedef struct { + opus_int8 GainsIndices[ MAX_NB_SUBFR ]; + opus_int8 LTPIndex[ MAX_NB_SUBFR ]; + opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ]; + opus_int16 lagIndex; + opus_int8 contourIndex; + opus_int8 signalType; + opus_int8 quantOffsetType; + opus_int8 NLSFInterpCoef_Q2; + opus_int8 PERIndex; + opus_int8 LTP_scaleIndex; + opus_int8 Seed; +} SideInfoIndices; + +/********************************/ +/* Encoder state */ +/********************************/ +typedef struct { + opus_int32 In_HP_State[ 2 ]; /* High pass filter state */ + opus_int32 variable_HP_smth1_Q15; /* State of first smoother */ + opus_int32 variable_HP_smth2_Q15; /* State of second smoother */ + silk_LP_state sLP; /* Low pass filter state */ + silk_VAD_state sVAD; /* Voice activity detector state */ + silk_nsq_state sNSQ; /* Noise Shape Quantizer State */ + opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */ + opus_int speech_activity_Q8; /* Speech activity */ + opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */ + opus_int8 LBRRprevLastGainIndex; + opus_int8 prevSignalType; + opus_int prevLag; + opus_int pitch_LPC_win_length; + opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */ + opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */ + opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */ + opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */ + opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */ + opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */ + opus_int fs_kHz; /* Internal sampling frequency (kHz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */ + opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */ + opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */ + opus_int32 TargetRate_bps; /* Target bitrate (bps) */ + opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */ + opus_int PacketLoss_perc; /* Packet loss rate measured by farend */ + opus_int32 frameCounter; + opus_int Complexity; /* Complexity setting */ + opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */ + opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */ + opus_int shapingLPCOrder; /* Filter order for noise shaping filters */ + opus_int predictLPCOrder; /* Filter order for prediction filters */ + opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */ + opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */ + opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */ + opus_int32 sum_log_gain_Q7; /* Cumulative max prediction gain */ + opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */ + opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */ + opus_int warping_Q16; /* Warping parameter for warped noise shaping */ + opus_int useCBR; /* Flag to enable constant bitrate */ + opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + opus_int input_quality_bands_Q15[ VAD_N_BANDS ]; + opus_int input_tilt_Q15; + opus_int SNR_dB_Q7; /* Quality setting */ + + opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int8 LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + SideInfoIndices indices; + opus_int8 pulses[ MAX_FRAME_LENGTH ]; + + int arch; + + /* Input/output buffering */ + opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */ + opus_int inputBufIx; + opus_int nFramesPerPacket; + opus_int nFramesEncoded; /* Number of frames analyzed in current packet */ + + opus_int nChannelsAPI; + opus_int nChannelsInternal; + opus_int channelNb; + + /* Parameters For LTP scaling Control */ + opus_int frames_since_onset; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + silk_resampler_state_struct resampler_state; + + /* DTX */ + opus_int useDTX; /* Flag to enable DTX */ + opus_int inDTX; /* Flag to signal DTX period */ + opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */ + + /* Inband Low Bitrate Redundancy (LBRR) data */ + opus_int useInBandFEC; /* Saves the API setting for query */ + opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */ + opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */ + SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ]; + opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ]; +} silk_encoder_state; + + +/* Struct for Packet Loss Concealment */ +typedef struct { + opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */ + opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */ + opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ]; + opus_int last_frame_lost; /* Was previous frame lost */ + opus_int32 rand_seed; /* Seed for unvoiced signal generation */ + opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */ + opus_int32 conc_energy; + opus_int conc_energy_shift; + opus_int16 prevLTP_scale_Q14; + opus_int32 prevGain_Q16[ 2 ]; + opus_int fs_kHz; + opus_int nb_subfr; + opus_int subfr_length; +} silk_PLC_struct; + +/* Struct for CNG */ +typedef struct { + opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ]; + opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ]; + opus_int32 CNG_synth_state[ MAX_LPC_ORDER ]; + opus_int32 CNG_smth_Gain_Q16; + opus_int32 rand_seed; + opus_int fs_kHz; +} silk_CNG_struct; + +/********************************/ +/* Decoder state */ +/********************************/ +typedef struct { + opus_int32 prev_gain_Q16; + opus_int32 exc_Q14[ MAX_FRAME_LENGTH ]; + opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ]; + opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */ + opus_int lagPrev; /* Previous Lag */ + opus_int8 LastGainIndex; /* Previous gain index */ + opus_int fs_kHz; /* Sampling frequency in kHz */ + opus_int32 fs_API_hz; /* API sample frequency (Hz) */ + opus_int nb_subfr; /* Number of 5 ms subframes in a frame */ + opus_int frame_length; /* Frame length (samples) */ + opus_int subfr_length; /* Subframe length (samples) */ + opus_int ltp_mem_length; /* Length of LTP memory */ + opus_int LPC_order; /* LPC order */ + opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */ + opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */ + const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */ + const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */ + + /* For buffering payload in case of more frames per packet */ + opus_int nFramesDecoded; + opus_int nFramesPerPacket; + + /* Specifically for entropy coding */ + opus_int ec_prevSignalType; + opus_int16 ec_prevLagIndex; + + opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ]; + opus_int LBRR_flag; + opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ]; + + silk_resampler_state_struct resampler_state; + + const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */ + + /* Quantization indices */ + SideInfoIndices indices; + + /* CNG state */ + silk_CNG_struct sCNG; + + /* Stuff used for PLC */ + opus_int lossCnt; + opus_int prevSignalType; + int arch; + + silk_PLC_struct sPLC; + +} silk_decoder_state; + +/************************/ +/* Decoder control */ +/************************/ +typedef struct { + /* Prediction and coding parameters */ + opus_int pitchL[ MAX_NB_SUBFR ]; + opus_int32 Gains_Q16[ MAX_NB_SUBFR ]; + /* Holds interpolated and final coefficients, 4-byte aligned */ + silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ]; + opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ]; + opus_int LTP_scale_Q14; +} silk_decoder_control; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/silk/sum_sqr_shift.c b/src/libopus/silk/sum_sqr_shift.c new file mode 100644 index 00000000..df0bd2e6 --- /dev/null +++ b/src/libopus/silk/sum_sqr_shift.c @@ -0,0 +1,83 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "SigProc_FIX.h" + +/* Compute number of bits to right shift the sum of squares of a vector */ +/* of int16s to make it fit in an int32 */ +void silk_sum_sqr_shift( + opus_int32 *energy, /* O Energy of x, after shifting to the right */ + opus_int *shift, /* O Number of bits right shift applied to energy */ + const opus_int16 *x, /* I Input vector */ + opus_int len /* I Length of input vector */ +) +{ + opus_int i, shft; + opus_uint32 nrg_tmp; + opus_int32 nrg; + + /* Do a first run with the maximum shift we could have. */ + shft = 31-silk_CLZ32(len); + /* Let's be conservative with rounding and start with nrg=len. */ + nrg = len; + for( i = 0; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + silk_assert( nrg >= 0 ); + /* Make sure the result will fit in a 32-bit signed integer with two bits + of headroom. */ + shft = silk_max_32(0, shft+3 - silk_CLZ32(nrg)); + nrg = 0; + for( i = 0 ; i < len - 1; i += 2 ) { + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + if( i < len ) { + /* One sample left to process */ + nrg_tmp = silk_SMULBB( x[ i ], x[ i ] ); + nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft ); + } + + silk_assert( nrg >= 0 ); + + /* Output arguments */ + *shift = shft; + *energy = nrg; +} + diff --git a/src/libopus/silk/table_LSF_cos.c b/src/libopus/silk/table_LSF_cos.c new file mode 100644 index 00000000..a78748ee --- /dev/null +++ b/src/libopus/silk/table_LSF_cos.c @@ -0,0 +1,70 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "tables.h" + +/* Cosine approximation table for LSF conversion */ +/* Q12 values (even) */ +const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = { + 8192, 8190, 8182, 8170, + 8152, 8130, 8104, 8072, + 8034, 7994, 7946, 7896, + 7840, 7778, 7714, 7644, + 7568, 7490, 7406, 7318, + 7226, 7128, 7026, 6922, + 6812, 6698, 6580, 6458, + 6332, 6204, 6070, 5934, + 5792, 5648, 5502, 5352, + 5198, 5040, 4880, 4718, + 4552, 4382, 4212, 4038, + 3862, 3684, 3502, 3320, + 3136, 2948, 2760, 2570, + 2378, 2186, 1990, 1794, + 1598, 1400, 1202, 1002, + 802, 602, 402, 202, + 0, -202, -402, -602, + -802, -1002, -1202, -1400, + -1598, -1794, -1990, -2186, + -2378, -2570, -2760, -2948, + -3136, -3320, -3502, -3684, + -3862, -4038, -4212, -4382, + -4552, -4718, -4880, -5040, + -5198, -5352, -5502, -5648, + -5792, -5934, -6070, -6204, + -6332, -6458, -6580, -6698, + -6812, -6922, -7026, -7128, + -7226, -7318, -7406, -7490, + -7568, -7644, -7714, -7778, + -7840, -7896, -7946, -7994, + -8034, -8072, -8104, -8130, + -8152, -8170, -8182, -8190, + -8192 +}; diff --git a/src/libopus/silk/tables.h b/src/libopus/silk/tables.h new file mode 100644 index 00000000..95230c45 --- /dev/null +++ b/src/libopus/silk/tables.h @@ -0,0 +1,114 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TABLES_H +#define SILK_TABLES_H + +#include "define.h" +#include "structs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Entropy coding tables (with size in bytes indicated) */ +extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */ +extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */ + +extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */ +extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */ +extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */ +extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */ +extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */ +extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */ + +extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ SILK_MAX_PULSES + 2 ]; /* 180 */ +extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ SILK_MAX_PULSES + 2 ]; /* 162 */ + +extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ +extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */ + +extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */ + +extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */ +extern const opus_uint8 silk_shell_code_table_offsets[ SILK_MAX_PULSES + 1 ]; /* 17 */ + +extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */ + +extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */ +extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */ +extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */ + +extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */ + +extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */ +extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */ +extern const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS]; +extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */ + +extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */ +extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */ + +extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */ +extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */ + +extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */ +extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */ +extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */ + +extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */ + +extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */ + +extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */ +extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */ + +/* Quantization offsets */ +extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */ +extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */ + +/* Rom table with cosine values */ +extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libopus/silk/tables_LTP.c b/src/libopus/silk/tables_LTP.c new file mode 100644 index 00000000..ce736e85 --- /dev/null +++ b/src/libopus/silk/tables_LTP.c @@ -0,0 +1,294 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "tables.h" + +const opus_uint8 silk_LTP_per_index_iCDF[3] = { + 179, 99, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_0[8] = { + 71, 56, 43, 30, 21, 12, 6, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_1[16] = { + 199, 165, 144, 124, 109, 96, 84, 71, + 61, 51, 42, 32, 23, 15, 8, 0 +}; + +static const opus_uint8 silk_LTP_gain_iCDF_2[32] = { + 241, 225, 211, 199, 187, 175, 164, 153, + 142, 132, 123, 114, 105, 96, 88, 80, + 72, 64, 57, 50, 44, 38, 33, 29, + 24, 20, 16, 12, 9, 5, 2, 0 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = { + 15, 131, 138, 138, 155, 155, 173, 173 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = { + 69, 93, 115, 118, 131, 138, 141, 138, + 150, 150, 155, 150, 155, 160, 166, 160 +}; + +static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = { + 131, 128, 134, 141, 141, 141, 145, 145, + 145, 150, 155, 155, 155, 155, 160, 160, + 160, 160, 166, 166, 173, 173, 182, 192, + 182, 192, 192, 192, 205, 192, 205, 224 +}; + +const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_iCDF_0, + silk_LTP_gain_iCDF_1, + silk_LTP_gain_iCDF_2 +}; + +const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = { + silk_LTP_gain_BITS_Q5_0, + silk_LTP_gain_BITS_Q5_1, + silk_LTP_gain_BITS_Q5_2 +}; + +static const opus_int8 silk_LTP_gain_vq_0[8][5] = +{ +{ + 4, 6, 24, 7, 5 +}, +{ + 0, 0, 2, 0, 0 +}, +{ + 12, 28, 41, 13, -4 +}, +{ + -9, 15, 42, 25, 14 +}, +{ + 1, -2, 62, 41, -9 +}, +{ + -10, 37, 65, -4, 3 +}, +{ + -6, 4, 66, 7, -8 +}, +{ + 16, 14, 38, -3, 33 +} +}; + +static const opus_int8 silk_LTP_gain_vq_1[16][5] = +{ +{ + 13, 22, 39, 23, 12 +}, +{ + -1, 36, 64, 27, -6 +}, +{ + -7, 10, 55, 43, 17 +}, +{ + 1, 1, 8, 1, 1 +}, +{ + 6, -11, 74, 53, -9 +}, +{ + -12, 55, 76, -12, 8 +}, +{ + -3, 3, 93, 27, -4 +}, +{ + 26, 39, 59, 3, -8 +}, +{ + 2, 0, 77, 11, 9 +}, +{ + -8, 22, 44, -6, 7 +}, +{ + 40, 9, 26, 3, 9 +}, +{ + -7, 20, 101, -7, 4 +}, +{ + 3, -8, 42, 26, 0 +}, +{ + -15, 33, 68, 2, 23 +}, +{ + -2, 55, 46, -2, 15 +}, +{ + 3, -1, 21, 16, 41 +} +}; + +static const opus_int8 silk_LTP_gain_vq_2[32][5] = +{ +{ + -6, 27, 61, 39, 5 +}, +{ + -11, 42, 88, 4, 1 +}, +{ + -2, 60, 65, 6, -4 +}, +{ + -1, -5, 73, 56, 1 +}, +{ + -9, 19, 94, 29, -9 +}, +{ + 0, 12, 99, 6, 4 +}, +{ + 8, -19, 102, 46, -13 +}, +{ + 3, 2, 13, 3, 2 +}, +{ + 9, -21, 84, 72, -18 +}, +{ + -11, 46, 104, -22, 8 +}, +{ + 18, 38, 48, 23, 0 +}, +{ + -16, 70, 83, -21, 11 +}, +{ + 5, -11, 117, 22, -8 +}, +{ + -6, 23, 117, -12, 3 +}, +{ + 3, -8, 95, 28, 4 +}, +{ + -10, 15, 77, 60, -15 +}, +{ + -1, 4, 124, 2, -4 +}, +{ + 3, 38, 84, 24, -25 +}, +{ + 2, 13, 42, 13, 31 +}, +{ + 21, -4, 56, 46, -1 +}, +{ + -1, 35, 79, -13, 19 +}, +{ + -7, 65, 88, -9, -14 +}, +{ + 20, 4, 81, 49, -29 +}, +{ + 20, 0, 75, 3, -17 +}, +{ + 5, -9, 44, 92, -8 +}, +{ + 1, -3, 22, 69, 31 +}, +{ + -6, 95, 41, -12, 5 +}, +{ + 39, 67, 16, -4, 1 +}, +{ + 0, -6, 120, 55, -36 +}, +{ + -13, 44, 122, 4, -24 +}, +{ + 81, 5, 11, 3, 7 +}, +{ + 2, 0, 9, 10, 88 +} +}; + +const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = { + (opus_int8 *)&silk_LTP_gain_vq_0[0][0], + (opus_int8 *)&silk_LTP_gain_vq_1[0][0], + (opus_int8 *)&silk_LTP_gain_vq_2[0][0] +}; + +/* Maximum frequency-dependent response of the pitch taps above, + computed as max(abs(freqz(taps))) */ +static const opus_uint8 silk_LTP_gain_vq_0_gain[8] = { + 46, 2, 90, 87, 93, 91, 82, 98 +}; + +static const opus_uint8 silk_LTP_gain_vq_1_gain[16] = { + 109, 120, 118, 12, 113, 115, 117, 119, + 99, 59, 87, 111, 63, 111, 112, 80 +}; + +static const opus_uint8 silk_LTP_gain_vq_2_gain[32] = { + 126, 124, 125, 124, 129, 121, 126, 23, + 132, 127, 127, 127, 126, 127, 122, 133, + 130, 134, 101, 118, 119, 145, 126, 86, + 124, 120, 123, 119, 170, 173, 107, 109 +}; + +const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = { + &silk_LTP_gain_vq_0_gain[0], + &silk_LTP_gain_vq_1_gain[0], + &silk_LTP_gain_vq_2_gain[0] +}; + +const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = { + 8, 16, 32 +}; diff --git a/src/libopus/silk/tables_NLSF_CB_NB_MB.c b/src/libopus/silk/tables_NLSF_CB_NB_MB.c new file mode 100644 index 00000000..ce76ea8c --- /dev/null +++ b/src/libopus/silk/tables_NLSF_CB_NB_MB.c @@ -0,0 +1,195 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = { + 12, 35, 60, 83, 108, 132, 157, 180, + 206, 228, 15, 32, 55, 77, 101, 125, + 151, 175, 201, 225, 19, 42, 66, 89, + 114, 137, 162, 184, 209, 230, 12, 25, + 50, 72, 97, 120, 147, 172, 200, 223, + 26, 44, 69, 90, 114, 135, 159, 180, + 205, 225, 13, 22, 53, 80, 106, 130, + 156, 180, 205, 228, 15, 25, 44, 64, + 90, 115, 142, 168, 196, 222, 19, 24, + 62, 82, 100, 120, 145, 168, 190, 214, + 22, 31, 50, 79, 103, 120, 151, 170, + 203, 227, 21, 29, 45, 65, 106, 124, + 150, 171, 196, 224, 30, 49, 75, 97, + 121, 142, 165, 186, 209, 229, 19, 25, + 52, 70, 93, 116, 143, 166, 192, 219, + 26, 34, 62, 75, 97, 118, 145, 167, + 194, 217, 25, 33, 56, 70, 91, 113, + 143, 165, 196, 223, 21, 34, 51, 72, + 97, 117, 145, 171, 196, 222, 20, 29, + 50, 67, 90, 117, 144, 168, 197, 221, + 22, 31, 48, 66, 95, 117, 146, 168, + 196, 222, 24, 33, 51, 77, 116, 134, + 158, 180, 200, 224, 21, 28, 70, 87, + 106, 124, 149, 170, 194, 217, 26, 33, + 53, 64, 83, 117, 152, 173, 204, 225, + 27, 34, 65, 95, 108, 129, 155, 174, + 210, 225, 20, 26, 72, 99, 113, 131, + 154, 176, 200, 219, 34, 43, 61, 78, + 93, 114, 155, 177, 205, 229, 23, 29, + 54, 97, 124, 138, 163, 179, 209, 229, + 30, 38, 56, 89, 118, 129, 158, 178, + 200, 231, 21, 29, 49, 63, 85, 111, + 142, 163, 193, 222, 27, 48, 77, 103, + 133, 158, 179, 196, 215, 232, 29, 47, + 74, 99, 124, 151, 176, 198, 220, 237, + 33, 42, 61, 76, 93, 121, 155, 174, + 207, 225, 29, 53, 87, 112, 136, 154, + 170, 188, 208, 227, 24, 30, 52, 84, + 131, 150, 166, 186, 203, 229, 37, 48, + 64, 84, 104, 118, 156, 177, 201, 230 +}; + +static const opus_int16 silk_NLSF_CB1_Wght_Q9[ 320 ] = { + 2897, 2314, 2314, 2314, 2287, 2287, 2314, 2300, 2327, 2287, + 2888, 2580, 2394, 2367, 2314, 2274, 2274, 2274, 2274, 2194, + 2487, 2340, 2340, 2314, 2314, 2314, 2340, 2340, 2367, 2354, + 3216, 2766, 2340, 2340, 2314, 2274, 2221, 2207, 2261, 2194, + 2460, 2474, 2367, 2394, 2394, 2394, 2394, 2367, 2407, 2314, + 3479, 3056, 2127, 2207, 2274, 2274, 2274, 2287, 2314, 2261, + 3282, 3141, 2580, 2394, 2247, 2221, 2207, 2194, 2194, 2114, + 4096, 3845, 2221, 2620, 2620, 2407, 2314, 2394, 2367, 2074, + 3178, 3244, 2367, 2221, 2553, 2434, 2340, 2314, 2167, 2221, + 3338, 3488, 2726, 2194, 2261, 2460, 2354, 2367, 2207, 2101, + 2354, 2420, 2327, 2367, 2394, 2420, 2420, 2420, 2460, 2367, + 3779, 3629, 2434, 2527, 2367, 2274, 2274, 2300, 2207, 2048, + 3254, 3225, 2713, 2846, 2447, 2327, 2300, 2300, 2274, 2127, + 3263, 3300, 2753, 2806, 2447, 2261, 2261, 2247, 2127, 2101, + 2873, 2981, 2633, 2367, 2407, 2354, 2194, 2247, 2247, 2114, + 3225, 3197, 2633, 2580, 2274, 2181, 2247, 2221, 2221, 2141, + 3178, 3310, 2740, 2407, 2274, 2274, 2274, 2287, 2194, 2114, + 3141, 3272, 2460, 2061, 2287, 2500, 2367, 2487, 2434, 2181, + 3507, 3282, 2314, 2700, 2647, 2474, 2367, 2394, 2340, 2127, + 3423, 3535, 3038, 3056, 2300, 1950, 2221, 2274, 2274, 2274, + 3404, 3366, 2087, 2687, 2873, 2354, 2420, 2274, 2474, 2540, + 3760, 3488, 1950, 2660, 2897, 2527, 2394, 2367, 2460, 2261, + 3028, 3272, 2740, 2888, 2740, 2154, 2127, 2287, 2234, 2247, + 3695, 3657, 2025, 1969, 2660, 2700, 2580, 2500, 2327, 2367, + 3207, 3413, 2354, 2074, 2888, 2888, 2340, 2487, 2247, 2167, + 3338, 3366, 2846, 2780, 2327, 2154, 2274, 2287, 2114, 2061, + 2327, 2300, 2181, 2167, 2181, 2367, 2633, 2700, 2700, 2553, + 2407, 2434, 2221, 2261, 2221, 2221, 2340, 2420, 2607, 2700, + 3038, 3244, 2806, 2888, 2474, 2074, 2300, 2314, 2354, 2380, + 2221, 2154, 2127, 2287, 2500, 2793, 2793, 2620, 2580, 2367, + 3676, 3713, 2234, 1838, 2181, 2753, 2726, 2673, 2513, 2207, + 2793, 3160, 2726, 2553, 2846, 2513, 2181, 2394, 2221, 2181 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = { + 212, 178, 148, 129, 108, 96, 85, 82, + 79, 77, 61, 59, 57, 56, 51, 49, + 48, 45, 42, 41, 40, 38, 36, 34, + 31, 30, 21, 12, 10, 3, 1, 0, + 255, 245, 244, 236, 233, 225, 217, 203, + 190, 176, 175, 161, 149, 136, 125, 114, + 102, 91, 81, 71, 60, 52, 43, 35, + 28, 20, 19, 18, 12, 11, 5, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = { + 16, 0, 0, 0, 0, 99, 66, 36, + 36, 34, 36, 34, 34, 34, 34, 83, + 69, 36, 52, 34, 116, 102, 70, 68, + 68, 176, 102, 68, 68, 34, 65, 85, + 68, 84, 36, 116, 141, 152, 139, 170, + 132, 187, 184, 216, 137, 132, 249, 168, + 185, 139, 104, 102, 100, 68, 68, 178, + 218, 185, 185, 170, 244, 216, 187, 187, + 170, 244, 187, 187, 219, 138, 103, 155, + 184, 185, 137, 116, 183, 155, 152, 136, + 132, 217, 184, 184, 170, 164, 217, 171, + 155, 139, 244, 169, 184, 185, 170, 164, + 216, 223, 218, 138, 214, 143, 188, 218, + 168, 244, 141, 136, 155, 170, 168, 138, + 220, 219, 139, 164, 219, 202, 216, 137, + 168, 186, 246, 185, 139, 116, 185, 219, + 185, 138, 100, 100, 134, 100, 102, 34, + 68, 68, 100, 68, 168, 203, 221, 218, + 168, 167, 154, 136, 104, 70, 164, 246, + 171, 137, 139, 137, 155, 218, 219, 139 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = { + 255, 254, 253, 238, 14, 3, 2, 1, + 0, 255, 254, 252, 218, 35, 3, 2, + 1, 0, 255, 254, 250, 208, 59, 4, + 2, 1, 0, 255, 254, 246, 194, 71, + 10, 2, 1, 0, 255, 252, 236, 183, + 82, 8, 2, 1, 0, 255, 252, 235, + 180, 90, 17, 2, 1, 0, 255, 248, + 224, 171, 97, 30, 4, 1, 0, 255, + 254, 236, 173, 95, 37, 7, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = { + 255, 255, 255, 131, 6, 145, 255, 255, + 255, 255, 255, 236, 93, 15, 96, 255, + 255, 255, 255, 255, 194, 83, 25, 71, + 221, 255, 255, 255, 255, 162, 73, 34, + 66, 162, 255, 255, 255, 210, 126, 73, + 43, 57, 173, 255, 255, 255, 201, 125, + 71, 48, 58, 130, 255, 255, 255, 166, + 110, 73, 57, 62, 104, 210, 255, 255, + 251, 123, 65, 55, 68, 100, 171, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = { + 179, 138, 140, 148, 151, 149, 153, 151, + 163, 116, 67, 82, 59, 92, 72, 100, + 89, 92 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = { + 250, 3, 6, 3, 3, 3, 4, 3, + 3, 3, 461 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB = +{ + 32, + 10, + SILK_FIX_CONST( 0.18, 16 ), + SILK_FIX_CONST( 1.0 / 0.18, 6 ), + silk_NLSF_CB1_NB_MB_Q8, + silk_NLSF_CB1_Wght_Q9, + silk_NLSF_CB1_iCDF_NB_MB, + silk_NLSF_PRED_NB_MB_Q8, + silk_NLSF_CB2_SELECT_NB_MB, + silk_NLSF_CB2_iCDF_NB_MB, + silk_NLSF_CB2_BITS_NB_MB_Q5, + silk_NLSF_DELTA_MIN_NB_MB_Q15, +}; diff --git a/src/libopus/silk/tables_NLSF_CB_WB.c b/src/libopus/silk/tables_NLSF_CB_WB.c new file mode 100644 index 00000000..f0b35552 --- /dev/null +++ b/src/libopus/silk/tables_NLSF_CB_WB.c @@ -0,0 +1,234 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "tables.h" + +static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = { + 7, 23, 38, 54, 69, 85, 100, 116, + 131, 147, 162, 178, 193, 208, 223, 239, + 13, 25, 41, 55, 69, 83, 98, 112, + 127, 142, 157, 171, 187, 203, 220, 236, + 15, 21, 34, 51, 61, 78, 92, 106, + 126, 136, 152, 167, 185, 205, 225, 240, + 10, 21, 36, 50, 63, 79, 95, 110, + 126, 141, 157, 173, 189, 205, 221, 237, + 17, 20, 37, 51, 59, 78, 89, 107, + 123, 134, 150, 164, 184, 205, 224, 240, + 10, 15, 32, 51, 67, 81, 96, 112, + 129, 142, 158, 173, 189, 204, 220, 236, + 8, 21, 37, 51, 65, 79, 98, 113, + 126, 138, 155, 168, 179, 192, 209, 218, + 12, 15, 34, 55, 63, 78, 87, 108, + 118, 131, 148, 167, 185, 203, 219, 236, + 16, 19, 32, 36, 56, 79, 91, 108, + 118, 136, 154, 171, 186, 204, 220, 237, + 11, 28, 43, 58, 74, 89, 105, 120, + 135, 150, 165, 180, 196, 211, 226, 241, + 6, 16, 33, 46, 60, 75, 92, 107, + 123, 137, 156, 169, 185, 199, 214, 225, + 11, 19, 30, 44, 57, 74, 89, 105, + 121, 135, 152, 169, 186, 202, 218, 234, + 12, 19, 29, 46, 57, 71, 88, 100, + 120, 132, 148, 165, 182, 199, 216, 233, + 17, 23, 35, 46, 56, 77, 92, 106, + 123, 134, 152, 167, 185, 204, 222, 237, + 14, 17, 45, 53, 63, 75, 89, 107, + 115, 132, 151, 171, 188, 206, 221, 240, + 9, 16, 29, 40, 56, 71, 88, 103, + 119, 137, 154, 171, 189, 205, 222, 237, + 16, 19, 36, 48, 57, 76, 87, 105, + 118, 132, 150, 167, 185, 202, 218, 236, + 12, 17, 29, 54, 71, 81, 94, 104, + 126, 136, 149, 164, 182, 201, 221, 237, + 15, 28, 47, 62, 79, 97, 115, 129, + 142, 155, 168, 180, 194, 208, 223, 238, + 8, 14, 30, 45, 62, 78, 94, 111, + 127, 143, 159, 175, 192, 207, 223, 239, + 17, 30, 49, 62, 79, 92, 107, 119, + 132, 145, 160, 174, 190, 204, 220, 235, + 14, 19, 36, 45, 61, 76, 91, 108, + 121, 138, 154, 172, 189, 205, 222, 238, + 12, 18, 31, 45, 60, 76, 91, 107, + 123, 138, 154, 171, 187, 204, 221, 236, + 13, 17, 31, 43, 53, 70, 83, 103, + 114, 131, 149, 167, 185, 203, 220, 237, + 17, 22, 35, 42, 58, 78, 93, 110, + 125, 139, 155, 170, 188, 206, 224, 240, + 8, 15, 34, 50, 67, 83, 99, 115, + 131, 146, 162, 178, 193, 209, 224, 239, + 13, 16, 41, 66, 73, 86, 95, 111, + 128, 137, 150, 163, 183, 206, 225, 241, + 17, 25, 37, 52, 63, 75, 92, 102, + 119, 132, 144, 160, 175, 191, 212, 231, + 19, 31, 49, 65, 83, 100, 117, 133, + 147, 161, 174, 187, 200, 213, 227, 242, + 18, 31, 52, 68, 88, 103, 117, 126, + 138, 149, 163, 177, 192, 207, 223, 239, + 16, 29, 47, 61, 76, 90, 106, 119, + 133, 147, 161, 176, 193, 209, 224, 240, + 15, 21, 35, 50, 61, 73, 86, 97, + 110, 119, 129, 141, 175, 198, 218, 237 +}; + +static const opus_int16 silk_NLSF_CB1_WB_Wght_Q9[ 512 ] = { + 3657, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2925, 2963, 2963, 2925, 2846, + 3216, 3085, 2972, 3056, 3056, 3010, 3010, 3010, 2963, 2963, 3010, 2972, 2888, 2846, 2846, 2726, + 3920, 4014, 2981, 3207, 3207, 2934, 3056, 2846, 3122, 3244, 2925, 2846, 2620, 2553, 2780, 2925, + 3516, 3197, 3010, 3103, 3019, 2888, 2925, 2925, 2925, 2925, 2888, 2888, 2888, 2888, 2888, 2753, + 5054, 5054, 2934, 3573, 3385, 3056, 3085, 2793, 3160, 3160, 2972, 2846, 2513, 2540, 2753, 2888, + 4428, 4149, 2700, 2753, 2972, 3010, 2925, 2846, 2981, 3019, 2925, 2925, 2925, 2925, 2888, 2726, + 3620, 3019, 2972, 3056, 3056, 2873, 2806, 3056, 3216, 3047, 2981, 3291, 3291, 2981, 3310, 2991, + 5227, 5014, 2540, 3338, 3526, 3385, 3197, 3094, 3376, 2981, 2700, 2647, 2687, 2793, 2846, 2673, + 5081, 5174, 4615, 4428, 2460, 2897, 3047, 3207, 3169, 2687, 2740, 2888, 2846, 2793, 2846, 2700, + 3122, 2888, 2963, 2925, 2925, 2925, 2925, 2963, 2963, 2963, 2963, 2925, 2925, 2963, 2963, 2963, + 4202, 3207, 2981, 3103, 3010, 2888, 2888, 2925, 2972, 2873, 2916, 3019, 2972, 3010, 3197, 2873, + 3760, 3760, 3244, 3103, 2981, 2888, 2925, 2888, 2972, 2934, 2793, 2793, 2846, 2888, 2888, 2660, + 3854, 4014, 3207, 3122, 3244, 2934, 3047, 2963, 2963, 3085, 2846, 2793, 2793, 2793, 2793, 2580, + 3845, 4080, 3357, 3516, 3094, 2740, 3010, 2934, 3122, 3085, 2846, 2846, 2647, 2647, 2846, 2806, + 5147, 4894, 3225, 3845, 3441, 3169, 2897, 3413, 3451, 2700, 2580, 2673, 2740, 2846, 2806, 2753, + 4109, 3789, 3291, 3160, 2925, 2888, 2888, 2925, 2793, 2740, 2793, 2740, 2793, 2846, 2888, 2806, + 5081, 5054, 3047, 3545, 3244, 3056, 3085, 2944, 3103, 2897, 2740, 2740, 2740, 2846, 2793, 2620, + 4309, 4309, 2860, 2527, 3207, 3376, 3376, 3075, 3075, 3376, 3056, 2846, 2647, 2580, 2726, 2753, + 3056, 2916, 2806, 2888, 2740, 2687, 2897, 3103, 3150, 3150, 3216, 3169, 3056, 3010, 2963, 2846, + 4375, 3882, 2925, 2888, 2846, 2888, 2846, 2846, 2888, 2888, 2888, 2846, 2888, 2925, 2888, 2846, + 2981, 2916, 2916, 2981, 2981, 3056, 3122, 3216, 3150, 3056, 3010, 2972, 2972, 2972, 2925, 2740, + 4229, 4149, 3310, 3347, 2925, 2963, 2888, 2981, 2981, 2846, 2793, 2740, 2846, 2846, 2846, 2793, + 4080, 4014, 3103, 3010, 2925, 2925, 2925, 2888, 2925, 2925, 2846, 2846, 2846, 2793, 2888, 2780, + 4615, 4575, 3169, 3441, 3207, 2981, 2897, 3038, 3122, 2740, 2687, 2687, 2687, 2740, 2793, 2700, + 4149, 4269, 3789, 3657, 2726, 2780, 2888, 2888, 3010, 2972, 2925, 2846, 2687, 2687, 2793, 2888, + 4215, 3554, 2753, 2846, 2846, 2888, 2888, 2888, 2925, 2925, 2888, 2925, 2925, 2925, 2963, 2888, + 5174, 4921, 2261, 3432, 3789, 3479, 3347, 2846, 3310, 3479, 3150, 2897, 2460, 2487, 2753, 2925, + 3451, 3685, 3122, 3197, 3357, 3047, 3207, 3207, 2981, 3216, 3085, 2925, 2925, 2687, 2540, 2434, + 2981, 3010, 2793, 2793, 2740, 2793, 2846, 2972, 3056, 3103, 3150, 3150, 3150, 3103, 3010, 3010, + 2944, 2873, 2687, 2726, 2780, 3010, 3432, 3545, 3357, 3244, 3056, 3010, 2963, 2925, 2888, 2846, + 3019, 2944, 2897, 3010, 3010, 2972, 3019, 3103, 3056, 3056, 3010, 2888, 2846, 2925, 2925, 2888, + 3920, 3967, 3010, 3197, 3357, 3216, 3291, 3291, 3479, 3704, 3441, 2726, 2181, 2460, 2580, 2607 +}; + +static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = { + 225, 204, 201, 184, 183, 175, 158, 154, + 153, 135, 119, 115, 113, 110, 109, 99, + 98, 95, 79, 68, 52, 50, 48, 45, + 43, 32, 31, 27, 18, 10, 3, 0, + 255, 251, 235, 230, 212, 201, 196, 182, + 167, 166, 163, 151, 138, 124, 110, 104, + 90, 78, 76, 70, 69, 57, 45, 34, + 24, 21, 11, 6, 5, 4, 3, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 100, 102, 102, 68, 68, 36, 34, 96, + 164, 107, 158, 185, 180, 185, 139, 102, + 64, 66, 36, 34, 34, 0, 1, 32, + 208, 139, 141, 191, 152, 185, 155, 104, + 96, 171, 104, 166, 102, 102, 102, 132, + 1, 0, 0, 0, 0, 16, 16, 0, + 80, 109, 78, 107, 185, 139, 103, 101, + 208, 212, 141, 139, 173, 153, 123, 103, + 36, 0, 0, 0, 0, 0, 0, 1, + 48, 0, 0, 0, 0, 0, 0, 32, + 68, 135, 123, 119, 119, 103, 69, 98, + 68, 103, 120, 118, 118, 102, 71, 98, + 134, 136, 157, 184, 182, 153, 139, 134, + 208, 168, 248, 75, 189, 143, 121, 107, + 32, 49, 34, 34, 34, 0, 17, 2, + 210, 235, 139, 123, 185, 137, 105, 134, + 98, 135, 104, 182, 100, 183, 171, 134, + 100, 70, 68, 70, 66, 66, 34, 131, + 64, 166, 102, 68, 36, 2, 1, 0, + 134, 166, 102, 68, 34, 34, 66, 132, + 212, 246, 158, 139, 107, 107, 87, 102, + 100, 219, 125, 122, 137, 118, 103, 132, + 114, 135, 137, 105, 171, 106, 50, 34, + 164, 214, 141, 143, 185, 151, 121, 103, + 192, 34, 0, 0, 0, 0, 0, 1, + 208, 109, 74, 187, 134, 249, 159, 137, + 102, 110, 154, 118, 87, 101, 119, 101, + 0, 2, 0, 36, 36, 66, 68, 35, + 96, 164, 102, 100, 36, 0, 2, 33, + 167, 138, 174, 102, 100, 84, 2, 2, + 100, 107, 120, 119, 36, 197, 24, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = { + 255, 254, 253, 244, 12, 3, 2, 1, + 0, 255, 254, 252, 224, 38, 3, 2, + 1, 0, 255, 254, 251, 209, 57, 4, + 2, 1, 0, 255, 254, 244, 195, 69, + 4, 2, 1, 0, 255, 251, 232, 184, + 84, 7, 2, 1, 0, 255, 254, 240, + 186, 86, 14, 2, 1, 0, 255, 254, + 239, 178, 91, 30, 5, 1, 0, 255, + 248, 227, 177, 100, 19, 2, 1, 0 +}; + +static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = { + 255, 255, 255, 156, 4, 154, 255, 255, + 255, 255, 255, 227, 102, 15, 92, 255, + 255, 255, 255, 255, 213, 83, 24, 72, + 236, 255, 255, 255, 255, 150, 76, 33, + 63, 214, 255, 255, 255, 190, 121, 77, + 43, 55, 185, 255, 255, 255, 245, 137, + 71, 43, 59, 139, 255, 255, 255, 255, + 131, 66, 50, 66, 107, 194, 255, 255, + 166, 116, 76, 55, 53, 125, 255, 255 +}; + +static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = { + 175, 148, 160, 176, 178, 173, 174, 164, + 177, 174, 196, 182, 198, 192, 182, 68, + 62, 66, 60, 72, 117, 85, 90, 118, + 136, 151, 142, 160, 142, 155 +}; + +static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = { + 100, 3, 40, 3, 3, 3, 5, 14, + 14, 10, 11, 3, 8, 9, 7, 3, + 347 +}; + +const silk_NLSF_CB_struct silk_NLSF_CB_WB = +{ + 32, + 16, + SILK_FIX_CONST( 0.15, 16 ), + SILK_FIX_CONST( 1.0 / 0.15, 6 ), + silk_NLSF_CB1_WB_Q8, + silk_NLSF_CB1_WB_Wght_Q9, + silk_NLSF_CB1_iCDF_WB, + silk_NLSF_PRED_WB_Q8, + silk_NLSF_CB2_SELECT_WB, + silk_NLSF_CB2_iCDF_WB, + silk_NLSF_CB2_BITS_WB_Q5, + silk_NLSF_DELTA_MIN_WB_Q15, +}; + diff --git a/src/libopus/silk/tables_gain.c b/src/libopus/silk/tables_gain.c new file mode 100644 index 00000000..b79eb2b1 --- /dev/null +++ b/src/libopus/silk/tables_gain.c @@ -0,0 +1,63 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] = +{ +{ + 224, 112, 44, 15, 3, 2, 1, 0 +}, +{ + 254, 237, 192, 132, 70, 23, 4, 0 +}, +{ + 255, 252, 226, 155, 61, 11, 2, 0 +} +}; + +const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = { + 250, 245, 234, 203, 71, 50, 42, 38, + 35, 33, 31, 29, 28, 27, 26, 25, + 24, 23, 22, 21, 20, 19, 18, 17, + 16, 15, 14, 13, 12, 11, 10, 9, + 8, 7, 6, 5, 4, 3, 2, 1, + 0 +}; + +#ifdef __cplusplus +} +#endif diff --git a/src/libopus/silk/tables_other.c b/src/libopus/silk/tables_other.c new file mode 100644 index 00000000..a15c06e0 --- /dev/null +++ b/src/libopus/silk/tables_other.c @@ -0,0 +1,124 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "structs.h" +#include "define.h" +#include "tables.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Tables for stereo predictor coding */ +const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = { + -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820, + 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732 +}; +const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = { + 249, 247, 246, 245, 244, + 234, 210, 202, 201, 200, + 197, 174, 82, 59, 56, + 55, 54, 46, 22, 12, + 11, 10, 9, 7, 0 +}; +const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 }; + +/* Tables for LBRR flags */ +static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 }; +static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 }; +const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = { + silk_LBRR_flags_2_iCDF, + silk_LBRR_flags_3_iCDF +}; + +/* Table for LSB coding */ +const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 }; + +/* Tables for LTPScale */ +const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 }; + +/* Tables for signal type and offset coding */ +const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = { + 232, 158, 10, 0 +}; +const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = { + 230, 0 +}; + +/* Tables for NLSF interpolation factor */ +const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 }; + +/* Quantization offsets */ +const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = { + { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 } +}; + +/* Table for LTPScale */ +const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 }; + +/* Uniform entropy tables */ +const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 }; +const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 }; +const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 }; +const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 }; +const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 }; + +const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 }; + +/* Elliptic/Cauer filters designed with 0.1 dB passband ripple, + 80 dB minimum stopband attenuation, and + [0.95 : 0.15 : 0.35] normalized cut off frequencies. */ + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] = +{ +{ 250767114, 501534038, 250767114 }, +{ 209867381, 419732057, 209867381 }, +{ 170987846, 341967853, 170987846 }, +{ 131531482, 263046905, 131531482 }, +{ 89306658, 178584282, 89306658 } +}; + +/* Interpolation points for filter coefficients used in the bandwidth transition smoother */ +const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] = +{ +{ 506393414, 239854379 }, +{ 411067935, 169683996 }, +{ 306733530, 116694253 }, +{ 185807084, 77959395 }, +{ 35497197, 57401098 } +}; + +#ifdef __cplusplus +} +#endif + diff --git a/src/libopus/silk/tables_pitch_lag.c b/src/libopus/silk/tables_pitch_lag.c new file mode 100644 index 00000000..50701a18 --- /dev/null +++ b/src/libopus/silk/tables_pitch_lag.c @@ -0,0 +1,69 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "tables.h" + +const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = { + 253, 250, 244, 233, 212, 182, 150, 131, + 120, 110, 98, 85, 72, 60, 49, 40, + 32, 25, 19, 15, 13, 11, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_pitch_delta_iCDF[21] = { + 210, 208, 206, 203, 199, 193, 183, 168, + 142, 104, 74, 52, 37, 27, 20, 14, + 10, 6, 4, 2, 0 +}; + +const opus_uint8 silk_pitch_contour_iCDF[34] = { + 223, 201, 183, 167, 152, 138, 124, 111, + 98, 88, 79, 70, 62, 56, 50, 44, + 39, 35, 31, 27, 24, 21, 18, 16, + 14, 12, 10, 8, 6, 4, 3, 2, + 1, 0 +}; + +const opus_uint8 silk_pitch_contour_NB_iCDF[11] = { + 188, 176, 155, 138, 119, 97, 67, 43, + 26, 10, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = { + 165, 119, 80, 61, 47, 35, 27, 20, + 14, 9, 4, 0 +}; + +const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = { + 113, 63, 0 +}; + + diff --git a/src/libopus/silk/tables_pulses_per_block.c b/src/libopus/silk/tables_pulses_per_block.c new file mode 100644 index 00000000..fd22b3ee --- /dev/null +++ b/src/libopus/silk/tables_pulses_per_block.c @@ -0,0 +1,264 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +//#ifdef HAVE_CONFIG_H +#include "../config.h" +//#endif + +#include "tables.h" + +const opus_uint8 silk_max_pulses_table[ 4 ] = { + 8, 10, 12, 16 +}; + +const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = { +{ + 125, 51, 26, 18, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 198, 105, 45, 22, 15, 12, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 213, 162, 116, 83, 59, 43, 32, 24, + 18, 15, 12, 9, 7, 6, 5, 3, + 2, 0 +}, +{ + 239, 187, 116, 59, 28, 16, 11, 10, + 9, 8, 7, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 250, 229, 188, 135, 86, 51, 30, 19, + 13, 10, 8, 6, 5, 4, 3, 2, + 1, 0 +}, +{ + 249, 235, 213, 185, 156, 128, 103, 83, + 66, 53, 42, 33, 26, 21, 17, 13, + 10, 0 +}, +{ + 254, 249, 235, 206, 164, 118, 77, 46, + 27, 16, 10, 7, 5, 4, 3, 2, + 1, 0 +}, +{ + 255, 253, 249, 239, 220, 191, 156, 119, + 85, 57, 37, 23, 15, 10, 6, 4, + 2, 0 +}, +{ + 255, 253, 251, 246, 237, 223, 203, 179, + 152, 124, 98, 75, 55, 40, 29, 21, + 15, 0 +}, +{ + 255, 254, 253, 247, 220, 162, 106, 67, + 42, 28, 18, 12, 9, 6, 4, 3, + 2, 0 +} +}; + +const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = { +{ + 31, 57, 107, 160, 205, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 69, 47, 67, 111, 166, 205, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 82, 74, 79, 95, 109, 128, 145, 160, + 173, 205, 205, 205, 224, 255, 255, 224, + 255, 224 +}, +{ + 125, 74, 59, 69, 97, 141, 182, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255 +}, +{ + 173, 115, 85, 73, 76, 92, 115, 145, + 173, 205, 224, 224, 255, 255, 255, 255, + 255, 255 +}, +{ + 166, 134, 113, 102, 101, 102, 107, 118, + 125, 138, 145, 155, 166, 182, 192, 192, + 205, 150 +}, +{ + 224, 182, 134, 101, 83, 79, 85, 97, + 120, 145, 173, 205, 224, 255, 255, 255, + 255, 255 +}, +{ + 255, 224, 192, 150, 120, 101, 92, 89, + 93, 102, 118, 134, 160, 182, 192, 224, + 224, 224 +}, +{ + 255, 224, 224, 182, 155, 134, 118, 109, + 104, 102, 106, 111, 118, 131, 145, 160, + 173, 131 +} +}; + +const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] = +{ +{ + 241, 190, 178, 132, 87, 74, 41, 14, + 0 +}, +{ + 223, 193, 157, 140, 106, 57, 39, 18, + 0 +} +}; + +const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] = +{ +{ + 131, 74, 141, 79, 80, 138, 95, 104, + 134 +}, +{ + 95, 99, 91, 125, 93, 76, 123, 115, + 123 +} +}; + +const opus_uint8 silk_shell_code_table0[ 152 ] = { + 128, 0, 214, 42, 0, 235, 128, 21, + 0, 244, 184, 72, 11, 0, 248, 214, + 128, 42, 7, 0, 248, 225, 170, 80, + 25, 5, 0, 251, 236, 198, 126, 54, + 18, 3, 0, 250, 238, 211, 159, 82, + 35, 15, 5, 0, 250, 231, 203, 168, + 128, 88, 53, 25, 6, 0, 252, 238, + 216, 185, 148, 108, 71, 40, 18, 4, + 0, 253, 243, 225, 199, 166, 128, 90, + 57, 31, 13, 3, 0, 254, 246, 233, + 212, 183, 147, 109, 73, 44, 23, 10, + 2, 0, 255, 250, 240, 223, 198, 166, + 128, 90, 58, 33, 16, 6, 1, 0, + 255, 251, 244, 231, 210, 181, 146, 110, + 75, 46, 25, 12, 5, 1, 0, 255, + 253, 248, 238, 221, 196, 164, 128, 92, + 60, 35, 18, 8, 3, 1, 0, 255, + 253, 249, 242, 229, 208, 180, 146, 110, + 76, 48, 27, 14, 7, 3, 1, 0 +}; + +const opus_uint8 silk_shell_code_table1[ 152 ] = { + 129, 0, 207, 50, 0, 236, 129, 20, + 0, 245, 185, 72, 10, 0, 249, 213, + 129, 42, 6, 0, 250, 226, 169, 87, + 27, 4, 0, 251, 233, 194, 130, 62, + 20, 4, 0, 250, 236, 207, 160, 99, + 47, 17, 3, 0, 255, 240, 217, 182, + 131, 81, 41, 11, 1, 0, 255, 254, + 233, 201, 159, 107, 61, 20, 2, 1, + 0, 255, 249, 233, 206, 170, 128, 86, + 50, 23, 7, 1, 0, 255, 250, 238, + 217, 186, 148, 108, 70, 39, 18, 6, + 1, 0, 255, 252, 243, 226, 200, 166, + 128, 90, 56, 30, 13, 4, 1, 0, + 255, 252, 245, 231, 209, 180, 146, 110, + 76, 47, 25, 11, 4, 1, 0, 255, + 253, 248, 237, 219, 194, 163, 128, 93, + 62, 37, 19, 8, 3, 1, 0, 255, + 254, 250, 241, 226, 205, 177, 145, 111, + 79, 51, 30, 15, 6, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table2[ 152 ] = { + 129, 0, 203, 54, 0, 234, 129, 23, + 0, 245, 184, 73, 10, 0, 250, 215, + 129, 41, 5, 0, 252, 232, 173, 86, + 24, 3, 0, 253, 240, 200, 129, 56, + 15, 2, 0, 253, 244, 217, 164, 94, + 38, 10, 1, 0, 253, 245, 226, 189, + 132, 71, 27, 7, 1, 0, 253, 246, + 231, 203, 159, 105, 56, 23, 6, 1, + 0, 255, 248, 235, 213, 179, 133, 85, + 47, 19, 5, 1, 0, 255, 254, 243, + 221, 194, 159, 117, 70, 37, 12, 2, + 1, 0, 255, 254, 248, 234, 208, 171, + 128, 85, 48, 22, 8, 2, 1, 0, + 255, 254, 250, 240, 220, 189, 149, 107, + 67, 36, 16, 6, 2, 1, 0, 255, + 254, 251, 243, 227, 201, 166, 128, 90, + 55, 29, 13, 5, 2, 1, 0, 255, + 254, 252, 246, 234, 213, 183, 147, 109, + 73, 43, 22, 10, 4, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table3[ 152 ] = { + 130, 0, 200, 58, 0, 231, 130, 26, + 0, 244, 184, 76, 12, 0, 249, 214, + 130, 43, 6, 0, 252, 232, 173, 87, + 24, 3, 0, 253, 241, 203, 131, 56, + 14, 2, 0, 254, 246, 221, 167, 94, + 35, 8, 1, 0, 254, 249, 232, 193, + 130, 65, 23, 5, 1, 0, 255, 251, + 239, 211, 162, 99, 45, 15, 4, 1, + 0, 255, 251, 243, 223, 186, 131, 74, + 33, 11, 3, 1, 0, 255, 252, 245, + 230, 202, 158, 105, 57, 24, 8, 2, + 1, 0, 255, 253, 247, 235, 214, 179, + 132, 84, 44, 19, 7, 2, 1, 0, + 255, 254, 250, 240, 223, 196, 159, 112, + 69, 36, 15, 6, 2, 1, 0, 255, + 254, 253, 245, 231, 209, 176, 136, 93, + 55, 27, 11, 3, 2, 1, 0, 255, + 254, 253, 252, 239, 221, 194, 158, 117, + 76, 42, 18, 4, 3, 2, 1, 0 +}; + +const opus_uint8 silk_shell_code_table_offsets[ 17 ] = { + 0, 0, 2, 5, 9, 14, 20, 27, + 35, 44, 54, 65, 77, 90, 104, 119, + 135 +}; + +const opus_uint8 silk_sign_iCDF[ 42 ] = { + 254, 49, 67, 77, 82, 93, 99, + 198, 11, 18, 24, 31, 36, 45, + 255, 46, 66, 78, 87, 94, 104, + 208, 14, 21, 32, 42, 51, 66, + 255, 94, 104, 109, 112, 115, 118, + 248, 53, 69, 80, 88, 95, 102 +}; diff --git a/src/libopus/silk/tuning_parameters.h b/src/libopus/silk/tuning_parameters.h new file mode 100644 index 00000000..d70275fd --- /dev/null +++ b/src/libopus/silk/tuning_parameters.h @@ -0,0 +1,155 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TUNING_PARAMETERS_H +#define SILK_TUNING_PARAMETERS_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Decay time for bitreservoir */ +#define BITRESERVOIR_DECAY_TIME_MS 500 + +/*******************/ +/* Pitch estimator */ +/*******************/ + +/* Level of noise floor for whitening filter LPC analysis in pitch analysis */ +#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f + +/* Bandwidth expansion for whitening filter in pitch analysis */ +#define FIND_PITCH_BANDWIDTH_EXPANSION 0.99f + +/*********************/ +/* Linear prediction */ +/*********************/ + +/* LPC analysis regularization */ +#define FIND_LPC_COND_FAC 1e-5f + +/* Max cumulative LTP gain */ +#define MAX_SUM_LOG_GAIN_DB 250.0f + +/* LTP analysis defines */ +#define LTP_CORR_INV_MAX 0.03f + +/***********************/ +/* High pass filtering */ +/***********************/ + +/* Smoothing parameters for low end of pitch frequency range estimation */ +#define VARIABLE_HP_SMTH_COEF1 0.1f +#define VARIABLE_HP_SMTH_COEF2 0.015f +#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f + +/* Min and max cut-off frequency values (-3 dB points) */ +#define VARIABLE_HP_MIN_CUTOFF_HZ 60 +#define VARIABLE_HP_MAX_CUTOFF_HZ 100 + +/***********/ +/* Various */ +/***********/ + +/* VAD threshold */ +#define SPEECH_ACTIVITY_DTX_THRES 0.05f + +/* Speech Activity LBRR enable threshold */ +#define LBRR_SPEECH_ACTIVITY_THRES 0.3f + +/*************************/ +/* Perceptual parameters */ +/*************************/ + +/* reduction in coding SNR during low speech activity */ +#define BG_SNR_DECR_dB 2.0f + +/* factor for reducing quantization noise during voiced speech */ +#define HARM_SNR_INCR_dB 2.0f + +/* factor for reducing quantization noise for unvoiced sparse signals */ +#define SPARSE_SNR_INCR_dB 2.0f + +/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */ +#define ENERGY_VARIATION_THRESHOLD_QNT_OFFSET 0.6f + +/* warping control */ +#define WARPING_MULTIPLIER 0.015f + +/* fraction added to first autocorrelation value */ +#define SHAPE_WHITE_NOISE_FRACTION 3e-5f + +/* noise shaping filter chirp factor */ +#define BANDWIDTH_EXPANSION 0.94f + +/* harmonic noise shaping */ +#define HARMONIC_SHAPING 0.3f + +/* extra harmonic noise shaping for high bitrates or noisy input */ +#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f + +/* parameter for shaping noise towards higher frequencies */ +#define HP_NOISE_COEF 0.25f + +/* parameter for shaping noise even more towards higher frequencies during voiced speech */ +#define HARM_HP_NOISE_COEF 0.35f + +/* parameter for applying a high-pass tilt to the input signal */ +#define INPUT_TILT 0.05f + +/* parameter for extra high-pass tilt to the input signal at high rates */ +#define HIGH_RATE_INPUT_TILT 0.1f + +/* parameter for reducing noise at the very low frequencies */ +#define LOW_FREQ_SHAPING 4.0f + +/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */ +#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f + +/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */ +#define SUBFR_SMTH_COEF 0.4f + +/* parameters defining the R/D tradeoff in the residual quantizer */ +#define LAMBDA_OFFSET 1.2f +#define LAMBDA_SPEECH_ACT -0.2f +#define LAMBDA_DELAYED_DECISIONS -0.05f +#define LAMBDA_INPUT_QUALITY -0.1f +#define LAMBDA_CODING_QUALITY -0.2f +#define LAMBDA_QUANT_OFFSET 0.8f + +/* Compensation in bitrate calculations for 10 ms modes */ +#define REDUCE_BITRATE_10_MS_BPS 2200 + +/* Maximum time before allowing a bandwidth transition */ +#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000 + +#ifdef __cplusplus +} +#endif + +#endif /* SILK_TUNING_PARAMETERS_H */ diff --git a/src/libopus/silk/typedef.h b/src/libopus/silk/typedef.h new file mode 100644 index 00000000..58ef72bf --- /dev/null +++ b/src/libopus/silk/typedef.h @@ -0,0 +1,78 @@ +/*********************************************************************** +Copyright (c) 2006-2011, Skype Limited. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +- Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +- Neither the name of Internet Society, IETF or IETF Trust, nor the +names of specific contributors, may be used to endorse or promote +products derived from this software without specific prior written +permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +***********************************************************************/ + +#ifndef SILK_TYPEDEF_H +#define SILK_TYPEDEF_H + +#include "../opus_types.h" +#include "../opus_defines.h" + +#ifndef FIXED_POINT +# include +# define silk_float float +# define silk_float_MAX FLT_MAX +#endif + +#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */ +#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */ +#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */ +#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */ +#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */ +#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */ +#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */ +#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */ +#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */ + +#define silk_TRUE 1 +#define silk_FALSE 0 + +/* assertions */ +#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS)) +# ifndef silk_assert +# include /* ASSERTE() */ +# define silk_assert(COND) _ASSERTE(COND) +# endif +#else +# ifdef ENABLE_ASSERTIONS +# include +# include +#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__); +#ifdef __GNUC__ +__attribute__((noreturn)) +#endif +static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line) +{ + fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str); + abort(); +} +# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}} +# else +# define silk_assert(COND) +# endif +#endif + +#endif /* SILK_TYPEDEF_H */ diff --git a/src/libopus/tansig_table.h b/src/libopus/tansig_table.h new file mode 100644 index 00000000..c76f844a --- /dev/null +++ b/src/libopus/tansig_table.h @@ -0,0 +1,45 @@ +/* This file is auto-generated by gen_tables */ + +static const float tansig_table[201] = { +0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f, +0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f, +0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f, +0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f, +0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f, +0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f, +0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f, +0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f, +0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f, +0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f, +0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f, +0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f, +0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f, +0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f, +0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f, +0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f, +0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f, +0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f, +0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f, +0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f, +0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f, +0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f, +0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f, +0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f, +0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f, +0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f, +0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f, +0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f, +0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f, +0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f, +0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f, +0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f, +0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f, +0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f, +0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f, +0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f, +0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, +0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f, +1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, +1.000000f, +}; diff --git a/src/opusfile/AUTHORS b/src/opusfile/AUTHORS new file mode 100644 index 00000000..d0ac09d6 --- /dev/null +++ b/src/opusfile/AUTHORS @@ -0,0 +1,5 @@ +Timothy B. Terriberry +Ralph Giles +Christopher "Monty" Montgomery (original libvorbisfile) +Gregory Maxwell (noise shaping dithering) +nu774 (original winsock support) diff --git a/src/opusfile/COPYING b/src/opusfile/COPYING new file mode 100644 index 00000000..7b53d665 --- /dev/null +++ b/src/opusfile/COPYING @@ -0,0 +1,28 @@ +Copyright (c) 1994-2013 Xiph.Org Foundation and contributors + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +- Neither the name of the Xiph.Org Foundation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION +OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/opusfile/README.esp8266.md b/src/opusfile/README.esp8266.md new file mode 100644 index 00000000..267aa28a --- /dev/null +++ b/src/opusfile/README.esp8266.md @@ -0,0 +1,3 @@ +This is opusfile from Xiph, modified to build under Arduino by and adjusted to work with AudioFileSources, + +Original license/etc. unchanged. diff --git a/src/opusfile/README.md b/src/opusfile/README.md new file mode 100644 index 00000000..609cc6b9 --- /dev/null +++ b/src/opusfile/README.md @@ -0,0 +1,18 @@ +# Opusfile + +[![GitLab Pipeline Status](https://gitlab.xiph.org/xiph/opusfile/badges/master/pipeline.svg)](https://gitlab.xiph.org/xiph/opusfile/commits/master) +[![Travis Build Status](https://travis-ci.org/xiph/opusfile.svg?branch=master)](https://travis-ci.org/xiph/opusfile) +[![AppVeyor Build Status](https://ci.appveyor.com/api/projects/status/github/xiph/opusfile?branch=master&svg=true)](https://ci.appveyor.com/project/rillian/opusfile) + +The opusfile and opusurl libraries provide a high-level API for +decoding and seeking within .opus files on disk or over http(s). + +opusfile depends on libopus and libogg. +opusurl depends on opusfile and openssl. + +The library is functional, but there are likely issues +we didn't find in our own testing. Please give feedback +in #opus on irc.freenode.net or at opus@xiph.org. + +Programming documentation is available in tree and online at +https://opus-codec.org/docs/ diff --git a/src/opusfile/config.h b/src/opusfile/config.h new file mode 100644 index 00000000..47d57494 --- /dev/null +++ b/src/opusfile/config.h @@ -0,0 +1,128 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_DLFCN_H 0 + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 0 + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR ".libs/" + +/* Disable floating-point API */ +#define OP_DISABLE_FLOAT_API 1 + +/* Enable assertions in code */ +/* #undef OP_ENABLE_ASSERTIONS */ + +/* Enable HTTP support */ +/* #undef OP_ENABLE_HTTP */ + +/* Enable fixed-point calculation */ +#define OP_FIXED_POINT 1 + +/* Enable use of clock_gettime function */ +/* #undef OP_HAVE_CLOCK_GETTIME */ + +/* Enable use of lrintf function */ +/* #undef OP_HAVE_LRINTF */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "opus@xiph.org" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "opusfile" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "opusfile 0.12" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "opusfile" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "0.12" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define this if the compiler supports __attribute__(( + ifelse([visibility("default")], , [visibility_default], + [visibility("default")]) )) */ +#define SUPPORT_ATTRIBUTE_VISIBILITY_DEFAULT 1 + +/* Define this if the compiler supports the -fvisibility flag */ +#define SUPPORT_FLAG_VISIBILITY 1 + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# define _ALL_SOURCE 1 +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# define _POSIX_PTHREAD_SEMANTICS 1 +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# define _TANDEM_SOURCE 1 +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# define __EXTENSIONS__ 1 +#endif + + +/* Enable large inode numbers on Mac OS X 10.5. */ +#ifndef _DARWIN_USE_64_BIT_INODE +# define _DARWIN_USE_64_BIT_INODE 1 +#endif + +/* Number of bits in a file offset, on hosts where this is settable. */ +/* #undef _FILE_OFFSET_BITS */ + +/* Define for large files, on AIX-style hosts. */ +/* #undef _LARGE_FILES */ + +/* Define to 1 if on MINIX. */ +/* #undef _MINIX */ + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* We need at least WindowsXP for getaddrinfo/freeaddrinfo */ +/* #undef _WIN32_WINNT */ diff --git a/src/opusfile/info.c b/src/opusfile/info.c new file mode 100644 index 00000000..106e6047 --- /dev/null +++ b/src/opusfile/info.c @@ -0,0 +1,775 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012-2020 * + * by the Xiph.Org Foundation and contributors https://xiph.org/ * + * * + ********************************************************************/ +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "internal.h" +#include +#include + +static unsigned op_parse_uint16le(const unsigned char *_data){ + return _data[0]|_data[1]<<8; +} + +static int op_parse_int16le(const unsigned char *_data){ + int ret; + ret=_data[0]|_data[1]<<8; + return (ret^0x8000)-0x8000; +} + +static opus_uint32 op_parse_uint32le(const unsigned char *_data){ + return _data[0]|(opus_uint32)_data[1]<<8| + (opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24; +} + +static opus_uint32 op_parse_uint32be(const unsigned char *_data){ + return _data[3]|(opus_uint32)_data[2]<<8| + (opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24; +} + +int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){ + OpusHead head; + if(_len<8)return OP_ENOTFORMAT; + if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT; + if(_len<9)return OP_EBADHEADER; + head.version=_data[8]; + if(head.version>15)return OP_EVERSION; + if(_len<19)return OP_EBADHEADER; + head.channel_count=_data[9]; + head.pre_skip=op_parse_uint16le(_data+10); + head.input_sample_rate=op_parse_uint32le(_data+12); + head.output_gain=op_parse_int16le(_data+16); + head.mapping_family=_data[18]; + if(head.mapping_family==0){ + if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER; + if(head.version<=1&&_len>19)return OP_EBADHEADER; + head.stream_count=1; + head.coupled_count=head.channel_count-1; + if(_head!=NULL){ + _head->mapping[0]=0; + _head->mapping[1]=1; + } + } + else if(head.mapping_family==1){ + size_t size; + int ci; + if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER; + size=21+head.channel_count; + if(_lensize)return OP_EBADHEADER; + head.stream_count=_data[19]; + if(head.stream_count<1)return OP_EBADHEADER; + head.coupled_count=_data[20]; + if(head.coupled_count>head.stream_count)return OP_EBADHEADER; + for(ci=0;ci=head.stream_count+head.coupled_count + &&_data[21+ci]!=255){ + return OP_EBADHEADER; + } + } + if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count); + } + /*General purpose players should not attempt to play back content with + channel mapping family 255.*/ + else if(head.mapping_family==255)return OP_EIMPL; + /*No other channel mapping families are currently defined.*/ + else return OP_EBADHEADER; + if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head); + return 0; +} + +void opus_tags_init(OpusTags *_tags){ + memset(_tags,0,sizeof(*_tags)); +} + +void opus_tags_clear(OpusTags *_tags){ + int ncomments; + int ci; + ncomments=_tags->comments; + if(_tags->user_comments!=NULL)ncomments++; + else{ + OP_ASSERT(ncomments==0); + } + for(ci=ncomments;ci-->0;)_ogg_free(_tags->user_comments[ci]); + _ogg_free(_tags->user_comments); + _ogg_free(_tags->comment_lengths); + _ogg_free(_tags->vendor); +} + +/*Ensure there's room for up to _ncomments comments.*/ +static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){ + char **user_comments; + int *comment_lengths; + int cur_ncomments; + size_t size; + if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT; + size=sizeof(*_tags->comment_lengths)*(_ncomments+1); + if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT; + cur_ncomments=_tags->comments; + /*We only support growing. + Trimming requires cleaning up the allocated strings in the old space, and + is best handled separately if it's ever needed.*/ + OP_ASSERT(_ncomments>=(size_t)cur_ncomments); + comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size); + if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT; + if(_tags->comment_lengths==NULL){ + OP_ASSERT(cur_ncomments==0); + comment_lengths[cur_ncomments]=0; + } + comment_lengths[_ncomments]=comment_lengths[cur_ncomments]; + _tags->comment_lengths=comment_lengths; + size=sizeof(*_tags->user_comments)*(_ncomments+1); + if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT; + user_comments=(char **)_ogg_realloc(_tags->user_comments,size); + if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT; + if(_tags->user_comments==NULL){ + OP_ASSERT(cur_ncomments==0); + user_comments[cur_ncomments]=NULL; + } + user_comments[_ncomments]=user_comments[cur_ncomments]; + _tags->user_comments=user_comments; + return 0; +} + +/*Duplicate a (possibly non-NUL terminated) string with a known length.*/ +static char *op_strdup_with_len(const char *_s,size_t _len){ + size_t size; + char *ret; + size=sizeof(*ret)*(_len+1); + if(OP_UNLIKELY(size<_len))return NULL; + ret=(char *)_ogg_malloc(size); + if(OP_LIKELY(ret!=NULL)){ + ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len); + ret[_len]='\0'; + } + return ret; +} + +/*The actual implementation of opus_tags_parse(). + Unlike the public API, this function requires _tags to already be + initialized, modifies its contents before success is guaranteed, and assumes + the caller will clear it on error.*/ +static int opus_tags_parse_impl(OpusTags *_tags, + const unsigned char *_data,size_t _len){ + opus_uint32 count; + size_t len; + int ncomments; + int ci; + len=_len; + if(len<8)return OP_ENOTFORMAT; + if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT; + if(len<16)return OP_EBADHEADER; + _data+=8; + len-=8; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + if(count>len)return OP_EBADHEADER; + if(_tags!=NULL){ + _tags->vendor=op_strdup_with_len((char *)_data,count); + if(_tags->vendor==NULL)return OP_EFAULT; + } + _data+=count; + len-=count; + if(len<4)return OP_EBADHEADER; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + /*Check to make sure there's minimally sufficient data left in the packet.*/ + if(count>len>>2)return OP_EBADHEADER; + /*Check for overflow (the API limits this to an int).*/ + if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT; + if(_tags!=NULL){ + int ret; + ret=op_tags_ensure_capacity(_tags,count); + if(ret<0)return ret; + } + ncomments=(int)count; + for(ci=0;cilen>>2)return OP_EBADHEADER; + count=op_parse_uint32le(_data); + _data+=4; + len-=4; + if(count>len)return OP_EBADHEADER; + /*Check for overflow (the API limits this to an int).*/ + if(count>(opus_uint32)INT_MAX)return OP_EFAULT; + if(_tags!=NULL){ + _tags->user_comments[ci]=op_strdup_with_len((char *)_data,count); + if(_tags->user_comments[ci]==NULL)return OP_EFAULT; + _tags->comment_lengths[ci]=(int)count; + _tags->comments=ci+1; + /*Needed by opus_tags_clear() if we fail before parsing the (optional) + binary metadata.*/ + _tags->user_comments[ci+1]=NULL; + } + _data+=count; + len-=count; + } + if(len>0&&(_data[0]&1)){ + if(len>(opus_uint32)INT_MAX)return OP_EFAULT; + if(_tags!=NULL){ + _tags->user_comments[ncomments]=(char *)_ogg_malloc(len); + if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT; + memcpy(_tags->user_comments[ncomments],_data,len); + _tags->comment_lengths[ncomments]=(int)len; + } + } + return 0; +} + +int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){ + if(_tags!=NULL){ + OpusTags tags; + int ret; + opus_tags_init(&tags); + ret=opus_tags_parse_impl(&tags,_data,_len); + if(ret<0)opus_tags_clear(&tags); + else *_tags=*&tags; + return ret; + } + else return opus_tags_parse_impl(NULL,_data,_len); +} + +/*The actual implementation of opus_tags_copy(). + Unlike the public API, this function requires _dst to already be + initialized, modifies its contents before success is guaranteed, and assumes + the caller will clear it on error.*/ +static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){ + char *vendor; + int ncomments; + int ret; + int ci; + vendor=_src->vendor; + _dst->vendor=op_strdup_with_len(vendor,strlen(vendor)); + if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT; + ncomments=_src->comments; + ret=op_tags_ensure_capacity(_dst,ncomments); + if(OP_UNLIKELY(ret<0))return ret; + for(ci=0;cicomment_lengths[ci]; + OP_ASSERT(len>=0); + _dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len); + if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT; + _dst->comment_lengths[ci]=len; + _dst->comments=ci+1; + } + if(_src->comment_lengths!=NULL){ + int len; + len=_src->comment_lengths[ncomments]; + if(len>0){ + _dst->user_comments[ncomments]=(char *)_ogg_malloc(len); + if(OP_UNLIKELY(_dst->user_comments[ncomments]==NULL))return OP_EFAULT; + memcpy(_dst->user_comments[ncomments],_src->user_comments[ncomments],len); + _dst->comment_lengths[ncomments]=len; + } + } + return 0; +} + +int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){ + OpusTags dst; + int ret; + opus_tags_init(&dst); + ret=opus_tags_copy_impl(&dst,_src); + if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst); + else *_dst=*&dst; + return ret; +} + +int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){ + char *comment; + size_t tag_len; + size_t value_len; + int ncomments; + int ret; + ncomments=_tags->comments; + ret=op_tags_ensure_capacity(_tags,ncomments+1); + if(OP_UNLIKELY(ret<0))return ret; + tag_len=strlen(_tag); + value_len=strlen(_value); + /*+2 for '=' and '\0'.*/ + if(tag_len+value_len(size_t)INT_MAX-2)return OP_EFAULT; + comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2)); + if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; + memcpy(comment,_tag,sizeof(*comment)*tag_len); + comment[tag_len]='='; + memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1)); + _tags->user_comments[ncomments]=comment; + _tags->comment_lengths[ncomments]=(int)(tag_len+value_len+1); + _tags->comments=ncomments+1; + return 0; +} + +int opus_tags_add_comment(OpusTags *_tags,const char *_comment){ + char *comment; + int comment_len; + int ncomments; + int ret; + ncomments=_tags->comments; + ret=op_tags_ensure_capacity(_tags,ncomments+1); + if(OP_UNLIKELY(ret<0))return ret; + comment_len=(int)strlen(_comment); + comment=op_strdup_with_len(_comment,comment_len); + if(OP_UNLIKELY(comment==NULL))return OP_EFAULT; + _tags->user_comments[ncomments]=comment; + _tags->comment_lengths[ncomments]=comment_len; + _tags->comments=ncomments+1; + return 0; +} + +int opus_tags_set_binary_suffix(OpusTags *_tags, + const unsigned char *_data,int _len){ + unsigned char *binary_suffix_data; + int ncomments; + int ret; + if(_len<0||_len>0&&(_data==NULL||!(_data[0]&1)))return OP_EINVAL; + ncomments=_tags->comments; + ret=op_tags_ensure_capacity(_tags,ncomments); + if(OP_UNLIKELY(ret<0))return ret; + binary_suffix_data= + (unsigned char *)_ogg_realloc(_tags->user_comments[ncomments],_len); + if(OP_UNLIKELY(binary_suffix_data==NULL))return OP_EFAULT; + memcpy(binary_suffix_data,_data,_len); + _tags->user_comments[ncomments]=(char *)binary_suffix_data; + _tags->comment_lengths[ncomments]=_len; + return 0; +} + +int opus_tagcompare(const char *_tag_name,const char *_comment){ + size_t tag_len; + tag_len=strlen(_tag_name); + if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return -1; + return opus_tagncompare(_tag_name,(int)tag_len,_comment); +} + +int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){ + int ret; + OP_ASSERT(_tag_len>=0); + ret=op_strncasecmp(_tag_name,_comment,_tag_len); + return ret?ret:'='-_comment[_tag_len]; +} + +const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){ + char **user_comments; + size_t tag_len; + int found; + int ncomments; + int ci; + tag_len=strlen(_tag); + if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return NULL; + ncomments=_tags->comments; + user_comments=_tags->user_comments; + found=0; + for(ci=0;ci(size_t)INT_MAX))return 0; + ncomments=_tags->comments; + user_comments=_tags->user_comments; + found=0; + for(ci=0;cicomments; + len=_tags->comment_lengths==NULL?0:_tags->comment_lengths[ncomments]; + *_len=len; + OP_ASSERT(len==0||_tags->user_comments!=NULL); + return len>0?(const unsigned char *)_tags->user_comments[ncomments]:NULL; +} + +static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8, + const char *_tag_name,size_t _tag_len){ + char **comments; + int ncomments; + int ci; + comments=_tags->user_comments; + ncomments=_tags->comments; + /*Look for the first valid tag with the name _tag_name and use that.*/ + for(ci=0;ci='0'&&*p<='9'){ + gain_q8=10*gain_q8+*p-'0'; + if(gain_q8>32767-negative)break; + p++; + } + /*This didn't look like a signed 16-bit decimal integer. + Not a valid gain tag.*/ + if(*p!='\0')continue; + *_gain_q8=(int)(gain_q8+negative^negative); + return 0; + } + } + return OP_FALSE; +} + +int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8){ + return opus_tags_get_gain(_tags,_gain_q8,"R128_ALBUM_GAIN",15); +} + +int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){ + return opus_tags_get_gain(_tags,_gain_q8,"R128_TRACK_GAIN",15); +} + +static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){ + return _buf_sz>=3&&memcmp(_buf,"\xFF\xD8\xFF",3)==0; +} + +/*Tries to extract the width, height, bits per pixel, and palette size of a + JPEG. + On failure, simply leaves its outputs unmodified.*/ +static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz, + opus_uint32 *_width,opus_uint32 *_height, + opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){ + if(op_is_jpeg(_buf,_buf_sz)){ + size_t offs; + offs=2; + for(;;){ + size_t segment_len; + int marker; + while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++; + while(offs<_buf_sz&&_buf[offs]==0xFF)offs++; + marker=_buf[offs]; + offs++; + /*If we hit EOI* (end of image), or another SOI* (start of image), + or SOS (start of scan), then stop now.*/ + if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break; + /*RST* (restart markers): skip (no segment length).*/ + else if(marker>=0xD0&&marker<=0xD7)continue; + /*Read the length of the marker segment.*/ + if(_buf_sz-offs<2)break; + segment_len=_buf[offs]<<8|_buf[offs+1]; + if(segment_len<2||_buf_sz-offs0xC0&&marker<0xD0&&(marker&3)!=0)){ + /*Found a SOFn (start of frame) marker segment:*/ + if(segment_len>=8){ + *_height=_buf[offs+3]<<8|_buf[offs+4]; + *_width=_buf[offs+5]<<8|_buf[offs+6]; + *_depth=_buf[offs+2]*_buf[offs+7]; + *_colors=0; + *_has_palette=0; + } + break; + } + /*Other markers: skip the whole marker segment.*/ + offs+=segment_len; + } + } +} + +static int op_is_png(const unsigned char *_buf,size_t _buf_sz){ + return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0; +} + +/*Tries to extract the width, height, bits per pixel, and palette size of a + PNG. + On failure, simply leaves its outputs unmodified.*/ +static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz, + opus_uint32 *_width,opus_uint32 *_height, + opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){ + if(op_is_png(_buf,_buf_sz)){ + size_t offs; + offs=8; + while(_buf_sz-offs>=12){ + ogg_uint32_t chunk_len; + chunk_len=op_parse_uint32be(_buf+offs); + if(chunk_len>_buf_sz-(offs+12))break; + else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){ + int color_type; + *_width=op_parse_uint32be(_buf+offs+8); + *_height=op_parse_uint32be(_buf+offs+12); + color_type=_buf[offs+17]; + if(color_type==3){ + *_depth=24; + *_has_palette=1; + } + else{ + int sample_depth; + sample_depth=_buf[offs+16]; + if(color_type==0)*_depth=sample_depth; + else if(color_type==2)*_depth=sample_depth*3; + else if(color_type==4)*_depth=sample_depth*2; + else if(color_type==6)*_depth=sample_depth*4; + *_colors=0; + *_has_palette=0; + break; + } + } + else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){ + *_colors=chunk_len/3; + break; + } + offs+=12+chunk_len; + } + } +} + +static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){ + return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0); +} + +/*Tries to extract the width, height, bits per pixel, and palette size of a + GIF. + On failure, simply leaves its outputs unmodified.*/ +static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz, + opus_uint32 *_width,opus_uint32 *_height, + opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){ + if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){ + *_width=_buf[6]|_buf[7]<<8; + *_height=_buf[8]|_buf[9]<<8; + /*libFLAC hard-codes the depth to 24.*/ + *_depth=24; + *_colors=1<<((_buf[10]&7)+1); + *_has_palette=1; + } +} + +/*The actual implementation of opus_picture_tag_parse(). + Unlike the public API, this function requires _pic to already be + initialized, modifies its contents before success is guaranteed, and assumes + the caller will clear it on error.*/ +static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag, + unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){ + opus_int32 picture_type; + opus_uint32 mime_type_length; + char *mime_type; + opus_uint32 description_length; + char *description; + opus_uint32 width; + opus_uint32 height; + opus_uint32 depth; + opus_uint32 colors; + opus_uint32 data_length; + opus_uint32 file_width; + opus_uint32 file_height; + opus_uint32 file_depth; + opus_uint32 file_colors; + int format; + int has_palette; + int colors_set; + size_t i; + /*Decode the BASE64 data.*/ + OP_ASSERT(_base64_sz>=11); + for(i=0;i<_base64_sz;i++){ + opus_uint32 value; + int j; + value=0; + for(j=0;j<4;j++){ + unsigned c; + unsigned d; + c=(unsigned char)_tag[4*i+j]; + if(c=='+')d=62; + else if(c=='/')d=63; + else if(c>='0'&&c<='9')d=52+c-'0'; + else if(c>='a'&&c<='z')d=26+c-'a'; + else if(c>='A'&&c<='Z')d=c-'A'; + else if(c=='='&&3*i+j>_buf_sz)d=0; + else return OP_ENOTFORMAT; + value=value<<6|d; + } + _buf[3*i]=(unsigned char)(value>>16); + if(3*i+1<_buf_sz){ + _buf[3*i+1]=(unsigned char)(value>>8); + if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value; + } + } + i=0; + picture_type=op_parse_uint32be(_buf+i); + i+=4; + /*Extract the MIME type.*/ + mime_type_length=op_parse_uint32be(_buf+i); + i+=4; + if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT; + mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1)); + if(mime_type==NULL)return OP_EFAULT; + memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length); + mime_type[mime_type_length]='\0'; + _pic->mime_type=mime_type; + i+=mime_type_length; + /*Extract the description string.*/ + description_length=op_parse_uint32be(_buf+i); + i+=4; + if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT; + description= + (char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1)); + if(description==NULL)return OP_EFAULT; + memcpy(description,_buf+i,sizeof(*description)*description_length); + description[description_length]='\0'; + _pic->description=description; + i+=description_length; + /*Extract the remaining fields.*/ + width=op_parse_uint32be(_buf+i); + i+=4; + height=op_parse_uint32be(_buf+i); + i+=4; + depth=op_parse_uint32be(_buf+i); + i+=4; + colors=op_parse_uint32be(_buf+i); + i+=4; + /*If one of these is set, they all must be, but colors==0 is a valid value.*/ + colors_set=width!=0||height!=0||depth!=0||colors!=0; + if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT; + data_length=op_parse_uint32be(_buf+i); + i+=4; + if(data_length>_buf_sz-i)return OP_ENOTFORMAT; + /*Trim extraneous data so we don't copy it below.*/ + _buf_sz=i+data_length; + /*Attempt to determine the image format.*/ + format=OP_PIC_FORMAT_UNKNOWN; + if(mime_type_length==3&&strcmp(mime_type,"-->")==0){ + format=OP_PIC_FORMAT_URL; + /*Picture type 1 must be a 32x32 PNG.*/ + if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){ + return OP_ENOTFORMAT; + } + /*Append a terminating NUL for the convenience of our callers.*/ + _buf[_buf_sz++]='\0'; + } + else{ + if(mime_type_length==10 + &&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){ + if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG; + } + else if(mime_type_length==9 + &&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){ + if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG; + } + else if(mime_type_length==9 + &&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){ + if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF; + } + else if(mime_type_length==0||(mime_type_length==6 + &&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){ + if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG; + else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG; + else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF; + } + file_width=file_height=file_depth=file_colors=0; + has_palette=-1; + switch(format){ + case OP_PIC_FORMAT_JPEG:{ + op_extract_jpeg_params(_buf+i,data_length, + &file_width,&file_height,&file_depth,&file_colors,&has_palette); + }break; + case OP_PIC_FORMAT_PNG:{ + op_extract_png_params(_buf+i,data_length, + &file_width,&file_height,&file_depth,&file_colors,&has_palette); + }break; + case OP_PIC_FORMAT_GIF:{ + op_extract_gif_params(_buf+i,data_length, + &file_width,&file_height,&file_depth,&file_colors,&has_palette); + }break; + } + if(has_palette>=0){ + /*If we successfully extracted these parameters from the image, override + any declared values.*/ + width=file_width; + height=file_height; + depth=file_depth; + colors=file_colors; + } + /*Picture type 1 must be a 32x32 PNG.*/ + if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){ + return OP_ENOTFORMAT; + } + } + /*Adjust _buf_sz instead of using data_length to capture the terminating NUL + for URLs.*/ + _buf_sz-=i; + memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz); + _buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz); + if(_buf_sz>0&&_buf==NULL)return OP_EFAULT; + _pic->type=picture_type; + _pic->width=width; + _pic->height=height; + _pic->depth=depth; + _pic->colors=colors; + _pic->data_length=data_length; + _pic->data=_buf; + _pic->format=format; + return 0; +} + +int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){ + OpusPictureTag pic; + unsigned char *buf; + size_t base64_sz; + size_t buf_sz; + size_t tag_length; + int ret; + if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23; + /*Figure out how much BASE64-encoded data we have.*/ + tag_length=strlen(_tag); + if(tag_length&3)return OP_ENOTFORMAT; + base64_sz=tag_length>>2; + buf_sz=3*base64_sz; + if(buf_sz<32)return OP_ENOTFORMAT; + if(_tag[tag_length-1]=='=')buf_sz--; + if(_tag[tag_length-2]=='=')buf_sz--; + if(buf_sz<32)return OP_ENOTFORMAT; + /*Allocate an extra byte to allow appending a terminating NUL to URL data.*/ + buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1)); + if(buf==NULL)return OP_EFAULT; + opus_picture_tag_init(&pic); + ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz); + if(ret<0){ + opus_picture_tag_clear(&pic); + _ogg_free(buf); + } + else *_pic=*&pic; + return ret; +} + +void opus_picture_tag_init(OpusPictureTag *_pic){ + memset(_pic,0,sizeof(*_pic)); +} + +void opus_picture_tag_clear(OpusPictureTag *_pic){ + _ogg_free(_pic->description); + _ogg_free(_pic->mime_type); + _ogg_free(_pic->data); +} diff --git a/src/opusfile/internal.c b/src/opusfile/internal.c new file mode 100644 index 00000000..8df4f158 --- /dev/null +++ b/src/opusfile/internal.c @@ -0,0 +1,42 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012-2020 * + * by the Xiph.Org Foundation and contributors https://xiph.org/ * + * * + ********************************************************************/ +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "internal.h" + +#if defined(OP_ENABLE_ASSERTIONS) +void op_fatal_impl(const char *_str,const char *_file,int _line){ + fprintf(stderr,"Fatal (internal) error in %s, line %i: %s\n", + _file,_line,_str); + abort(); +} +#endif + +/*A version of strncasecmp() that is guaranteed to only ignore the case of + ASCII characters.*/ +int op_strncasecmp(const char *_a,const char *_b,int _n){ + int i; + for(i=0;i<_n;i++){ + int a; + int b; + int d; + a=_a[i]; + b=_b[i]; + if(a>='a'&&a<='z')a-='a'-'A'; + if(b>='a'&&b<='z')b-='a'-'A'; + d=a-b; + if(d)return d; + } + return 0; +} diff --git a/src/opusfile/internal.h b/src/opusfile/internal.h new file mode 100644 index 00000000..e73989c0 --- /dev/null +++ b/src/opusfile/internal.h @@ -0,0 +1,259 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012-2020 * + * by the Xiph.Org Foundation and contributors https://xiph.org/ * + * * + ********************************************************************/ +#if !defined(_opusfile_internal_h) +# define _opusfile_internal_h (1) + +# if !defined(_REENTRANT) +# define _REENTRANT +# endif +# if !defined(_GNU_SOURCE) +# define _GNU_SOURCE +# endif +# if !defined(_LARGEFILE_SOURCE) +# define _LARGEFILE_SOURCE +# endif +# if !defined(_LARGEFILE64_SOURCE) +# define _LARGEFILE64_SOURCE +# endif +# if !defined(_FILE_OFFSET_BITS) +# define _FILE_OFFSET_BITS 64 +# endif + +# include +# include "opusfile.h" + +typedef struct OggOpusLink OggOpusLink; + +# if defined(OP_FIXED_POINT) + +typedef opus_int16 op_sample; + +# else + +typedef float op_sample; + +/*We're using this define to test for libopus 1.1 or later until libopus + provides a better mechanism.*/ +# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST) +/*Enable soft clipping prevention in 16-bit decodes.*/ +# define OP_SOFT_CLIP (1) +# endif + +# endif + +# if OP_GNUC_PREREQ(4,2) +/*Disable excessive warnings about the order of operations.*/ +# pragma GCC diagnostic ignored "-Wparentheses" +# elif defined(_MSC_VER) +/*Disable excessive warnings about the order of operations.*/ +# pragma warning(disable:4554) +/*Disable warnings about "deprecated" POSIX functions.*/ +# pragma warning(disable:4996) +# endif + +# if OP_GNUC_PREREQ(3,0) +/*Another alternative is + (__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1)) + but that evaluates _x multiple times, which may be bad.*/ +# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1)) +# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0)) +# else +# define OP_LIKELY(_x) (!!(_x)) +# define OP_UNLIKELY(_x) (!!(_x)) +# endif + +# if defined(OP_ENABLE_ASSERTIONS) +# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590 +__attribute__((noreturn)) +# endif +void op_fatal_impl(const char *_str,const char *_file,int _line); + +# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__)) + +# define OP_ASSERT(_cond) \ + do{ \ + if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \ + } \ + while(0) +# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond) + +# else +# define OP_FATAL(_str) abort() +# define OP_ASSERT(_cond) +# define OP_ALWAYS_TRUE(_cond) ((void)(_cond)) +# endif + +# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1) +# define OP_INT64_MIN (-OP_INT64_MAX-1) +# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1) +# define OP_INT32_MIN (-OP_INT32_MAX-1) + +# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b)) +# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b)) +# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi))) + +/*Advance a file offset by the given amount, clamping against OP_INT64_MAX. + This is used to advance a known offset by things like OP_CHUNK_SIZE or + OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow. + It assumes that both _offset and _amount are non-negative.*/ +#define OP_ADV_OFFSET(_offset,_amount) \ + (OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount)) + +/*The maximum channel count for any mapping we'll actually decode.*/ +# define OP_NCHANNELS_MAX (8) + +/*Initial state.*/ +# define OP_NOTOPEN (0) +/*We've found the first Opus stream in the first link.*/ +# define OP_PARTOPEN (1) +# define OP_OPENED (2) +/*We've found the first Opus stream in the current link.*/ +# define OP_STREAMSET (3) +/*We've initialized the decoder for the chosen Opus stream in the current + link.*/ +# define OP_INITSET (4) + +/*Information cached for a single link in a chained Ogg Opus file. + We choose the first Opus stream encountered in each link to play back (and + require at least one).*/ +struct OggOpusLink{ + /*The byte offset of the first header page in this link.*/ + opus_int64 offset; + /*The byte offset of the first data page from the chosen Opus stream in this + link (after the headers).*/ + opus_int64 data_offset; + /*The byte offset of the last page from the chosen Opus stream in this link. + This is used when seeking to ensure we find a page before the last one, so + that end-trimming calculations work properly. + This is only valid for seekable sources.*/ + opus_int64 end_offset; + /*The total duration of all prior links. + This is always zero for non-seekable sources.*/ + ogg_int64_t pcm_file_offset; + /*The granule position of the last sample. + This is only valid for seekable sources.*/ + ogg_int64_t pcm_end; + /*The granule position before the first sample.*/ + ogg_int64_t pcm_start; + /*The serial number.*/ + ogg_uint32_t serialno; + /*The contents of the info header.*/ + OpusHead head; + /*The contents of the comment header.*/ + OpusTags tags; +}; + +struct OggOpusFile{ + /*The callbacks used to access the stream.*/ + OpusFileCallbacks callbacks; + /*A FILE *, memory buffer, etc.*/ + void *stream; + /*Whether or not we can seek with this stream.*/ + int seekable; + /*The number of links in this chained Ogg Opus file.*/ + int nlinks; + /*The cached information from each link in a chained Ogg Opus file. + If stream isn't seekable (e.g., it's a pipe), only the current link + appears.*/ + OggOpusLink *links; + /*The number of serial numbers from a single link.*/ + int nserialnos; + /*The capacity of the list of serial numbers from a single link.*/ + int cserialnos; + /*Storage for the list of serial numbers from a single link. + This is a scratch buffer used when scanning the BOS pages at the start of + each link.*/ + ogg_uint32_t *serialnos; + /*This is the current offset of the data processed by the ogg_sync_state. + After a seek, this should be set to the target offset so that we can track + the byte offsets of subsequent pages. + After a call to op_get_next_page(), this will point to the first byte after + that page.*/ + opus_int64 offset; + /*The total size of this stream, or -1 if it's unseekable.*/ + opus_int64 end; + /*Used to locate pages in the stream.*/ + ogg_sync_state oy; + /*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/ + int ready_state; + /*The current link being played back.*/ + int cur_link; + /*The number of decoded samples to discard from the start of decoding.*/ + opus_int32 cur_discard_count; + /*The granule position of the previous packet (current packet start time).*/ + ogg_int64_t prev_packet_gp; + /*The stream offset of the most recent page with completed packets, or -1. + This is only needed to recover continued packet data in the seeking logic, + when we use the current position as one of our bounds, only to later + discover it was the correct starting point.*/ + opus_int64 prev_page_offset; + /*The number of bytes read since the last bitrate query, including framing.*/ + opus_int64 bytes_tracked; + /*The number of samples decoded since the last bitrate query.*/ + ogg_int64_t samples_tracked; + /*Takes physical pages and welds them into a logical stream of packets.*/ + ogg_stream_state os; + /*Re-timestamped packets from a single page. + Buffering these relies on the undocumented libogg behavior that ogg_packet + pointers remain valid until the next page is submitted to the + ogg_stream_state they came from.*/ + ogg_packet op[255]; + /*The index of the next packet to return.*/ + int op_pos; + /*The total number of packets available.*/ + int op_count; + /*Central working state for the packet-to-PCM decoder.*/ + OpusMSDecoder *od; + /*The application-provided packet decode callback.*/ + op_decode_cb_func decode_cb; + /*The application-provided packet decode callback context.*/ + void *decode_cb_ctx; + /*The stream count used to initialize the decoder.*/ + int od_stream_count; + /*The coupled stream count used to initialize the decoder.*/ + int od_coupled_count; + /*The channel count used to initialize the decoder.*/ + int od_channel_count; + /*The channel mapping used to initialize the decoder.*/ + unsigned char od_mapping[OP_NCHANNELS_MAX]; + /*The buffered data for one decoded packet.*/ + op_sample *od_buffer; + /*The current position in the decoded buffer.*/ + int od_buffer_pos; + /*The number of valid samples in the decoded buffer.*/ + int od_buffer_size; + /*The type of gain offset to apply. + One of OP_HEADER_GAIN, OP_ALBUM_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/ + int gain_type; + /*The offset to apply to the gain.*/ + opus_int32 gain_offset_q8; + /*Internal state for soft clipping and dithering float->short output.*/ +#if !defined(OP_FIXED_POINT) +# if defined(OP_SOFT_CLIP) + float clip_state[OP_NCHANNELS_MAX]; +# endif + float dither_a[OP_NCHANNELS_MAX*4]; + float dither_b[OP_NCHANNELS_MAX*4]; + opus_uint32 dither_seed; + int dither_mute; + int dither_disabled; + /*The number of channels represented by the internal state. + This gets set to 0 whenever anything that would prevent state propagation + occurs (switching between the float/short APIs, or between the + stereo/multistream APIs).*/ + int state_channel_count; +#endif +}; + +int op_strncasecmp(const char *_a,const char *_b,int _n); + +#endif diff --git a/src/opusfile/opusfile.c b/src/opusfile/opusfile.c new file mode 100644 index 00000000..23f05ef9 --- /dev/null +++ b/src/opusfile/opusfile.c @@ -0,0 +1,3343 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2020 * + * by the Xiph.Org Foundation and contributors https://xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $ + + ********************************************************************/ +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "internal.h" +#include +#include +#include +#include +#include +#include + +#include "opusfile.h" + +/*This implementation is largely based off of libvorbisfile. + All of the Ogg bits work roughly the same, though I have made some + "improvements" that have not been folded back there, yet.*/ + +/*A 'chained bitstream' is an Ogg Opus bitstream that contains more than one + logical bitstream arranged end to end (the only form of Ogg multiplexing + supported by this library. + Grouping (parallel multiplexing) is not supported, except to the extent that + if there are multiple logical Ogg streams in a single link of the chain, we + will ignore all but the first Opus stream we find.*/ + +/*An Ogg Opus file can be played beginning to end (streamed) without worrying + ahead of time about chaining (see opusdec from the opus-tools package). + If we have the whole file, however, and want random access + (seeking/scrubbing) or desire to know the total length/time of a file, we + need to account for the possibility of chaining.*/ + +/*We can handle things a number of ways. + We can determine the entire bitstream structure right off the bat, or find + pieces on demand. + This library determines and caches structure for the entire bitstream, but + builds a virtual decoder on the fly when moving between links in the chain.*/ + +/*There are also different ways to implement seeking. + Enough information exists in an Ogg bitstream to seek to sample-granularity + positions in the output. + Or, one can seek by picking some portion of the stream roughly in the desired + area if we only want coarse navigation through the stream. + We implement and expose both strategies.*/ + +/*The maximum number of bytes in a page (including the page headers).*/ +#define OP_PAGE_SIZE_MAX (65307) +/*The default amount to seek backwards per step when trying to find the + previous page. + This must be at least as large as the maximum size of a page.*/ +#define OP_CHUNK_SIZE (65536) +/*The maximum amount to seek backwards per step when trying to find the + previous page.*/ +#define OP_CHUNK_SIZE_MAX (1024*(opus_int32)1024) +/*A smaller read size is needed for low-rate streaming.*/ +#define OP_READ_SIZE (2048) + +int op_test(OpusHead *_head, + const unsigned char *_initial_data,size_t _initial_bytes){ + ogg_sync_state oy; + char *data; + int err; + /*The first page of a normal Opus file will be at most 57 bytes (27 Ogg + page header bytes + 1 lacing value + 21 Opus header bytes + 8 channel + mapping bytes). + It will be at least 47 bytes (27 Ogg page header bytes + 1 lacing value + + 19 Opus header bytes using channel mapping family 0). + If we don't have at least that much data, give up now.*/ + if(_initial_bytes<47)return OP_FALSE; + /*Only proceed if we start with the magic OggS string. + This is to prevent us spending a lot of time allocating memory and looking + for Ogg pages in non-Ogg files.*/ + if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT; + if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT; + ogg_sync_init(&oy); + data=ogg_sync_buffer(&oy,(long)_initial_bytes); + if(data!=NULL){ + ogg_stream_state os; + ogg_page og; + int ret; + memcpy(data,_initial_data,_initial_bytes); + ogg_sync_wrote(&oy,(long)_initial_bytes); + ogg_stream_init(&os,-1); + err=OP_FALSE; + do{ + ogg_packet op; + ret=ogg_sync_pageout(&oy,&og); + /*Ignore holes.*/ + if(ret<0)continue; + /*Stop if we run out of data.*/ + if(!ret)break; + ogg_stream_reset_serialno(&os,ogg_page_serialno(&og)); + ogg_stream_pagein(&os,&og); + /*Only process the first packet on this page (if it's a BOS packet, + it's required to be the only one).*/ + if(ogg_stream_packetout(&os,&op)==1){ + if(op.b_o_s){ + ret=opus_head_parse(_head,op.packet,op.bytes); + /*If this didn't look like Opus, keep going.*/ + if(ret==OP_ENOTFORMAT)continue; + /*Otherwise we're done, one way or another.*/ + err=ret; + } + /*We finished parsing the headers. + There is no Opus to be found.*/ + else err=OP_ENOTFORMAT; + } + } + while(err==OP_FALSE); + ogg_stream_clear(&os); + } + else err=OP_EFAULT; + ogg_sync_clear(&oy); + return err; +} + +/*Many, many internal helpers. + The intention is not to be confusing. + Rampant duplication and monolithic function implementation (though we do have + some large, omnibus functions still) would be harder to understand anyway. + The high level functions are last. + Begin grokking near the end of the file if you prefer to read things + top-down.*/ + +/*The read/seek functions track absolute position within the stream.*/ + +/*Read a little more data from the file/pipe into the ogg_sync framer. + _nbytes: The maximum number of bytes to read. + Return: A positive number of bytes read on success, 0 on end-of-file, or a + negative value on failure.*/ +static int op_get_data(OggOpusFile *_of,int _nbytes){ + unsigned char *buffer; + int nbytes; + OP_ASSERT(_nbytes>0); + buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes); + nbytes=(int)(*_of->callbacks.read)(_of->stream,buffer,_nbytes); + OP_ASSERT(nbytes<=_nbytes); + if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes); + return nbytes; +} + +/*Save a tiny smidge of verbosity to make the code more readable.*/ +static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){ + if(_offset==_of->offset)return 0; + if(_of->callbacks.seek==NULL + ||(*_of->callbacks.seek)(_of->stream,_offset,SEEK_SET)){ + return OP_EREAD; + } + _of->offset=_offset; + ogg_sync_reset(&_of->oy); + return 0; +} + +/*Get the current position indicator of the underlying stream. + This should be the same as the value reported by tell().*/ +static opus_int64 op_position(const OggOpusFile *_of){ + /*The current position indicator is _not_ simply offset. + We may also have unprocessed, buffered data in the sync state.*/ + return _of->offset+_of->oy.fill-_of->oy.returned; +} + +/*From the head of the stream, get the next page. + _boundary specifies if the function is allowed to fetch more data from the + stream (and how much) or only use internally buffered data. + _boundary: -1: Unbounded search. + 0: Read no additional data. + Use only cached data. + n: Search for the start of a new page up to file position n. + Return: n>=0: Found a page at absolute offset n. + OP_FALSE: Hit the _boundary limit. + OP_EREAD: An underlying read operation failed. + OP_BADLINK: We hit end-of-file before reaching _boundary.*/ +static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og, + opus_int64 _boundary){ + while(_boundary<=0||_of->offset<_boundary){ + int more; + more=ogg_sync_pageseek(&_of->oy,_og); + /*Skipped (-more) bytes.*/ + if(OP_UNLIKELY(more<0))_of->offset-=more; + else if(more==0){ + int read_nbytes; + int ret; + /*Send more paramedics.*/ + if(!_boundary)return OP_FALSE; + if(_boundary<0)read_nbytes=OP_READ_SIZE; + else{ + opus_int64 position; + position=op_position(_of); + if(position>=_boundary)return OP_FALSE; + read_nbytes=(int)OP_MIN(_boundary-position,OP_READ_SIZE); + } + ret=op_get_data(_of,read_nbytes); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + if(OP_UNLIKELY(ret==0)){ + /*Only fail cleanly on EOF if we didn't have a known boundary. + Otherwise, we should have been able to reach that boundary, and this + is a fatal error.*/ + return OP_UNLIKELY(_boundary<0)?OP_FALSE:OP_EBADLINK; + } + } + else{ + /*Got a page. + Return the page start offset and advance the internal offset past the + page end.*/ + opus_int64 page_offset; + page_offset=_of->offset; + _of->offset+=more; + OP_ASSERT(page_offset>=0); + return page_offset; + } + } + return OP_FALSE; +} + +static int op_add_serialno(const ogg_page *_og, + ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){ + ogg_uint32_t *serialnos; + int nserialnos; + int cserialnos; + ogg_uint32_t s; + s=ogg_page_serialno(_og); + serialnos=*_serialnos; + nserialnos=*_nserialnos; + cserialnos=*_cserialnos; + if(OP_UNLIKELY(nserialnos>=cserialnos)){ + if(OP_UNLIKELY(cserialnos>INT_MAX/(int)sizeof(*serialnos)-1>>1)){ + return OP_EFAULT; + } + cserialnos=2*cserialnos+1; + OP_ASSERT(nserialnos=OP_PAGE_SIZE_MAX); + begin=OP_MAX(begin-chunk_size,0); + ret=op_seek_helper(_of,begin); + if(OP_UNLIKELY(ret<0))return ret; + search_start=begin; + while(_of->offsetsearch_start=search_start; + _sr->offset=_offset=llret; + _sr->serialno=serialno; + OP_ASSERT(_of->offset-_offset>=0); + OP_ASSERT(_of->offset-_offset<=OP_PAGE_SIZE_MAX); + _sr->size=(opus_int32)(_of->offset-_offset); + _sr->gp=ogg_page_granulepos(&og); + /*If this page is from the stream we're looking for, remember it.*/ + if(serialno==_serialno){ + preferred_found=1; + *&preferred_sr=*_sr; + } + if(!op_lookup_serialno(serialno,_serialnos,_nserialnos)){ + /*We fell off the end of the link, which means we seeked back too far + and shouldn't have been looking in that link to begin with. + If we found the preferred serial number, forget that we saw it.*/ + preferred_found=0; + } + search_start=llret+1; + } + /*We started from the beginning of the stream and found nothing. + This should be impossible unless the contents of the stream changed out + from under us after we read from it.*/ + if(OP_UNLIKELY(!begin)&&OP_UNLIKELY(_offset<0))return OP_EBADLINK; + /*Bump up the chunk size. + This is mildly helpful when seeks are very expensive (http).*/ + chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX); + /*Avoid quadratic complexity if we hit an invalid patch of the file.*/ + end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end); + } + while(_offset<0); + if(preferred_found)*_sr=*&preferred_sr; + return 0; +} + +/*Find the last page beginning before _offset with the given serial number and + a valid granule position. + Unlike the above search, this continues until it finds such a page, but does + not stray outside the current link. + We could implement it (inefficiently) by calling op_get_prev_page_serial() + repeatedly until it returned a page that had both our preferred serial + number and a valid granule position, but doing it with a separate function + allows us to avoid repeatedly re-scanning valid pages from other streams as + we seek-back-and-read-forward. + [out] _gp: Returns the granule position of the page that was found on + success. + _offset: The _offset before which to find a page. + Any page returned will consist of data entirely before _offset. + _serialno: The target serial number. + _serialnos: The list of serial numbers in the link that contains the + preferred serial number. + _nserialnos: The number of serial numbers in the current link. + Return: The offset of the page on success, or a negative value on failure. + OP_EREAD: Failed to read more data (error or EOF). + OP_EBADLINK: We couldn't find a page even after seeking back past the + beginning of the link.*/ +static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp, + opus_int64 _offset,ogg_uint32_t _serialno, + const ogg_uint32_t *_serialnos,int _nserialnos){ + ogg_page og; + ogg_int64_t gp; + opus_int64 begin; + opus_int64 end; + opus_int64 original_end; + opus_int32 chunk_size; + /*The target serial number must belong to the current link.*/ + OP_ASSERT(op_lookup_serialno(_serialno,_serialnos,_nserialnos)); + original_end=end=begin=_offset; + _offset=-1; + /*We shouldn't have to initialize gp, but gcc is too dumb to figure out that + ret>=0 implies we entered the if(page_gp!=-1) block at least once.*/ + gp=-1; + chunk_size=OP_CHUNK_SIZE; + do{ + int left_link; + int ret; + OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX); + begin=OP_MAX(begin-chunk_size,0); + ret=op_seek_helper(_of,begin); + if(OP_UNLIKELY(ret<0))return ret; + left_link=0; + while(_of->offsetready_stateos,ogg_page_serialno(_og)); + ogg_stream_pagein(&_of->os,_og); + if(OP_LIKELY(ogg_stream_packetout(&_of->os,&op)>0)){ + ret=opus_head_parse(_head,op.packet,op.bytes); + /*Found a valid Opus header. + Continue setup.*/ + if(OP_LIKELY(ret>=0))_of->ready_state=OP_STREAMSET; + /*If it's just a stream type we don't recognize, ignore it. + Everything else is fatal.*/ + else if(ret!=OP_ENOTFORMAT)return ret; + } + /*TODO: Should a BOS page with no packets be an error?*/ + } + /*Get the next page. + No need to clamp the boundary offset against _of->end, as all errors + become OP_ENOTFORMAT or OP_EBADHEADER.*/ + if(OP_UNLIKELY(op_get_next_page(_of,_og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return _of->ready_stateready_state!=OP_STREAMSET))return OP_ENOTFORMAT; + /*If the first non-header page belonged to our Opus stream, submit it.*/ + if(_of->os.serialno==ogg_page_serialno(_og))ogg_stream_pagein(&_of->os,_og); + /*Loop getting packets.*/ + for(;;){ + switch(ogg_stream_packetout(&_of->os,&op)){ + case 0:{ + /*Loop getting pages.*/ + for(;;){ + /*No need to clamp the boundary offset against _of->end, as all + errors become OP_EBADHEADER.*/ + if(OP_UNLIKELY(op_get_next_page(_of,_og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return OP_EBADHEADER; + } + /*If this page belongs to the correct stream, go parse it.*/ + if(_of->os.serialno==ogg_page_serialno(_og)){ + ogg_stream_pagein(&_of->os,_og); + break; + } + /*If the link ends before we see the Opus comment header, abort.*/ + if(OP_UNLIKELY(ogg_page_bos(_og)))return OP_EBADHEADER; + /*Otherwise, keep looking.*/ + } + }break; + /*We shouldn't get a hole in the headers!*/ + case -1:return OP_EBADHEADER; + default:{ + /*Got a packet. + It should be the comment header.*/ + ret=opus_tags_parse(_tags,op.packet,op.bytes); + if(OP_UNLIKELY(ret<0))return ret; + /*Make sure the page terminated at the end of the comment header. + If there is another packet on the page, or part of a packet, then + reject the stream. + Otherwise seekable sources won't be able to seek back to the start + properly.*/ + ret=ogg_stream_packetout(&_of->os,&op); + if(OP_UNLIKELY(ret!=0) + ||OP_UNLIKELY(_og->header[_og->header_len-1]==255)){ + /*If we fail, the caller assumes our tags are uninitialized.*/ + opus_tags_clear(_tags); + return OP_EBADHEADER; + } + return 0; + } + } + } +} + +static int op_fetch_headers(OggOpusFile *_of,OpusHead *_head, + OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos, + int *_cserialnos,ogg_page *_og){ + ogg_page og; + int ret; + if(!_og){ + /*No need to clamp the boundary offset against _of->end, as all errors + become OP_ENOTFORMAT.*/ + if(OP_UNLIKELY(op_get_next_page(_of,&og, + OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){ + return OP_ENOTFORMAT; + } + _og=&og; + } + _of->ready_state=OP_OPENED; + ret=op_fetch_headers_impl(_of,_head,_tags,_serialnos,_nserialnos, + _cserialnos,_og); + /*Revert back from OP_STREAMSET to OP_OPENED on failure, to prevent + double-free of the tags in an unseekable stream.*/ + if(OP_UNLIKELY(ret<0))_of->ready_state=OP_OPENED; + return ret; +} + +/*Granule position manipulation routines. + A granule position is defined to be an unsigned 64-bit integer, with the + special value -1 in two's complement indicating an unset or invalid granule + position. + We are not guaranteed to have an unsigned 64-bit type, so we construct the + following routines that + a) Properly order negative numbers as larger than positive numbers, and + b) Check for underflow or overflow past the special -1 value. + This lets us operate on the full, valid range of granule positions in a + consistent and safe manner. + This full range is organized into distinct regions: + [ -1 (invalid) ][ 0 ... OP_INT64_MAX ][ OP_INT64_MIN ... -2 ][-1 (invalid) ] + + No one should actually use granule positions so large that they're negative, + even if they are technically valid, as very little software handles them + correctly (including most of Xiph.Org's). + This library also refuses to support durations so large they won't fit in a + signed 64-bit integer (to avoid exposing this mess to the application, and + to simplify a good deal of internal arithmetic), so the only way to use them + successfully is if pcm_start is very large. + This means there isn't anything you can do with negative granule positions + that you couldn't have done with purely non-negative ones. + The main purpose of these routines is to allow us to think very explicitly + about the possible failure cases of all granule position manipulations.*/ + +/*Safely adds a small signed integer to a valid (not -1) granule position. + The result can use the full 64-bit range of values (both positive and + negative), but will fail on overflow (wrapping past -1; wrapping past + OP_INT64_MAX is explicitly okay). + [out] _dst_gp: The resulting granule position. + Only modified on success. + _src_gp: The granule position to add to. + This must not be -1. + _delta: The amount to add. + This is allowed to be up to 32 bits to support the maximum + duration of a single Ogg page (255 packets * 120 ms per + packet == 1,468,800 samples at 48 kHz). + Return: 0 on success, or OP_EINVAL if the result would wrap around past -1.*/ +static int op_granpos_add(ogg_int64_t *_dst_gp,ogg_int64_t _src_gp, + opus_int32 _delta){ + /*The code below handles this case correctly, but there's no reason we + should ever be called with these values, so make sure we aren't.*/ + OP_ASSERT(_src_gp!=-1); + if(_delta>0){ + /*Adding this amount to the granule position would overflow its 64-bit + range.*/ + if(OP_UNLIKELY(_src_gp<0)&&OP_UNLIKELY(_src_gp>=-1-_delta))return OP_EINVAL; + if(OP_UNLIKELY(_src_gp>OP_INT64_MAX-_delta)){ + /*Adding this amount to the granule position would overflow the positive + half of its 64-bit range. + Since signed overflow is undefined in C, do it in a way the compiler + isn't allowed to screw up.*/ + _delta-=(opus_int32)(OP_INT64_MAX-_src_gp)+1; + _src_gp=OP_INT64_MIN; + } + } + else if(_delta<0){ + /*Subtracting this amount from the granule position would underflow its + 64-bit range.*/ + if(_src_gp>=0&&OP_UNLIKELY(_src_gp<-_delta))return OP_EINVAL; + if(OP_UNLIKELY(_src_gp da < 0.*/ + da=(OP_INT64_MIN-_gp_a)-1; + /*_gp_b >= 0 => db >= 0.*/ + db=OP_INT64_MAX-_gp_b; + /*Step 2: Check for overflow.*/ + if(OP_UNLIKELY(OP_INT64_MAX+da= 0 => da <= 0*/ + da=_gp_a+OP_INT64_MIN; + /*_gp_b < 0 => db <= 0*/ + db=OP_INT64_MIN-_gp_b; + /*Step 2: Check for overflow.*/ + if(OP_UNLIKELY(da=0)return 1; + /*Else fall through.*/ + } + else if(OP_UNLIKELY(_gp_b<0))return -1; + /*No wrapping case.*/ + return (_gp_a>_gp_b)-(_gp_b>_gp_a); +} + +/*Returns the duration of the packet (in samples at 48 kHz), or a negative + value on error.*/ +static int op_get_packet_duration(const unsigned char *_data,int _len){ + int nframes; + int frame_size; + int nsamples; + nframes=opus_packet_get_nb_frames(_data,_len); + if(OP_UNLIKELY(nframes<0))return OP_EBADPACKET; + frame_size=opus_packet_get_samples_per_frame(_data,48000); + nsamples=nframes*frame_size; + if(OP_UNLIKELY(nsamples>120*48))return OP_EBADPACKET; + return nsamples; +} + +/*This function more properly belongs in info.c, but we define it here to allow + the static granule position manipulation functions to remain static.*/ +ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp){ + opus_int32 pre_skip; + pre_skip=_head->pre_skip; + if(_gp!=-1&&op_granpos_add(&_gp,_gp,-pre_skip))_gp=-1; + return _gp; +} + +/*Grab all the packets currently in the stream state, and compute their + durations. + _of->op_count is set to the number of packets collected. + [out] _durations: Returns the durations of the individual packets. + Return: The total duration of all packets, or OP_HOLE if there was a hole.*/ +static opus_int32 op_collect_audio_packets(OggOpusFile *_of, + int _durations[255]){ + opus_int32 total_duration; + int op_count; + /*Count the durations of all packets in the page.*/ + op_count=0; + total_duration=0; + for(;;){ + int ret; + /*This takes advantage of undocumented libogg behavior that returned + ogg_packet buffers are valid at least until the next page is + submitted. + Relying on this is not too terrible, as _none_ of the Ogg memory + ownership/lifetime rules are well-documented. + But I can read its code and know this will work.*/ + ret=ogg_stream_packetout(&_of->os,_of->op+op_count); + if(!ret)break; + if(OP_UNLIKELY(ret<0)){ + /*We shouldn't get holes in the middle of pages.*/ + OP_ASSERT(op_count==0); + /*Set the return value and break out of the loop. + We want to make sure op_count gets set to 0, because we've ingested a + page, so any previously loaded packets are now invalid.*/ + total_duration=OP_HOLE; + break; + } + /*Unless libogg is broken, we can't get more than 255 packets from a + single page.*/ + OP_ASSERT(op_count<255); + _durations[op_count]=op_get_packet_duration(_of->op[op_count].packet, + _of->op[op_count].bytes); + if(OP_LIKELY(_durations[op_count]>0)){ + /*With at most 255 packets on a page, this can't overflow.*/ + total_duration+=_durations[op_count++]; + } + /*Ignore packets with an invalid TOC sequence.*/ + else if(op_count>0){ + /*But save the granule position, if there was one.*/ + _of->op[op_count-1].granulepos=_of->op[op_count].granulepos; + } + } + _of->op_pos=0; + _of->op_count=op_count; + return total_duration; +} + +/*Starting from current cursor position, get the initial PCM offset of the next + page. + This also validates the granule position on the first page with a completed + audio data packet, as required by the spec. + If this link is completely empty (no pages with completed packets), then this + function sets pcm_start=pcm_end=0 and returns the BOS page of the next link + (if any). + In the seekable case, we initialize pcm_end=-1 before calling this function, + so that later we can detect that the link was empty before calling + op_find_final_pcm_offset(). + [inout] _link: The link for which to find pcm_start. + [out] _og: Returns the BOS page of the next link if this link was empty. + In the unseekable case, we can then feed this to + op_fetch_headers() to start the next link. + The caller may pass NULL (e.g., for seekable streams), in + which case this page will be discarded. + Return: 0 on success, 1 if there is a buffered BOS page available, or a + negative value on unrecoverable error.*/ +static int op_find_initial_pcm_offset(OggOpusFile *_of, + OggOpusLink *_link,ogg_page *_og){ + ogg_page og; + opus_int64 page_offset; + ogg_int64_t pcm_start; + ogg_int64_t prev_packet_gp; + ogg_int64_t cur_page_gp; + ogg_uint32_t serialno; + opus_int32 total_duration; + int durations[255]; + int cur_page_eos; + int op_count; + int pi; + if(_og==NULL)_og=&og; + serialno=_of->os.serialno; + op_count=0; + /*We shouldn't have to initialize total_duration, but gcc is too dumb to + figure out that op_count>0 implies we've been through the whole loop at + least once.*/ + total_duration=0; + do{ + page_offset=op_get_next_page(_of,_og,_of->end); + /*We should get a page unless the file is truncated or mangled. + Otherwise there are no audio data packets in the whole logical stream.*/ + if(OP_UNLIKELY(page_offset<0)){ + /*Fail if there was a read error.*/ + if(page_offsethead.pre_skip>0)return OP_EBADTIMESTAMP; + _link->pcm_file_offset=0; + /*Set pcm_end and end_offset so we can skip the call to + op_find_final_pcm_offset().*/ + _link->pcm_start=_link->pcm_end=0; + _link->end_offset=_link->data_offset; + return 0; + } + /*Similarly, if we hit the next link in the chain, we've gone too far.*/ + if(OP_UNLIKELY(ogg_page_bos(_og))){ + if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP; + /*Set pcm_end and end_offset so we can skip the call to + op_find_final_pcm_offset().*/ + _link->pcm_file_offset=0; + _link->pcm_start=_link->pcm_end=0; + _link->end_offset=_link->data_offset; + /*Tell the caller we've got a buffered page for them.*/ + return 1; + } + /*Ignore pages from other streams (not strictly necessary, because of the + checks in ogg_stream_pagein(), but saves some work).*/ + if(serialno!=(ogg_uint32_t)ogg_page_serialno(_og))continue; + ogg_stream_pagein(&_of->os,_og); + /*Bitrate tracking: add the header's bytes here. + The body bytes are counted when we consume the packets.*/ + _of->bytes_tracked+=_og->header_len; + /*Count the durations of all packets in the page.*/ + do total_duration=op_collect_audio_packets(_of,durations); + /*Ignore holes.*/ + while(OP_UNLIKELY(total_duration<0)); + op_count=_of->op_count; + } + while(op_count<=0); + /*We found the first page with a completed audio data packet: actually look + at the granule position. + RFC 3533 says, "A special value of -1 (in two's complement) indicates that + no packets finish on this page," which does not say that a granule + position that is NOT -1 indicates that some packets DO finish on that page + (even though this was the intention, libogg itself violated this intention + for years before we fixed it). + The Ogg Opus specification only imposes its start-time requirements + on the granule position of the first page with completed packets, + so we ignore any set granule positions until then.*/ + cur_page_gp=_of->op[op_count-1].granulepos; + /*But getting a packet without a valid granule position on the page is not + okay.*/ + if(cur_page_gp==-1)return OP_EBADTIMESTAMP; + cur_page_eos=_of->op[op_count-1].e_o_s; + if(OP_LIKELY(!cur_page_eos)){ + /*The EOS flag wasn't set. + Work backwards from the provided granule position to get the starting PCM + offset.*/ + if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){ + /*The starting granule position MUST not be smaller than the amount of + audio on the first page with completed packets.*/ + return OP_EBADTIMESTAMP; + } + } + else{ + /*The first page with completed packets was also the last.*/ + if(OP_LIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){ + /*If there's less audio on the page than indicated by the granule + position, then we're doing end-trimming, and the starting PCM offset + is zero by spec mandate.*/ + pcm_start=0; + /*However, the end-trimming MUST not ask us to trim more samples than + exist after applying the pre-skip.*/ + if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){ + return OP_EBADTIMESTAMP; + } + } + } + /*Timestamp the individual packets.*/ + prev_packet_gp=pcm_start; + for(pi=0;pi0){ + /*If we trimmed the entire packet, stop (the spec says encoders + shouldn't do this, but we support it anyway).*/ + if(OP_UNLIKELY(diff>durations[pi]))break; + _of->op[pi].granulepos=prev_packet_gp=cur_page_gp; + /*Move the EOS flag to this packet, if necessary, so we'll trim the + samples.*/ + _of->op[pi].e_o_s=1; + continue; + } + } + /*Update the granule position as normal.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&_of->op[pi].granulepos, + prev_packet_gp,durations[pi])); + prev_packet_gp=_of->op[pi].granulepos; + } + /*Update the packet count after end-trimming.*/ + _of->op_count=pi; + _of->cur_discard_count=_link->head.pre_skip; + _link->pcm_file_offset=0; + _of->prev_packet_gp=_link->pcm_start=pcm_start; + _of->prev_page_offset=page_offset; + return 0; +} + +/*Starting from current cursor position, get the final PCM offset of the + previous page. + This also validates the duration of the link, which, while not strictly + required by the spec, we need to ensure duration calculations don't + overflow. + This is only done for seekable sources. + We must validate that op_find_initial_pcm_offset() succeeded for this link + before calling this function, otherwise it will scan the entire stream + backwards until it reaches the start, and then fail.*/ +static int op_find_final_pcm_offset(OggOpusFile *_of, + const ogg_uint32_t *_serialnos,int _nserialnos,OggOpusLink *_link, + opus_int64 _offset,ogg_uint32_t _end_serialno,ogg_int64_t _end_gp, + ogg_int64_t *_total_duration){ + ogg_int64_t total_duration; + ogg_int64_t duration; + ogg_uint32_t cur_serialno; + /*For the time being, fetch end PCM offset the simple way.*/ + cur_serialno=_link->serialno; + if(_end_serialno!=cur_serialno||_end_gp==-1){ + _offset=op_get_last_page(_of,&_end_gp,_offset, + cur_serialno,_serialnos,_nserialnos); + if(OP_UNLIKELY(_offset<0))return (int)_offset; + } + /*At worst we should have found the first page with completed packets.*/ + if(OP_UNLIKELY(_offset<_link->data_offset))return OP_EBADLINK; + /*This implementation requires that the difference between the first and last + granule positions in each link be representable in a signed, 64-bit + number, and that each link also have at least as many samples as the + pre-skip requires.*/ + if(OP_UNLIKELY(op_granpos_diff(&duration,_end_gp,_link->pcm_start)<0) + ||OP_UNLIKELY(duration<_link->head.pre_skip)){ + return OP_EBADTIMESTAMP; + } + /*We also require that the total duration be representable in a signed, + 64-bit number.*/ + duration-=_link->head.pre_skip; + total_duration=*_total_duration; + if(OP_UNLIKELY(OP_INT64_MAX-durationpcm_end=_end_gp; + _link->end_offset=_offset; + return 0; +} + +/*Rescale the number _x from the range [0,_from] to [0,_to]. + _from and _to must be positive.*/ +static opus_int64 op_rescale64(opus_int64 _x,opus_int64 _from,opus_int64 _to){ + opus_int64 frac; + opus_int64 ret; + int i; + if(_x>=_from)return _to; + if(_x<=0)return 0; + frac=0; + for(i=0;i<63;i++){ + frac<<=1; + OP_ASSERT(_x<=_from); + if(_x>=_from>>1){ + _x-=_from-_x; + frac|=1; + } + else _x<<=1; + } + ret=0; + for(i=0;i<63;i++){ + if(frac&1)ret=(ret&_to&1)+(ret>>1)+(_to>>1); + else ret>>=1; + frac>>=1; + } + return ret; +} + +/*The minimum granule position spacing allowed for making predictions. + This corresponds to about 1 second of audio at 48 kHz for both Opus and + Vorbis, or one keyframe interval in Theora with the default keyframe spacing + of 256.*/ +#define OP_GP_SPACING_MIN (48000) + +/*Try to estimate the location of the next link using the current seek + records, assuming the initial granule position of any streams we've found is + 0.*/ +static opus_int64 op_predict_link_start(const OpusSeekRecord *_sr,int _nsr, + opus_int64 _searched,opus_int64 _end_searched,opus_int32 _bias){ + opus_int64 bisect; + int sri; + int srj; + /*Require that we be at least OP_CHUNK_SIZE from the end. + We don't require that we be at least OP_CHUNK_SIZE from the beginning, + because if we are we'll just scan forward without seeking.*/ + _end_searched-=OP_CHUNK_SIZE; + if(_searched>=_end_searched)return -1; + bisect=_end_searched; + for(sri=0;sri<_nsr;sri++){ + ogg_int64_t gp1; + ogg_int64_t gp2_min; + ogg_uint32_t serialno1; + opus_int64 offset1; + /*If the granule position is negative, either it's invalid or we'd cause + overflow.*/ + gp1=_sr[sri].gp; + if(gp1<0)continue; + /*We require some minimum distance between granule positions to make an + estimate. + We don't actually know what granule position scheme is being used, + because we have no idea what kind of stream these came from. + Therefore we require a minimum spacing between them, with the + expectation that while bitrates and granule position increments might + vary locally in quite complex ways, they are globally smooth.*/ + if(OP_UNLIKELY(op_granpos_add(&gp2_min,gp1,OP_GP_SPACING_MIN)<0)){ + /*No granule position would satisfy us.*/ + continue; + } + offset1=_sr[sri].offset; + serialno1=_sr[sri].serialno; + for(srj=sri;srj-->0;){ + ogg_int64_t gp2; + opus_int64 offset2; + opus_int64 num; + ogg_int64_t den; + ogg_int64_t ipart; + gp2=_sr[srj].gp; + if(gp20); + if(ipart>0&&(offset2-_searched)/ipart=_end_searched?-1:bisect; +} + +/*Finds each bitstream link, one at a time, using a bisection search. + This has to begin by knowing the offset of the first link's initial page.*/ +static int op_bisect_forward_serialno(OggOpusFile *_of, + opus_int64 _searched,OpusSeekRecord *_sr,int _csr, + ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){ + ogg_page og; + OggOpusLink *links; + int nlinks; + int clinks; + ogg_uint32_t *serialnos; + int nserialnos; + ogg_int64_t total_duration; + int nsr; + int ret; + links=_of->links; + nlinks=clinks=_of->nlinks; + total_duration=0; + /*We start with one seek record, for the last page in the file. + We build up a list of records for places we seek to during link + enumeration. + This list is kept sorted in reverse order. + We only care about seek locations that were _not_ in the current link, + therefore we can add them one at a time to the end of the list as we + improve the lower bound on the location where the next link starts.*/ + nsr=1; + for(;;){ + opus_int64 end_searched; + opus_int64 bisect; + opus_int64 next; + opus_int64 last; + ogg_int64_t end_offset; + ogg_int64_t end_gp; + int sri; + serialnos=*_serialnos; + nserialnos=*_nserialnos; + if(OP_UNLIKELY(nlinks>=clinks)){ + if(OP_UNLIKELY(clinks>INT_MAX-1>>1))return OP_EFAULT; + clinks=2*clinks+1; + OP_ASSERT(nlinkslinks=links; + } + /*Invariants: + We have the headers and serial numbers for the link beginning at 'begin'. + We have the offset and granule position of the last page in the file + (potentially not a page we care about).*/ + /*Scan the seek records we already have to save us some bisection.*/ + for(sri=0;sri1){ + opus_int64 last_offset; + opus_int64 avg_link_size; + opus_int64 upper_limit; + last_offset=links[nlinks-1].offset; + avg_link_size=last_offset/(nlinks-1); + upper_limit=end_searched-OP_CHUNK_SIZE-avg_link_size; + if(OP_LIKELY(last_offset>_searched-avg_link_size) + &&OP_LIKELY(last_offset>1); + /*If we're within OP_CHUNK_SIZE of the start, scan forward.*/ + if(bisect-_searchedoffset-last>=0); + OP_ASSERT(_of->offset-last<=OP_PAGE_SIZE_MAX); + _sr[nsr].size=(opus_int32)(_of->offset-last); + _sr[nsr].serialno=serialno; + _sr[nsr].gp=gp; + nsr++; + } + } + else{ + _searched=_of->offset; + next_bias=OP_CHUNK_SIZE; + if(serialno==links[nlinks-1].serialno){ + /*This page was from the stream we want, remember it. + If it's the last such page in the link, we won't have to go back + looking for it later.*/ + end_gp=gp; + end_offset=last; + } + } + } + bisect=op_predict_link_start(_sr,nsr,_searched,end_searched,next_bias); + } + /*Bisection point found. + Get the final granule position of the previous link, assuming + op_find_initial_pcm_offset() didn't already determine the link was + empty.*/ + if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){ + if(end_gp==-1){ + /*If we don't know where the end page is, we'll have to seek back and + look for it, starting from the end of the link.*/ + end_offset=next; + /*Also forget the last page we read. + It won't be available after the seek.*/ + last=-1; + } + ret=op_find_final_pcm_offset(_of,serialnos,nserialnos, + links+nlinks-1,end_offset,links[nlinks-1].serialno,end_gp, + &total_duration); + if(OP_UNLIKELY(ret<0))return ret; + } + if(last!=next){ + /*The last page we read was not the first page the next link. + Move the cursor position to the offset of that first page. + This only performs an actual seek if the first page of the next link + does not start at the end of the last page from the current Opus + stream with a valid granule position.*/ + ret=op_seek_helper(_of,next); + if(OP_UNLIKELY(ret<0))return ret; + } + ret=op_fetch_headers(_of,&links[nlinks].head,&links[nlinks].tags, + _serialnos,_nserialnos,_cserialnos,last!=next?NULL:&og); + if(OP_UNLIKELY(ret<0))return ret; + links[nlinks].offset=next; + links[nlinks].data_offset=_of->offset; + links[nlinks].serialno=_of->os.serialno; + links[nlinks].pcm_end=-1; + /*This might consume a page from the next link, however the next bisection + always starts with a seek.*/ + ret=op_find_initial_pcm_offset(_of,links+nlinks,NULL); + if(OP_UNLIKELY(ret<0))return ret; + links[nlinks].pcm_file_offset=total_duration; + _searched=_of->offset; + /*Mark the current link count so it can be cleaned up on error.*/ + _of->nlinks=++nlinks; + } + /*Last page is in the starting serialno list, so we've reached the last link. + Now find the last granule position for it (if we didn't the first time we + looked at the end of the stream, and if op_find_initial_pcm_offset() + didn't already determine the link was empty).*/ + if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){ + ret=op_find_final_pcm_offset(_of,serialnos,nserialnos, + links+nlinks-1,_sr[0].offset,_sr[0].serialno,_sr[0].gp,&total_duration); + if(OP_UNLIKELY(ret<0))return ret; + } + /*Trim back the links array if necessary.*/ + links=(OggOpusLink *)_ogg_realloc(links,sizeof(*links)*nlinks); + if(OP_LIKELY(links!=NULL))_of->links=links; + /*We also don't need these anymore.*/ + _ogg_free(*_serialnos); + *_serialnos=NULL; + *_cserialnos=*_nserialnos=0; + return 0; +} + +static void op_update_gain(OggOpusFile *_of){ + OpusHead *head; + opus_int32 gain_q8; + int li; + /*If decode isn't ready, then we'll apply the gain when we initialize the + decoder.*/ + if(_of->ready_stategain_offset_q8; + li=_of->seekable?_of->cur_link:0; + head=&_of->links[li].head; + /*We don't have to worry about overflow here because the header gain and + track gain must lie in the range [-32768,32767], and the user-supplied + offset has been pre-clamped to [-98302,98303].*/ + switch(_of->gain_type){ + case OP_ALBUM_GAIN:{ + int album_gain_q8; + album_gain_q8=0; + opus_tags_get_album_gain(&_of->links[li].tags,&album_gain_q8); + gain_q8+=album_gain_q8; + gain_q8+=head->output_gain; + }break; + case OP_TRACK_GAIN:{ + int track_gain_q8; + track_gain_q8=0; + opus_tags_get_track_gain(&_of->links[li].tags,&track_gain_q8); + gain_q8+=track_gain_q8; + gain_q8+=head->output_gain; + }break; + case OP_HEADER_GAIN:gain_q8+=head->output_gain;break; + case OP_ABSOLUTE_GAIN:break; + default:OP_ASSERT(0); + } + gain_q8=OP_CLAMP(-32768,gain_q8,32767); + OP_ASSERT(_of->od!=NULL); +#if defined(OPUS_SET_GAIN) + opus_multistream_decoder_ctl(_of->od,OPUS_SET_GAIN(gain_q8)); +#else +/*A fallback that works with both float and fixed-point is a bunch of work, + so just force people to use a sufficiently new version. + This is deployed well enough at this point that this shouldn't be a burden.*/ +# error "libopus 1.0.1 or later required" +#endif +} + +static int op_make_decode_ready(OggOpusFile *_of){ + const OpusHead *head; + int li; + int stream_count; + int coupled_count; + int channel_count; + if(_of->ready_state>OP_STREAMSET)return 0; + if(OP_UNLIKELY(_of->ready_stateseekable?_of->cur_link:0; + head=&_of->links[li].head; + stream_count=head->stream_count; + coupled_count=head->coupled_count; + channel_count=head->channel_count; + /*Check to see if the current decoder is compatible with the current link.*/ + if(_of->od!=NULL&&_of->od_stream_count==stream_count + &&_of->od_coupled_count==coupled_count&&_of->od_channel_count==channel_count + &&memcmp(_of->od_mapping,head->mapping, + sizeof(*head->mapping)*channel_count)==0){ + opus_multistream_decoder_ctl(_of->od,OPUS_RESET_STATE); + } + else{ + int err; + opus_multistream_decoder_destroy(_of->od); + _of->od=opus_multistream_decoder_create(48000,channel_count, + stream_count,coupled_count,head->mapping,&err); + if(_of->od==NULL)return OP_EFAULT; + _of->od_stream_count=stream_count; + _of->od_coupled_count=coupled_count; + _of->od_channel_count=channel_count; + memcpy(_of->od_mapping,head->mapping,sizeof(*head->mapping)*channel_count); + } + _of->ready_state=OP_INITSET; + _of->bytes_tracked=0; + _of->samples_tracked=0; +#if !defined(OP_FIXED_POINT) + _of->state_channel_count=0; + /*Use the serial number for the PRNG seed to get repeatable output for + straight play-throughs.*/ + _of->dither_seed=_of->links[li].serialno; +#endif + op_update_gain(_of); + return 0; +} + +static int op_open_seekable2_impl(OggOpusFile *_of){ + /*64 seek records should be enough for anybody. + Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE + granularity, much more than enough.*/ + OpusSeekRecord sr[64]; + opus_int64 data_offset; + int ret; + /*We can seek, so set out learning all about this file.*/ + (*_of->callbacks.seek)(_of->stream,0,SEEK_END); + _of->offset=_of->end=(*_of->callbacks.tell)(_of->stream); + if(OP_UNLIKELY(_of->end<0))return OP_EREAD; + data_offset=_of->links[0].data_offset; + if(OP_UNLIKELY(_of->endend, + _of->links[0].serialno,_of->serialnos,_of->nserialnos); + if(OP_UNLIKELY(ret<0))return ret; + /*If there's any trailing junk, forget about it.*/ + _of->end=sr[0].offset+sr[0].size; + if(OP_UNLIKELY(_of->endserialnos,&_of->nserialnos,&_of->cserialnos); +} + +static int op_open_seekable2(OggOpusFile *_of){ + ogg_sync_state oy_start; + ogg_stream_state os_start; + ogg_packet *op_start; + opus_int64 prev_page_offset; + opus_int64 start_offset; + int start_op_count; + int ret; + /*We're partially open and have a first link header state in storage in _of. + Save off that stream state so we can come back to it. + It would be simpler to just dump all this state and seek back to + links[0].data_offset when we're done. + But we do the extra work to allow us to seek back to _exactly_ the same + stream position we're at now. + This allows, e.g., the HTTP backend to continue reading from the original + connection (if it's still available), instead of opening a new one. + This means we can open and start playing a normal Opus file with a single + link and reasonable packet sizes using only two HTTP requests.*/ + start_op_count=_of->op_count; + /*This is a bit too large to put on the stack unconditionally.*/ + op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count); + if(op_start==NULL)return OP_EFAULT; + *&oy_start=_of->oy; + *&os_start=_of->os; + prev_page_offset=_of->prev_page_offset; + start_offset=_of->offset; + memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count); + OP_ASSERT((*_of->callbacks.tell)(_of->stream)==op_position(_of)); + ogg_sync_init(&_of->oy); + ogg_stream_init(&_of->os,-1); + ret=op_open_seekable2_impl(_of); + /*Restore the old stream state.*/ + ogg_stream_clear(&_of->os); + ogg_sync_clear(&_of->oy); + *&_of->oy=*&oy_start; + *&_of->os=*&os_start; + _of->offset=start_offset; + _of->op_count=start_op_count; + memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count); + _ogg_free(op_start); + _of->prev_packet_gp=_of->links[0].pcm_start; + _of->prev_page_offset=prev_page_offset; + _of->cur_discard_count=_of->links[0].head.pre_skip; + if(OP_UNLIKELY(ret<0))return ret; + /*And restore the position indicator.*/ + ret=(*_of->callbacks.seek)(_of->stream,op_position(_of),SEEK_SET); + return OP_UNLIKELY(ret<0)?OP_EREAD:0; +} + +/*Clear out the current logical bitstream decoder.*/ +static void op_decode_clear(OggOpusFile *_of){ + /*We don't actually free the decoder. + We might be able to re-use it for the next link.*/ + _of->op_count=0; + _of->od_buffer_size=0; + _of->prev_packet_gp=-1; + _of->prev_page_offset=-1; + if(!_of->seekable){ + OP_ASSERT(_of->ready_state>=OP_INITSET); + opus_tags_clear(&_of->links[0].tags); + } + _of->ready_state=OP_OPENED; +} + +static void op_clear(OggOpusFile *_of){ + OggOpusLink *links; + _ogg_free(_of->od_buffer); + if(_of->od!=NULL)opus_multistream_decoder_destroy(_of->od); + links=_of->links; + if(!_of->seekable){ + if(_of->ready_state>OP_OPENED||_of->ready_state==OP_PARTOPEN){ + opus_tags_clear(&links[0].tags); + } + } + else if(OP_LIKELY(links!=NULL)){ + int nlinks; + int link; + nlinks=_of->nlinks; + for(link=0;linkserialnos); + ogg_stream_clear(&_of->os); + ogg_sync_clear(&_of->oy); + if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->stream); +} + +static int op_open1(OggOpusFile *_of, + void *_stream,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes){ + ogg_page og; + ogg_page *pog; + int seekable; + int ret; + memset(_of,0,sizeof(*_of)); + if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT; + _of->end=-1; + _of->stream=_stream; + *&_of->callbacks=*_cb; + /*At a minimum, we need to be able to read data.*/ + if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD; + /*Initialize the framing state.*/ + ogg_sync_init(&_of->oy); + /*Perhaps some data was previously read into a buffer for testing against + other stream types. + Allow initialization from this previously read data (especially as we may + be reading from a non-seekable stream). + This requires copying it into a buffer allocated by ogg_sync_buffer() and + doesn't support seeking, so this is not a good mechanism to use for + decoding entire files from RAM.*/ + if(_initial_bytes>0){ + char *buffer; + buffer=ogg_sync_buffer(&_of->oy,(long)_initial_bytes); + memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer)); + ogg_sync_wrote(&_of->oy,(long)_initial_bytes); + } + /*Can we seek? + Stevens suggests the seek test is portable. + It's actually not for files on win32, but we address that by fixing it in + our callback implementation (see stream.c).*/ + seekable=_cb->seek!=NULL&&(*_cb->seek)(_stream,0,SEEK_CUR)!=-1; + /*If seek is implemented, tell must also be implemented.*/ + if(seekable){ + opus_int64 pos; + if(OP_UNLIKELY(_of->callbacks.tell==NULL))return OP_EINVAL; + pos=(*_of->callbacks.tell)(_of->stream); + /*If the current position is not equal to the initial bytes consumed, + absolute seeking will not work.*/ + if(OP_UNLIKELY(pos!=(opus_int64)_initial_bytes))return OP_EINVAL; + } + _of->seekable=seekable; + /*Don't seek yet. + Set up a 'single' (current) logical bitstream entry for partial open.*/ + _of->links=(OggOpusLink *)_ogg_malloc(sizeof(*_of->links)); + /*The serialno gets filled in later by op_fetch_headers().*/ + ogg_stream_init(&_of->os,-1); + pog=NULL; + for(;;){ + /*Fetch all BOS pages, store the Opus header and all seen serial numbers, + and load subsequent Opus setup headers.*/ + ret=op_fetch_headers(_of,&_of->links[0].head,&_of->links[0].tags, + &_of->serialnos,&_of->nserialnos,&_of->cserialnos,pog); + if(OP_UNLIKELY(ret<0))break; + _of->nlinks=1; + _of->links[0].offset=0; + _of->links[0].data_offset=_of->offset; + _of->links[0].pcm_end=-1; + _of->links[0].serialno=_of->os.serialno; + /*Fetch the initial PCM offset.*/ + ret=op_find_initial_pcm_offset(_of,_of->links,&og); + if(seekable||OP_LIKELY(ret<=0))break; + /*This link was empty, but we already have the BOS page for the next one in + og. + We can't seek, so start processing the next link right now.*/ + opus_tags_clear(&_of->links[0].tags); + _of->nlinks=0; + if(!seekable)_of->cur_link++; + pog=&og; + } + if(OP_LIKELY(ret>=0))_of->ready_state=OP_PARTOPEN; + return ret; +} + +static int op_open2(OggOpusFile *_of){ + int ret; + OP_ASSERT(_of->ready_state==OP_PARTOPEN); + if(_of->seekable){ + _of->ready_state=OP_OPENED; + ret=op_open_seekable2(_of); + } + else ret=0; + if(OP_LIKELY(ret>=0)){ + /*We have buffered packets from op_find_initial_pcm_offset(). + Move to OP_INITSET so we can use them.*/ + _of->ready_state=OP_STREAMSET; + ret=op_make_decode_ready(_of); + if(OP_LIKELY(ret>=0))return 0; + } + /*Don't auto-close the stream on failure.*/ + _of->callbacks.close=NULL; + op_clear(_of); + return ret; +} + +OggOpusFile *op_test_callbacks(void *_stream,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes,int *_error){ + OggOpusFile *of; + int ret; + of=(OggOpusFile *)_ogg_malloc(sizeof(*of)); + ret=OP_EFAULT; + if(OP_LIKELY(of!=NULL)){ + ret=op_open1(of,_stream,_cb,_initial_data,_initial_bytes); + if(OP_LIKELY(ret>=0)){ + if(_error!=NULL)*_error=0; + return of; + } + /*Don't auto-close the stream on failure.*/ + of->callbacks.close=NULL; + op_clear(of); + _ogg_free(of); + } + if(_error!=NULL)*_error=ret; + return NULL; +} + +OggOpusFile *op_open_callbacks(void *_stream,const OpusFileCallbacks *_cb, + const unsigned char *_initial_data,size_t _initial_bytes,int *_error){ + OggOpusFile *of; + of=op_test_callbacks(_stream,_cb,_initial_data,_initial_bytes,_error); + if(OP_LIKELY(of!=NULL)){ + int ret; + ret=op_open2(of); + if(OP_LIKELY(ret>=0))return of; + if(_error!=NULL)*_error=ret; + _ogg_free(of); + } + return NULL; +} + +/*Convenience routine to clean up from failure for the open functions that + create their own streams.*/ +static OggOpusFile *op_open_close_on_failure(void *_stream, + const OpusFileCallbacks *_cb,int *_error){ + OggOpusFile *of; + if(OP_UNLIKELY(_stream==NULL)){ + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_open_callbacks(_stream,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_stream); + return of; +} + +OggOpusFile *op_open_file(const char *_path,int *_error){ + OpusFileCallbacks cb; + return op_open_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error); +} + +OggOpusFile *op_open_memory(const unsigned char *_data,size_t _size, + int *_error){ + OpusFileCallbacks cb; + return op_open_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb, + _error); +} + +/*Convenience routine to clean up from failure for the open functions that + create their own streams.*/ +static OggOpusFile *op_test_close_on_failure(void *_stream, + const OpusFileCallbacks *_cb,int *_error){ + OggOpusFile *of; + if(OP_UNLIKELY(_stream==NULL)){ + if(_error!=NULL)*_error=OP_EFAULT; + return NULL; + } + of=op_test_callbacks(_stream,_cb,NULL,0,_error); + if(OP_UNLIKELY(of==NULL))(*_cb->close)(_stream); + return of; +} + +OggOpusFile *op_test_file(const char *_path,int *_error){ + OpusFileCallbacks cb; + return op_test_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error); +} + +OggOpusFile *op_test_memory(const unsigned char *_data,size_t _size, + int *_error){ + OpusFileCallbacks cb; + return op_test_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb, + _error); +} + +int op_test_open(OggOpusFile *_of){ + int ret; + if(OP_UNLIKELY(_of->ready_state!=OP_PARTOPEN))return OP_EINVAL; + ret=op_open2(_of); + /*op_open2() will clear this structure on failure. + Reset its contents to prevent double-frees in op_free().*/ + if(OP_UNLIKELY(ret<0))memset(_of,0,sizeof(*_of)); + return ret; +} + +void op_free(OggOpusFile *_of){ + if(OP_LIKELY(_of!=NULL)){ + op_clear(_of); + _ogg_free(_of); + } +} + +int op_seekable(const OggOpusFile *_of){ + return _of->seekable; +} + +int op_link_count(const OggOpusFile *_of){ + return _of->nlinks; +} + +opus_uint32 op_serialno(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable)_li=0; + return _of->links[_li<0?_of->cur_link:_li].serialno; +} + +int op_channel_count(const OggOpusFile *_of,int _li){ + return op_head(_of,_li)->channel_count; +} + +opus_int64 op_raw_total(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=_of->nlinks)){ + return OP_EINVAL; + } + if(_li<0)return _of->end; + return (_li+1>=_of->nlinks?_of->end:_of->links[_li+1].offset) + -(_li>0?_of->links[_li].offset:0); +} + +ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){ + OggOpusLink *links; + ogg_int64_t pcm_total; + ogg_int64_t diff; + int nlinks; + nlinks=_of->nlinks; + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=nlinks)){ + return OP_EINVAL; + } + links=_of->links; + /*We verify that the granule position differences are larger than the + pre-skip and that the total duration does not overflow during link + enumeration, so we don't have to check here.*/ + pcm_total=0; + if(_li<0){ + pcm_total=links[nlinks-1].pcm_file_offset; + _li=nlinks-1; + } + OP_ALWAYS_TRUE(!op_granpos_diff(&diff, + links[_li].pcm_end,links[_li].pcm_start)); + return pcm_total+diff-links[_li].head.pre_skip; +} + +const OpusHead *op_head(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable)_li=0; + return &_of->links[_li<0?_of->cur_link:_li].head; +} + +const OpusTags *op_tags(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1; + if(!_of->seekable){ + if(_of->ready_stateready_state!=OP_PARTOPEN){ + return NULL; + } + _li=0; + } + else if(_li<0)_li=_of->ready_state>=OP_STREAMSET?_of->cur_link:0; + return &_of->links[_li].tags; +} + +int op_current_link(const OggOpusFile *_of){ + if(OP_UNLIKELY(_of->ready_statecur_link; +} + +/*Compute an average bitrate given a byte and sample count. + Return: The bitrate in bits per second.*/ +static opus_int32 op_calc_bitrate(opus_int64 _bytes,ogg_int64_t _samples){ + if(OP_UNLIKELY(_samples<=0))return OP_INT32_MAX; + /*These rates are absurd, but let's handle them anyway.*/ + if(OP_UNLIKELY(_bytes>(OP_INT64_MAX-(_samples>>1))/(48000*8))){ + ogg_int64_t den; + if(OP_UNLIKELY(_bytes/(OP_INT32_MAX/(48000*8))>=_samples)){ + return OP_INT32_MAX; + } + den=_samples/(48000*8); + return (opus_int32)((_bytes+(den>>1))/den); + } + /*This can't actually overflow in normal operation: even with a pre-skip of + 545 2.5 ms frames with 8 streams running at 1282*8+1 bytes per packet + (1275 byte frames + Opus framing overhead + Ogg lacing values), that all + produce a single sample of decoded output, we still don't top 45 Mbps. + The only way to get bitrates larger than that is with excessive Opus + padding, more encoded streams than output channels, or lots and lots of + Ogg pages with no packets on them.*/ + return (opus_int32)OP_MIN((_bytes*48000*8+(_samples>>1))/_samples, + OP_INT32_MAX); +} + +opus_int32 op_bitrate(const OggOpusFile *_of,int _li){ + if(OP_UNLIKELY(_of->ready_stateseekable) + ||OP_UNLIKELY(_li>=_of->nlinks)){ + return OP_EINVAL; + } + return op_calc_bitrate(op_raw_total(_of,_li),op_pcm_total(_of,_li)); +} + +opus_int32 op_bitrate_instant(OggOpusFile *_of){ + ogg_int64_t samples_tracked; + opus_int32 ret; + if(OP_UNLIKELY(_of->ready_statesamples_tracked; + if(OP_UNLIKELY(samples_tracked==0))return OP_FALSE; + ret=op_calc_bitrate(_of->bytes_tracked,samples_tracked); + _of->bytes_tracked=0; + _of->samples_tracked=0; + return ret; +} + +/*Given a serialno, find a link with a corresponding Opus stream, if it exists. + Return: The index of the link to which the page belongs, or a negative number + if it was not a desired Opus bitstream section.*/ +static int op_get_link_from_serialno(const OggOpusFile *_of,int _cur_link, + opus_int64 _page_offset,ogg_uint32_t _serialno){ + const OggOpusLink *links; + int nlinks; + int li_lo; + int li_hi; + OP_ASSERT(_of->seekable); + links=_of->links; + nlinks=_of->nlinks; + li_lo=0; + /*Start off by guessing we're just a multiplexed page in the current link.*/ + li_hi=_cur_link+1=links[_cur_link].offset)li_lo=_cur_link; + else li_hi=_cur_link; + _cur_link=li_lo+(li_hi-li_lo>>1); + } + while(li_hi-li_lo>1); + /*We've identified the link that should contain this page. + Make sure it's a page we care about.*/ + if(links[_cur_link].serialno!=_serialno)return OP_FALSE; + return _cur_link; +} + +/*Fetch and process a page. + This handles the case where we're at a bitstream boundary and dumps the + decoding machine. + If the decoding machine is unloaded, it loads it. + It also keeps prev_packet_gp up to date (seek and read both use this). + Return: <0) Error, OP_HOLE (lost packet), or OP_EOF. + 0) Got at least one audio data packet.*/ +static int op_fetch_and_process_page(OggOpusFile *_of, + ogg_page *_og,opus_int64 _page_offset,int _spanp,int _ignore_holes){ + OggOpusLink *links; + ogg_uint32_t cur_serialno; + int seekable; + int cur_link; + int ret; + /*We shouldn't get here if we have unprocessed packets.*/ + OP_ASSERT(_of->ready_stateop_pos>=_of->op_count); + seekable=_of->seekable; + links=_of->links; + cur_link=seekable?_of->cur_link:0; + cur_serialno=links[cur_link].serialno; + /*Handle one page.*/ + for(;;){ + ogg_page og; + OP_ASSERT(_of->ready_state>=OP_OPENED); + /*If we were given a page to use, use it.*/ + if(_og!=NULL){ + *&og=*_og; + _og=NULL; + } + /*Keep reading until we get a page with the correct serialno.*/ + else _page_offset=op_get_next_page(_of,&og,_of->end); + /*EOF: Leave uninitialized.*/ + if(_page_offset<0)return _page_offsetready_state>=OP_STREAMSET) + &&cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){ + /*Two possibilities: + 1) Another stream is multiplexed into this logical section, or*/ + if(OP_LIKELY(!ogg_page_bos(&og)))continue; + /* 2) Our decoding just traversed a bitstream boundary.*/ + if(!_spanp)return OP_EOF; + if(OP_LIKELY(_of->ready_state>=OP_INITSET))op_decode_clear(_of); + } + /*Bitrate tracking: add the header's bytes here. + The body bytes are counted when we consume the packets.*/ + else _of->bytes_tracked+=og.header_len; + /*Do we need to load a new machine before submitting the page? + This is different in the seekable and non-seekable cases. + In the seekable case, we already have all the header information loaded + and cached. + We just initialize the machine with it and continue on our merry way. + In the non-seekable (streaming) case, we'll only be at a boundary if we + just left the previous logical bitstream, and we're now nominally at the + header of the next bitstream.*/ + if(OP_UNLIKELY(_of->ready_state=0&&cur_link<_of->nlinks); + if(links[cur_link].serialno!=serialno){ + /*It wasn't a page from the current link. + Is it from the next one?*/ + if(OP_LIKELY(cur_link+1<_of->nlinks&&links[cur_link+1].serialno== + serialno)){ + cur_link++; + } + else{ + int new_link; + new_link= + op_get_link_from_serialno(_of,cur_link,_page_offset,serialno); + /*Not a desired Opus bitstream section. + Keep trying.*/ + if(new_link<0)continue; + cur_link=new_link; + } + } + cur_serialno=serialno; + _of->cur_link=cur_link; + ogg_stream_reset_serialno(&_of->os,serialno); + _of->ready_state=OP_STREAMSET; + /*If we're at the start of this link, initialize the granule position + and pre-skip tracking.*/ + if(_page_offset<=links[cur_link].data_offset){ + _of->prev_packet_gp=links[cur_link].pcm_start; + _of->prev_page_offset=-1; + _of->cur_discard_count=links[cur_link].head.pre_skip; + /*Ignore a hole at the start of a new link (this is common for + streams joined in the middle) or after seeking.*/ + _ignore_holes=1; + } + } + else{ + do{ + /*We're streaming. + Fetch the two header packets, build the info struct.*/ + ret=op_fetch_headers(_of,&links[0].head,&links[0].tags, + NULL,NULL,NULL,&og); + if(OP_UNLIKELY(ret<0))return ret; + /*op_find_initial_pcm_offset() will suppress any initial hole for us, + so no need to set _ignore_holes.*/ + ret=op_find_initial_pcm_offset(_of,links,&og); + if(OP_UNLIKELY(ret<0))return ret; + _of->links[0].serialno=cur_serialno=_of->os.serialno; + _of->cur_link++; + } + /*If the link was empty, keep going, because we already have the + BOS page of the next one in og.*/ + while(OP_UNLIKELY(ret>0)); + /*If we didn't get any packets out of op_find_initial_pcm_offset(), + keep going (this is possible if end-trimming trimmed them all).*/ + if(_of->op_count<=0)continue; + /*Otherwise, we're done. + TODO: This resets bytes_tracked, which misses the header bytes + already processed by op_find_initial_pcm_offset().*/ + ret=op_make_decode_ready(_of); + if(OP_UNLIKELY(ret<0))return ret; + return 0; + } + } + /*The buffered page is the data we want, and we're ready for it. + Add it to the stream state.*/ + if(OP_UNLIKELY(_of->ready_state==OP_STREAMSET)){ + ret=op_make_decode_ready(_of); + if(OP_UNLIKELY(ret<0))return ret; + } + /*Extract all the packets from the current page.*/ + ogg_stream_pagein(&_of->os,&og); + if(OP_LIKELY(_of->ready_state>=OP_INITSET)){ + opus_int32 total_duration; + int durations[255]; + int op_count; + int report_hole; + report_hole=0; + total_duration=op_collect_audio_packets(_of,durations); + if(OP_UNLIKELY(total_duration<0)){ + /*libogg reported a hole (a gap in the page sequence numbers). + Drain the packets from the page anyway. + If we don't, they'll still be there when we fetch the next page. + Then, when we go to pull out packets, we might get more than 255, + which would overrun our packet buffer. + We repeat this call until we get any actual packets, since we might + have buffered multiple out-of-sequence pages with no packets on + them.*/ + do total_duration=op_collect_audio_packets(_of,durations); + while(total_duration<0); + if(!_ignore_holes){ + /*Report the hole to the caller after we finish timestamping the + packets.*/ + report_hole=1; + /*We had lost or damaged pages, so reset our granule position + tracking. + This makes holes behave the same as a small raw seek. + If the next page is the EOS page, we'll discard it (because we + can't perform end trimming properly), and we'll always discard at + least 80 ms of audio (to allow decoder state to re-converge). + We could try to fill in the gap with PLC by looking at timestamps + in the non-EOS case, but that's complicated and error prone and we + can't rely on the timestamps being valid.*/ + _of->prev_packet_gp=-1; + } + } + op_count=_of->op_count; + /*If we found at least one audio data packet, compute per-packet granule + positions for them.*/ + if(op_count>0){ + ogg_int64_t diff; + ogg_int64_t prev_packet_gp; + ogg_int64_t cur_packet_gp; + ogg_int64_t cur_page_gp; + int cur_page_eos; + int pi; + cur_page_gp=_of->op[op_count-1].granulepos; + cur_page_eos=_of->op[op_count-1].e_o_s; + prev_packet_gp=_of->prev_packet_gp; + if(OP_UNLIKELY(prev_packet_gp==-1)){ + opus_int32 cur_discard_count; + /*This is the first call after a raw seek. + Try to reconstruct prev_packet_gp from scratch.*/ + OP_ASSERT(seekable); + if(OP_UNLIKELY(cur_page_eos)){ + /*If the first page we hit after our seek was the EOS page, and + we didn't start from data_offset or before, we don't have + enough information to do end-trimming. + Proceed to the next link, rather than risk playing back some + samples that shouldn't have been played.*/ + _of->op_count=0; + if(report_hole)return OP_HOLE; + continue; + } + /*By default discard 80 ms of data after a seek, unless we seek + into the pre-skip region.*/ + cur_discard_count=80*48; + cur_page_gp=_of->op[op_count-1].granulepos; + /*Try to initialize prev_packet_gp. + If the current page had packets but didn't have a granule + position, or the granule position it had was too small (both + illegal), just use the starting granule position for the link.*/ + prev_packet_gp=links[cur_link].pcm_start; + if(OP_LIKELY(cur_page_gp!=-1)){ + op_granpos_add(&prev_packet_gp,cur_page_gp,-total_duration); + } + if(OP_LIKELY(!op_granpos_diff(&diff, + prev_packet_gp,links[cur_link].pcm_start))){ + opus_int32 pre_skip; + /*If we start at the beginning of the pre-skip region, or we're + at least 80 ms from the end of the pre-skip region, we discard + to the end of the pre-skip region. + Otherwise, we still use the 80 ms default, which will discard + past the end of the pre-skip region.*/ + pre_skip=links[cur_link].head.pre_skip; + if(diff>=0&&diff<=OP_MAX(0,pre_skip-80*48)){ + cur_discard_count=pre_skip-(int)diff; + } + } + _of->cur_discard_count=cur_discard_count; + } + if(OP_UNLIKELY(cur_page_gp==-1)){ + /*This page had completed packets but didn't have a valid granule + position. + This is illegal, but we'll try to handle it by continuing to count + forwards from the previous page.*/ + if(op_granpos_add(&cur_page_gp,prev_packet_gp,total_duration)<0){ + /*The timestamp for this page overflowed.*/ + cur_page_gp=links[cur_link].pcm_end; + } + } + /*If we hit the last page, handle end-trimming.*/ + if(OP_UNLIKELY(cur_page_eos) + &&OP_LIKELY(!op_granpos_diff(&diff,cur_page_gp,prev_packet_gp)) + &&OP_LIKELY(diff0){ + /*If we trimmed the entire packet, stop (the spec says encoders + shouldn't do this, but we support it anyway).*/ + if(OP_UNLIKELY(diff>durations[pi]))break; + cur_packet_gp=cur_page_gp; + /*Move the EOS flag to this packet, if necessary, so we'll trim + the samples during decode.*/ + _of->op[pi].e_o_s=1; + } + else{ + /*Update the granule position as normal.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp, + cur_packet_gp,durations[pi])); + } + _of->op[pi].granulepos=cur_packet_gp; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,cur_page_gp,cur_packet_gp)); + } + } + else{ + /*Propagate timestamps to earlier packets. + op_granpos_add(&prev_packet_gp,prev_packet_gp,total_duration) + should succeed and give prev_packet_gp==cur_page_gp. + But we don't bother to check that, as there isn't much we can do + if it's not true, and it actually will not be true on the first + page after a seek, if there was a continued packet. + The only thing we guarantee is that the start and end granule + positions of the packets are valid, and that they are monotonic + within a page. + They might be completely out of range for this link (we'll check + that elsewhere), or non-monotonic between pages.*/ + if(OP_UNLIKELY(op_granpos_add(&prev_packet_gp, + cur_page_gp,-total_duration)<0)){ + /*The starting timestamp for the first packet on this page + underflowed. + This is illegal, but we ignore it.*/ + prev_packet_gp=0; + } + for(pi=0;pi=0); + OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp, + cur_packet_gp,durations[pi])); + _of->op[pi].granulepos=cur_packet_gp; + } + OP_ASSERT(total_duration==0); + } + _of->prev_packet_gp=prev_packet_gp; + _of->prev_page_offset=_page_offset; + _of->op_count=op_count=pi; + } + if(report_hole)return OP_HOLE; + /*If end-trimming didn't trim all the packets, we're done.*/ + if(op_count>0)return 0; + } + } +} + +int op_raw_seek(OggOpusFile *_of,opus_int64 _pos){ + int ret; + if(OP_UNLIKELY(_of->ready_stateseekable))return OP_ENOSEEK; + if(OP_UNLIKELY(_pos<0)||OP_UNLIKELY(_pos>_of->end))return OP_EINVAL; + /*Clear out any buffered, decoded data.*/ + op_decode_clear(_of); + _of->bytes_tracked=0; + _of->samples_tracked=0; + ret=op_seek_helper(_of,_pos); + if(OP_UNLIKELY(ret<0))return OP_EREAD; + ret=op_fetch_and_process_page(_of,NULL,-1,1,1); + /*If we hit EOF, op_fetch_and_process_page() leaves us uninitialized. + Instead, jump to the end.*/ + if(ret==OP_EOF){ + int cur_link; + op_decode_clear(_of); + cur_link=_of->nlinks-1; + _of->cur_link=cur_link; + _of->prev_packet_gp=_of->links[cur_link].pcm_end; + _of->cur_discard_count=0; + ret=0; + } + return ret; +} + +/*Convert a PCM offset relative to the start of the whole stream to a granule + position in an individual link.*/ +static ogg_int64_t op_get_granulepos(const OggOpusFile *_of, + ogg_int64_t _pcm_offset,int *_li){ + const OggOpusLink *links; + ogg_int64_t duration; + ogg_int64_t pcm_start; + opus_int32 pre_skip; + int nlinks; + int li_lo; + int li_hi; + OP_ASSERT(_pcm_offset>=0); + nlinks=_of->nlinks; + links=_of->links; + li_lo=0; + li_hi=nlinks; + do{ + int li; + li=li_lo+(li_hi-li_lo>>1); + if(links[li].pcm_file_offset<=_pcm_offset)li_lo=li; + else li_hi=li; + } + while(li_hi-li_lo>1); + _pcm_offset-=links[li_lo].pcm_file_offset; + pcm_start=links[li_lo].pcm_start; + pre_skip=links[li_lo].head.pre_skip; + OP_ALWAYS_TRUE(!op_granpos_diff(&duration,links[li_lo].pcm_end,pcm_start)); + duration-=pre_skip; + if(_pcm_offset>=duration)return -1; + _pcm_offset+=pre_skip; + if(OP_UNLIKELY(pcm_start>OP_INT64_MAX-_pcm_offset)){ + /*Adding this amount to the granule position would overflow the positive + half of its 64-bit range. + Since signed overflow is undefined in C, do it in a way the compiler + isn't allowed to screw up.*/ + _pcm_offset-=OP_INT64_MAX-pcm_start+1; + pcm_start=OP_INT64_MIN; + } + pcm_start+=_pcm_offset; + *_li=li_lo; + return pcm_start; +} + +/*A small helper to determine if an Ogg page contains data that continues onto + a subsequent page.*/ +static int op_page_continues(const ogg_page *_og){ + int nlacing; + OP_ASSERT(_og->header_len>=27); + nlacing=_og->header[26]; + OP_ASSERT(_og->header_len>=27+nlacing); + /*This also correctly handles the (unlikely) case of nlacing==0, because + 0!=255.*/ + return _og->header[27+nlacing-1]==255; +} + +/*A small helper to buffer the continued packet data from a page.*/ +static void op_buffer_continued_data(OggOpusFile *_of,ogg_page *_og){ + ogg_packet op; + ogg_stream_pagein(&_of->os,_og); + /*Drain any packets that did end on this page (and ignore holes). + We only care about the continued packet data.*/ + while(ogg_stream_packetout(&_of->os,&op)); +} + +/*This controls how close the target has to be to use the current stream + position to subdivide the initial range. + Two minutes seems to be a good default.*/ +#define OP_CUR_TIME_THRESH (120*48*(opus_int32)1000) + +/*Note: The OP_SMALL_FOOTPRINT #define doesn't (currently) save much code size, + but it's meant to serve as documentation for portions of the seeking + algorithm that are purely optional, to aid others learning from/porting this + code to other contexts.*/ +/*#define OP_SMALL_FOOTPRINT (1)*/ + +/*Search within link _li for the page with the highest granule position + preceding (or equal to) _target_gp. + There is a danger here: missing pages or incorrect frame number information + in the bitstream could make our task impossible. + Account for that (and report it as an error condition).*/ +static int op_pcm_seek_page(OggOpusFile *_of, + ogg_int64_t _target_gp,int _li){ + const OggOpusLink *link; + ogg_page og; + ogg_int64_t pcm_pre_skip; + ogg_int64_t pcm_start; + ogg_int64_t pcm_end; + ogg_int64_t best_gp; + ogg_int64_t diff; + ogg_uint32_t serialno; + opus_int32 pre_skip; + opus_int64 begin; + opus_int64 end; + opus_int64 boundary; + opus_int64 best; + opus_int64 best_start; + opus_int64 page_offset; + opus_int64 d0; + opus_int64 d1; + opus_int64 d2; + int force_bisect; + int buffering; + int ret; + _of->bytes_tracked=0; + _of->samples_tracked=0; + link=_of->links+_li; + best_gp=pcm_start=link->pcm_start; + pcm_end=link->pcm_end; + serialno=link->serialno; + best=best_start=begin=link->data_offset; + page_offset=-1; + buffering=0; + /*We discard the first 80 ms of data after a seek, so seek back that much + farther. + If we can't, simply seek to the beginning of the link.*/ + if(OP_UNLIKELY(op_granpos_add(&_target_gp,_target_gp,-80*48)<0) + ||OP_UNLIKELY(op_granpos_cmp(_target_gp,pcm_start)<0)){ + _target_gp=pcm_start; + } + /*Special case seeking to the start of the link.*/ + pre_skip=link->head.pre_skip; + OP_ALWAYS_TRUE(!op_granpos_add(&pcm_pre_skip,pcm_start,pre_skip)); + if(op_granpos_cmp(_target_gp,pcm_pre_skip)<0)end=boundary=begin; + else{ + end=boundary=link->end_offset; +#if !defined(OP_SMALL_FOOTPRINT) + /*If we were decoding from this link, we can narrow the range a bit.*/ + if(_li==_of->cur_link&&_of->ready_state>=OP_INITSET){ + opus_int64 offset; + int op_count; + op_count=_of->op_count; + /*The only way the offset can be invalid _and_ we can fail the granule + position checks below is if someone changed the contents of the last + page since we read it. + We'd be within our rights to just return OP_EBADLINK in that case, but + we'll simply ignore the current position instead.*/ + offset=_of->offset; + if(op_count>0&&OP_LIKELY(offset<=end)){ + ogg_int64_t gp; + /*Make sure the timestamp is valid. + The granule position might be -1 if we collected the packets from a + page without a granule position after reporting a hole.*/ + gp=_of->op[op_count-1].granulepos; + if(OP_LIKELY(gp!=-1)&&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<0) + &&OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0)){ + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,gp,_target_gp)); + /*We only actually use the current time if either + a) We can cut off at least half the range, or + b) We're seeking sufficiently close to the current position that + it's likely to be informative. + Otherwise it appears using the whole link range to estimate the + first seek location gives better results, on average.*/ + if(diff<0){ + OP_ASSERT(offset>=begin); + if(offset-begin>=end-begin>>1||diff>-OP_CUR_TIME_THRESH){ + best=begin=offset; + best_gp=pcm_start=gp; + /*If we have buffered data from a continued packet, remember the + offset of the previous page's start, so that if we do wind up + having to seek back here later, we can prime the stream with + the continued packet data. + With no continued packet, we remember the end of the page.*/ + best_start=_of->os.body_returned<_of->os.body_fill? + _of->prev_page_offset:best; + /*If there's completed packets and data in the stream state, + prev_page_offset should always be set.*/ + OP_ASSERT(best_start>=0); + /*Buffer any continued packet data starting from here.*/ + buffering=1; + } + } + else{ + ogg_int64_t prev_page_gp; + /*We might get lucky and already have the packet with the target + buffered. + Worth checking. + For very small files (with all of the data in a single page, + generally 1 second or less), we can loop them continuously + without seeking at all.*/ + OP_ALWAYS_TRUE(!op_granpos_add(&prev_page_gp,_of->op[0].granulepos, + -op_get_packet_duration(_of->op[0].packet,_of->op[0].bytes))); + if(op_granpos_cmp(prev_page_gp,_target_gp)<=0){ + /*Don't call op_decode_clear(), because it will dump our + packets.*/ + _of->op_pos=0; + _of->od_buffer_size=0; + _of->prev_packet_gp=prev_page_gp; + /*_of->prev_page_offset already points to the right place.*/ + _of->ready_state=OP_STREAMSET; + return op_make_decode_ready(_of); + } + /*No such luck. + Check if we can cut off at least half the range, though.*/ + if(offset-begin<=end-begin>>1||diffos,serialno); + _of->cur_link=_li; + _of->ready_state=OP_STREAMSET; + /*Initialize the interval size history.*/ + d2=d1=d0=end-begin; + force_bisect=0; + while(begin>1; + d1=d2>>1; + d2=end-begin>>1; + if(force_bisect)bisect=begin+(end-begin>>1); + else{ + ogg_int64_t diff2; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start)); + OP_ALWAYS_TRUE(!op_granpos_diff(&diff2,pcm_end,pcm_start)); + /*Take a (pretty decent) guess.*/ + bisect=begin+op_rescale64(diff,diff2,end-begin)-OP_CHUNK_SIZE; + } + if(bisect-OP_CHUNK_SIZEoffset){ + /*Discard any buffered continued packet data.*/ + if(buffering)ogg_stream_reset(&_of->os); + buffering=0; + page_offset=-1; + ret=op_seek_helper(_of,bisect); + if(OP_UNLIKELY(ret<0))return ret; + } + chunk_size=OP_CHUNK_SIZE; + next_boundary=boundary; + /*Now scan forward and figure out where we landed. + In the ideal case, we will see a page with a granule position at or + before our target, followed by a page with a granule position after our + target (or the end of the search interval). + Then we can just drop out and will have all of the data we need with no + additional seeking. + If we landed too far before, or after, we'll break out and do another + bisection.*/ + while(beginos); + buffering=0; + bisect=OP_MAX(bisect-chunk_size,begin); + ret=op_seek_helper(_of,bisect); + if(OP_UNLIKELY(ret<0))return ret; + /*Bump up the chunk size.*/ + chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX); + /*If we did find a page from another stream or without a timestamp, + don't read past it.*/ + boundary=next_boundary; + } + } + else{ + ogg_int64_t gp; + int has_packets; + /*Save the offset of the first page we found after the seek, regardless + of the stream it came from or whether or not it has a timestamp.*/ + next_boundary=OP_MIN(page_offset,next_boundary); + if(serialno!=(ogg_uint32_t)ogg_page_serialno(&og))continue; + has_packets=ogg_page_packets(&og)>0; + /*Force the gp to -1 (as it should be per spec) if no packets end on + this page. + Otherwise we might get confused when we try to pull out a packet + with that timestamp and can't find it.*/ + gp=has_packets?ogg_page_granulepos(&og):-1; + if(gp==-1){ + if(buffering){ + if(OP_LIKELY(!has_packets))ogg_stream_pagein(&_of->os,&og); + else{ + /*If packets did end on this page, but we still didn't have a + valid granule position (in violation of the spec!), stop + buffering continued packet data. + Otherwise we might continue past the packet we actually + wanted.*/ + ogg_stream_reset(&_of->os); + buffering=0; + } + } + continue; + } + if(op_granpos_cmp(gp,_target_gp)<0){ + /*We found a page that ends before our target. + Advance to the raw offset of the next page.*/ + begin=_of->offset; + if(OP_UNLIKELY(op_granpos_cmp(pcm_start,gp)>0) + ||OP_UNLIKELY(op_granpos_cmp(pcm_end,gp)<0)){ + /*Don't let pcm_start get out of range! + That could happen with an invalid timestamp.*/ + break; + } + /*Save the byte offset of the end of the page with this granule + position.*/ + best=best_start=begin; + /*Buffer any data from a continued packet, if necessary. + This avoids the need to seek back here if the next timestamp we + encounter while scanning forward lies after our target.*/ + if(buffering)ogg_stream_reset(&_of->os); + if(op_page_continues(&og)){ + op_buffer_continued_data(_of,&og); + /*If we have a continued packet, remember the offset of this + page's start, so that if we do wind up having to seek back here + later, we can prime the stream with the continued packet data. + With no continued packet, we remember the end of the page.*/ + best_start=page_offset; + } + /*Then force buffering on, so that if a packet starts (but does not + end) on the next page, we still avoid the extra seek back.*/ + buffering=1; + best_gp=pcm_start=gp; + OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start)); + /*If we're more than a second away from our target, break out and + do another bisection.*/ + if(diff>48000)break; + /*Otherwise, keep scanning forward (do NOT use begin+1).*/ + bisect=begin; + } + else{ + /*We found a page that ends after our target.*/ + /*If we scanned the whole interval before we found it, we're done.*/ + if(bisect<=begin+1)end=begin; + else{ + end=bisect; + /*In later iterations, don't read past the first page we found.*/ + boundary=next_boundary; + /*If we're not making much progress shrinking the interval size, + start forcing straight bisection to limit the worst case.*/ + force_bisect=end-begin>d0*2; + /*Don't let pcm_end get out of range! + That could happen with an invalid timestamp.*/ + if(OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0) + &&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<=0)){ + pcm_end=gp; + } + break; + } + } + } + } + } + /*Found our page.*/ + OP_ASSERT(op_granpos_cmp(best_gp,pcm_start)>=0); + /*Seek, if necessary. + If we were buffering data from a continued packet, we should be able to + continue to scan forward to get the rest of the data (even if + page_offset==-1). + Otherwise, we need to seek back to best_start.*/ + if(!buffering){ + if(best_start!=page_offset){ + page_offset=-1; + ret=op_seek_helper(_of,best_start); + if(OP_UNLIKELY(ret<0))return ret; + } + if(best_startend_offset); + if(OP_UNLIKELY(page_offsetprev_packet_gp=best_gp; + _of->prev_page_offset=best_start; + ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,0,1); + if(OP_UNLIKELY(ret<0))return OP_EBADLINK; + /*Verify result.*/ + if(OP_UNLIKELY(op_granpos_cmp(_of->prev_packet_gp,_target_gp)>0)){ + return OP_EBADLINK; + } + /*Our caller will set cur_discard_count to handle pre-roll.*/ + return 0; +} + +int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){ + const OggOpusLink *link; + ogg_int64_t pcm_start; + ogg_int64_t target_gp; + ogg_int64_t prev_packet_gp; + ogg_int64_t skip; + ogg_int64_t diff; + int op_count; + int op_pos; + int ret; + int li; + if(OP_UNLIKELY(_of->ready_stateseekable))return OP_ENOSEEK; + if(OP_UNLIKELY(_pcm_offset<0))return OP_EINVAL; + target_gp=op_get_granulepos(_of,_pcm_offset,&li); + if(OP_UNLIKELY(target_gp==-1))return OP_EINVAL; + link=_of->links+li; + pcm_start=link->pcm_start; + OP_ALWAYS_TRUE(!op_granpos_diff(&_pcm_offset,target_gp,pcm_start)); +#if !defined(OP_SMALL_FOOTPRINT) + /*For small (90 ms or less) forward seeks within the same link, just decode + forward. + This also optimizes the case of seeking to the current position.*/ + if(li==_of->cur_link&&_of->ready_state>=OP_INITSET){ + ogg_int64_t gp; + gp=_of->prev_packet_gp; + if(OP_LIKELY(gp!=-1)){ + ogg_int64_t discard_count; + int nbuffered; + nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0); + OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered)); + /*We do _not_ add cur_discard_count to gp. + Otherwise the total amount to discard could grow without bound, and it + would be better just to do a full seek.*/ + if(OP_LIKELY(!op_granpos_diff(&discard_count,target_gp,gp))){ + /*We use a threshold of 90 ms instead of 80, since 80 ms is the + _minimum_ we would have discarded after a full seek. + Assuming 20 ms frames (the default), we'd discard 90 ms on average.*/ + if(discard_count>=0&&OP_UNLIKELY(discard_count<90*48)){ + _of->cur_discard_count=(opus_int32)discard_count; + return 0; + } + } + } + } +#endif + ret=op_pcm_seek_page(_of,target_gp,li); + if(OP_UNLIKELY(ret<0))return ret; + /*Now skip samples until we actually get to our target.*/ + /*Figure out where we should skip to.*/ + if(_pcm_offset<=link->head.pre_skip)skip=0; + else skip=OP_MAX(_pcm_offset-80*48,0); + OP_ASSERT(_pcm_offset-skip>=0); + OP_ASSERT(_pcm_offset-skipop_count; + prev_packet_gp=_of->prev_packet_gp; + for(op_pos=_of->op_pos;op_posop[op_pos].granulepos; + if(OP_LIKELY(!op_granpos_diff(&diff,cur_packet_gp,pcm_start)) + &&diff>skip){ + break; + } + prev_packet_gp=cur_packet_gp; + } + _of->prev_packet_gp=prev_packet_gp; + _of->op_pos=op_pos; + if(op_posskip + ||_pcm_offset-diff>=OP_INT32_MAX){ + return OP_EBADLINK; + } + /*TODO: If there are further holes/illegal timestamps, we still won't decode + to the correct sample. + However, at least op_pcm_tell() will report the correct value immediately + after returning.*/ + _of->cur_discard_count=(opus_int32)(_pcm_offset-diff); + return 0; +} + +opus_int64 op_raw_tell(const OggOpusFile *_of){ + if(OP_UNLIKELY(_of->ready_stateoffset; +} + +/*Convert a granule position from a given link to a PCM offset relative to the + start of the whole stream. + For unseekable sources, this gets reset to 0 at the beginning of each link.*/ +static ogg_int64_t op_get_pcm_offset(const OggOpusFile *_of, + ogg_int64_t _gp,int _li){ + const OggOpusLink *links; + ogg_int64_t pcm_offset; + links=_of->links; + OP_ASSERT(_li>=0&&_li<_of->nlinks); + pcm_offset=links[_li].pcm_file_offset; + if(_of->seekable&&OP_UNLIKELY(op_granpos_cmp(_gp,links[_li].pcm_end)>0)){ + _gp=links[_li].pcm_end; + } + if(OP_LIKELY(op_granpos_cmp(_gp,links[_li].pcm_start)>0)){ + ogg_int64_t delta; + if(OP_UNLIKELY(op_granpos_diff(&delta,_gp,links[_li].pcm_start)<0)){ + /*This means an unseekable stream claimed to have a page from more than + 2 billion days after we joined.*/ + OP_ASSERT(!_of->seekable); + return OP_INT64_MAX; + } + if(deltaready_stateprev_packet_gp; + if(gp==-1)return 0; + nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0); + OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered)); + li=_of->seekable?_of->cur_link:0; + if(op_granpos_add(&gp,gp,_of->cur_discard_count)<0){ + gp=_of->links[li].pcm_end; + } + return op_get_pcm_offset(_of,gp,li); +} + +void op_set_decode_callback(OggOpusFile *_of, + op_decode_cb_func _decode_cb,void *_ctx){ + _of->decode_cb=_decode_cb; + _of->decode_cb_ctx=_ctx; +} + +int op_set_gain_offset(OggOpusFile *_of, + int _gain_type,opus_int32 _gain_offset_q8){ + if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_ALBUM_GAIN + &&_gain_type!=OP_TRACK_GAIN&&_gain_type!=OP_ABSOLUTE_GAIN){ + return OP_EINVAL; + } + _of->gain_type=_gain_type; + /*The sum of header gain and track gain lies in the range [-65536,65534]. + These bounds allow the offset to set the final value to anywhere in the + range [-32768,32767], which is what we'll clamp it to before applying.*/ + _of->gain_offset_q8=OP_CLAMP(-98302,_gain_offset_q8,98303); + op_update_gain(_of); + return 0; +} + +void op_set_dither_enabled(OggOpusFile *_of,int _enabled){ +#if !defined(OP_FIXED_POINT) + _of->dither_disabled=!_enabled; + if(!_enabled)_of->dither_mute=65; +#else + (void) _of; + (void) _enabled; +#endif +} + +/*Allocate the decoder scratch buffer. + This is done lazily, since if the user provides large enough buffers, we'll + never need it.*/ +static int op_init_buffer(OggOpusFile *_of){ + int nchannels_max; + if(_of->seekable){ + const OggOpusLink *links; + int nlinks; + int li; + links=_of->links; + nlinks=_of->nlinks; + nchannels_max=1; + for(li=0;liod_buffer=(op_sample *)_ogg_malloc( + sizeof(*_of->od_buffer)*nchannels_max*120*48); + if(_of->od_buffer==NULL)return OP_EFAULT; + return 0; +} + +/*Decode a single packet into the target buffer.*/ +static int op_decode(OggOpusFile *_of,op_sample *_pcm, + const ogg_packet *_op,int _nsamples,int _nchannels){ + int ret; + /*First we try using the application-provided decode callback.*/ + if(_of->decode_cb!=NULL){ +#if defined(OP_FIXED_POINT) + ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op, + _nsamples,_nchannels,OP_DEC_FORMAT_SHORT,_of->cur_link); +#else + ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op, + _nsamples,_nchannels,OP_DEC_FORMAT_FLOAT,_of->cur_link); +#endif + } + else ret=OP_DEC_USE_DEFAULT; + /*If the application didn't want to handle decoding, do it ourselves.*/ + if(ret==OP_DEC_USE_DEFAULT){ +#if defined(OP_FIXED_POINT) + ret=opus_multistream_decode(_of->od, + _op->packet,_op->bytes,_pcm,_nsamples,0); +#else + ret=opus_multistream_decode_float(_of->od, + _op->packet,_op->bytes,_pcm,_nsamples,0); +#endif + OP_ASSERT(ret<0||ret==_nsamples); + } + /*If the application returned a positive value other than 0 or + OP_DEC_USE_DEFAULT, fail.*/ + else if(OP_UNLIKELY(ret>0))return OP_EBADPACKET; + if(OP_UNLIKELY(ret<0))return OP_EBADPACKET; + return ret; +} + +/*Read more samples from the stream, using the same API as op_read() or + op_read_float().*/ +static int op_read_native(OggOpusFile *_of, + op_sample *_pcm,int _buf_size,int *_li){ + if(OP_UNLIKELY(_of->ready_stateready_state>=OP_INITSET)){ + int nchannels; + int od_buffer_pos; + int nsamples; + int op_pos; + nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count; + od_buffer_pos=_of->od_buffer_pos; + nsamples=_of->od_buffer_size-od_buffer_pos; + /*If we have buffered samples, return them.*/ + if(nsamples>0){ + if(nsamples*nchannels>_buf_size)nsamples=_buf_size/nchannels; + OP_ASSERT(_pcm!=NULL||nsamples<=0); + /*Check nsamples again so we don't pass NULL to memcpy() if _buf_size + is zero. + That would technically be undefined behavior, even if the number of + bytes to copy were zero.*/ + if(nsamples>0){ + memcpy(_pcm,_of->od_buffer+nchannels*od_buffer_pos, + sizeof(*_pcm)*nchannels*nsamples); + od_buffer_pos+=nsamples; + _of->od_buffer_pos=od_buffer_pos; + } + if(_li!=NULL)*_li=_of->cur_link; + return nsamples; + } + /*If we have buffered packets, decode one.*/ + op_pos=_of->op_pos; + if(OP_LIKELY(op_pos<_of->op_count)){ + const ogg_packet *pop; + ogg_int64_t diff; + opus_int32 cur_discard_count; + int duration; + int trimmed_duration; + pop=_of->op+op_pos++; + _of->op_pos=op_pos; + cur_discard_count=_of->cur_discard_count; + duration=op_get_packet_duration(pop->packet,pop->bytes); + /*We don't buffer packets with an invalid TOC sequence.*/ + OP_ASSERT(duration>0); + trimmed_duration=duration; + /*Perform end-trimming.*/ + if(OP_UNLIKELY(pop->e_o_s)){ + if(OP_UNLIKELY(op_granpos_cmp(pop->granulepos, + _of->prev_packet_gp)<=0)){ + trimmed_duration=0; + } + else if(OP_LIKELY(!op_granpos_diff(&diff, + pop->granulepos,_of->prev_packet_gp))){ + trimmed_duration=(int)OP_MIN(diff,trimmed_duration); + } + } + _of->prev_packet_gp=pop->granulepos; + if(OP_UNLIKELY(duration*nchannels>_buf_size)){ + op_sample *buf; + /*If the user's buffer is too small, decode into a scratch buffer.*/ + buf=_of->od_buffer; + if(OP_UNLIKELY(buf==NULL)){ + ret=op_init_buffer(_of); + if(OP_UNLIKELY(ret<0))return ret; + buf=_of->od_buffer; + } + ret=op_decode(_of,buf,pop,duration,nchannels); + if(OP_UNLIKELY(ret<0))return ret; + /*Perform pre-skip/pre-roll.*/ + od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count); + cur_discard_count-=od_buffer_pos; + _of->cur_discard_count=cur_discard_count; + _of->od_buffer_pos=od_buffer_pos; + _of->od_buffer_size=trimmed_duration; + /*Update bitrate tracking based on the actual samples we used from + what was decoded.*/ + _of->bytes_tracked+=pop->bytes; + _of->samples_tracked+=trimmed_duration-od_buffer_pos; + } + else{ + OP_ASSERT(_pcm!=NULL); + /*Otherwise decode directly into the user's buffer.*/ + ret=op_decode(_of,_pcm,pop,duration,nchannels); + if(OP_UNLIKELY(ret<0))return ret; + if(OP_LIKELY(trimmed_duration>0)){ + /*Perform pre-skip/pre-roll.*/ + od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count); + cur_discard_count-=od_buffer_pos; + _of->cur_discard_count=cur_discard_count; + trimmed_duration-=od_buffer_pos; + if(OP_LIKELY(trimmed_duration>0) + &&OP_UNLIKELY(od_buffer_pos>0)){ + memmove(_pcm,_pcm+od_buffer_pos*nchannels, + sizeof(*_pcm)*trimmed_duration*nchannels); + } + /*Update bitrate tracking based on the actual samples we used from + what was decoded.*/ + _of->bytes_tracked+=pop->bytes; + _of->samples_tracked+=trimmed_duration; + if(OP_LIKELY(trimmed_duration>0)){ + if(_li!=NULL)*_li=_of->cur_link; + return trimmed_duration; + } + } + } + /*Don't grab another page yet. + This one might have more packets, or might have buffered data now.*/ + continue; + } + } + /*Suck in another page.*/ + ret=op_fetch_and_process_page(_of,NULL,-1,1,0); + if(OP_UNLIKELY(ret==OP_EOF)){ + if(_li!=NULL)*_li=_of->cur_link; + return 0; + } + if(OP_UNLIKELY(ret<0))return ret; + } +} + +/*A generic filter to apply to the decoded audio data. + _src is non-const because we will destructively modify the contents of the + source buffer that we consume in some cases.*/ +typedef int (*op_read_filter_func)(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels); + +/*Decode some samples and then apply a custom filter to them. + This is used to convert to different output formats.*/ +static int op_filter_read_native(OggOpusFile *_of,void *_dst,int _dst_sz, + op_read_filter_func _filter,int *_li){ + int ret; + /*Ensure we have some decoded samples in our buffer.*/ + ret=op_read_native(_of,NULL,0,_li); + /*Now apply the filter to them.*/ + if(OP_LIKELY(ret>=0)&&OP_LIKELY(_of->ready_state>=OP_INITSET)){ + int od_buffer_pos; + od_buffer_pos=_of->od_buffer_pos; + ret=_of->od_buffer_size-od_buffer_pos; + if(OP_LIKELY(ret>0)){ + int nchannels; + nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count; + ret=(*_filter)(_of,_dst,_dst_sz, + _of->od_buffer+nchannels*od_buffer_pos,ret,nchannels); + OP_ASSERT(ret>=0); + OP_ASSERT(ret<=_of->od_buffer_size-od_buffer_pos); + od_buffer_pos+=ret; + _of->od_buffer_pos=od_buffer_pos; + } + } + return ret; +} + +#if !defined(OP_FIXED_POINT)||!defined(OP_DISABLE_FLOAT_API) + +/*Matrices for downmixing from the supported channel counts to stereo. + The matrices with 5 or more channels are normalized to a total volume of 2.0, + since most mixes sound too quiet if normalized to 1.0 (as there is generally + little volume in the side/rear channels).*/ +static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={ + /*3.0*/ + { + {0.5858F,0.0F},{0.4142F,0.4142F},{0.0F,0.5858F} + }, + /*quadrophonic*/ + { + {0.4226F,0.0F},{0.0F,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F} + }, + /*5.0*/ + { + {0.651F,0.0F},{0.46F,0.46F},{0.0F,0.651F},{0.5636F,0.3254F}, + {0.3254F,0.5636F} + }, + /*5.1*/ + { + {0.529F,0.0F},{0.3741F,0.3741F},{0.0F,0.529F},{0.4582F,0.2645F}, + {0.2645F,0.4582F},{0.3741F,0.3741F} + }, + /*6.1*/ + { + {0.4553F,0.0F},{0.322F,0.322F},{0.0F,0.4553F},{0.3943F,0.2277F}, + {0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F} + }, + /*7.1*/ + { + {0.3886F,0.0F},{0.2748F,0.2748F},{0.0F,0.3886F},{0.3366F,0.1943F}, + {0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F} + } +}; + +#endif + +#if defined(OP_FIXED_POINT) + +/*Matrices for downmixing from the supported channel counts to stereo. + The matrices with 5 or more channels are normalized to a total volume of 2.0, + since most mixes sound too quiet if normalized to 1.0 (as there is generally + little volume in the side/rear channels). + Hence we keep the coefficients in Q14, so the downmix values won't overflow a + 32-bit number.*/ +static const opus_int16 OP_STEREO_DOWNMIX_Q14 + [OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={ + /*3.0*/ + { + {9598,0},{6786,6786},{0,9598} + }, + /*quadrophonic*/ + { + {6924,0},{0,6924},{5996,3464},{3464,5996} + }, + /*5.0*/ + { + {10666,0},{7537,7537},{0,10666},{9234,5331},{5331,9234} + }, + /*5.1*/ + { + {8668,0},{6129,6129},{0,8668},{7507,4335},{4335,7507},{6129,6129} + }, + /*6.1*/ + { + {7459,0},{5275,5275},{0,7459},{6460,3731},{3731,6460},{4568,4568}, + {5275,5275} + }, + /*7.1*/ + { + {6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183}, + {3183,5515},{4502,4502} + } +}; + +int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){ + return op_read_native(_of,_pcm,_buf_size,_li); +} + +static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + (void)_of; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src)); + else{ + opus_int16 *dst; + int i; + dst=(opus_int16 *)_dst; + if(_nchannels==1){ + for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i]; + } + else{ + for(i=0;i<_nsamples;i++){ + opus_int32 l; + opus_int32 r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + opus_int32 s; + s=_src[_nchannels*i+ci]; + l+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][0]*s; + r+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][1]*s; + } + /*TODO: For 5 or more channels, we should do soft clipping here.*/ + dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767); + dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767); + } + } + } + return _nsamples; +} + +int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){ + return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL); +} + +# if !defined(OP_DISABLE_FLOAT_API) + +static int op_short2float_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + float *dst; + int i; + (void)_of; + dst=(float *)_dst; + if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels; + _dst_sz=_nsamples*_nchannels; + for(i=0;i<_dst_sz;i++)dst[i]=(1.0F/32768)*_src[i]; + return _nsamples; +} + +int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){ + return op_filter_read_native(_of,_pcm,_buf_size,op_short2float_filter,_li); +} + +static int op_short2float_stereo_filter(OggOpusFile *_of, + void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){ + float *dst; + int i; + dst=(float *)_dst; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==1){ + _nsamples=op_short2float_filter(_of,dst,_nsamples,_src,_nsamples,1); + for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i]; + } + else if(_nchannels<5){ + /*For 3 or 4 channels, we can downmix in fixed point without risk of + clipping.*/ + if(_nchannels>2){ + _nsamples=op_stereo_filter(_of,_src,_nsamples*2, + _src,_nsamples,_nchannels); + } + return op_short2float_filter(_of,dst,_dst_sz,_src,_nsamples,2); + } + else{ + /*For 5 or more channels, we convert to floats and then downmix (so that we + don't risk clipping).*/ + for(i=0;i<_nsamples;i++){ + float l; + float r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + float s; + s=(1.0F/32768)*_src[_nchannels*i+ci]; + l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*s; + r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*s; + } + dst[2*i+0]=l; + dst[2*i+1]=r; + } + } + return _nsamples; +} + +int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){ + return op_filter_read_native(_of,_pcm,_buf_size, + op_short2float_stereo_filter,NULL); +} + +# endif + +#else + +# if defined(OP_HAVE_LRINTF) +# include +# define op_float2int(_x) (lrintf(_x)) +# else +# define op_float2int(_x) ((int)((_x)+((_x)<0?-0.5F:0.5F))) +# endif + +/*The dithering code here is adapted from opusdec, part of opus-tools. + It was originally written by Greg Maxwell.*/ + +static opus_uint32 op_rand(opus_uint32 _seed){ + return _seed*96314165+907633515&0xFFFFFFFFU; +} + +/*This implements 16-bit quantization with full triangular dither and IIR noise + shaping. + The noise shaping filters were designed by Sebastian Gesemann, and are based + on the LAME ATH curves with flattening to limit their peak gain to 20 dB. + Everyone else's noise shaping filters are mildly crazy. + The 48 kHz version of this filter is just a warped version of the 44.1 kHz + filter and probably could be improved by shifting the HF shelf up in + frequency a little bit, since 48 kHz has a bit more room and being more + conservative against bat-ears is probably more important than more noise + suppression. + This process can increase the peak level of the signal (in theory by the peak + error of 1.5 +20 dB, though that is unobservably rare). + To avoid clipping, the signal is attenuated by a couple thousandths of a dB. + Initially, the approach taken here was to only attenuate by the 99.9th + percentile, making clipping rare but not impossible (like SoX), but the + limited gain of the filter means that the worst case was only two + thousandths of a dB more, so this just uses the worst case. + The attenuation is probably also helpful to prevent clipping in the DAC + reconstruction filters or downstream resampling, in any case.*/ + +# define OP_GAIN (32753.0F) + +# define OP_PRNG_GAIN (1.0F/(float)0xFFFFFFFF) + +/*48 kHz noise shaping filter, sd=2.34.*/ + +static const float OP_FCOEF_B[4]={ + 2.2374F,-0.7339F,-0.1251F,-0.6033F +}; + +static const float OP_FCOEF_A[4]={ + 0.9030F,0.0116F,-0.5853F,-0.2571F +}; + +static int op_float2short_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + float *_src,int _nsamples,int _nchannels){ + opus_int16 *dst; + int ci; + int i; + dst=(opus_int16 *)_dst; + if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels; +# if defined(OP_SOFT_CLIP) + if(_of->state_channel_count!=_nchannels){ + for(ci=0;ci<_nchannels;ci++)_of->clip_state[ci]=0; + } + opus_pcm_soft_clip(_src,_nsamples,_nchannels,_of->clip_state); +# endif + if(_of->dither_disabled){ + for(i=0;i<_nchannels*_nsamples;i++){ + dst[i]=op_float2int(OP_CLAMP(-32768,32768.0F*_src[i],32767)); + } + } + else{ + opus_uint32 seed; + int mute; + seed=_of->dither_seed; + mute=_of->dither_mute; + if(_of->state_channel_count!=_nchannels)mute=65; + /*In order to avoid replacing digital silence with quiet dither noise, we + mute if the output has been silent for a while.*/ + if(mute>64)memset(_of->dither_a,0,sizeof(*_of->dither_a)*4*_nchannels); + for(i=0;i<_nsamples;i++){ + int silent; + silent=1; + for(ci=0;ci<_nchannels;ci++){ + float r; + float s; + float err; + int si; + int j; + s=_src[_nchannels*i+ci]; + silent&=s==0; + s*=OP_GAIN; + err=0; + for(j=0;j<4;j++){ + err+=OP_FCOEF_B[j]*_of->dither_b[ci*4+j] + -OP_FCOEF_A[j]*_of->dither_a[ci*4+j]; + } + for(j=3;j-->0;)_of->dither_a[ci*4+j+1]=_of->dither_a[ci*4+j]; + for(j=3;j-->0;)_of->dither_b[ci*4+j+1]=_of->dither_b[ci*4+j]; + _of->dither_a[ci*4]=err; + s-=err; + if(mute>16)r=0; + else{ + seed=op_rand(seed); + r=seed*OP_PRNG_GAIN; + seed=op_rand(seed); + r-=seed*OP_PRNG_GAIN; + } + /*Clamp in float out of paranoia that the input will be > 96 dBFS and + wrap if the integer is clamped.*/ + si=op_float2int(OP_CLAMP(-32768,s+r,32767)); + dst[_nchannels*i+ci]=(opus_int16)si; + /*Including clipping in the noise shaping is generally disastrous: the + futile effort to restore the clipped energy results in more clipping. + However, small amounts---at the level which could normally be created + by dither and rounding---are harmless and can even reduce clipping + somewhat due to the clipping sometimes reducing the dither + rounding + error.*/ + _of->dither_b[ci*4]=mute>16?0:OP_CLAMP(-1.5F,si-s,1.5F); + } + mute++; + if(!silent)mute=0; + } + _of->dither_mute=OP_MIN(mute,65); + _of->dither_seed=seed; + } + _of->state_channel_count=_nchannels; + return _nsamples; +} + +int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){ + return op_filter_read_native(_of,_pcm,_buf_size,op_float2short_filter,_li); +} + +int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){ + _of->state_channel_count=0; + return op_read_native(_of,_pcm,_buf_size,_li); +} + +static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, + op_sample *_src,int _nsamples,int _nchannels){ + (void)_of; + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src)); + else{ + float *dst; + int i; + dst=(float *)_dst; + if(_nchannels==1){ + for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i]; + } + else{ + for(i=0;i<_nsamples;i++){ + float l; + float r; + int ci; + l=r=0; + for(ci=0;ci<_nchannels;ci++){ + l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*_src[_nchannels*i+ci]; + r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*_src[_nchannels*i+ci]; + } + dst[2*i+0]=l; + dst[2*i+1]=r; + } + } + } + return _nsamples; +} + +static int op_float2short_stereo_filter(OggOpusFile *_of, + void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){ + opus_int16 *dst; + dst=(opus_int16 *)_dst; + if(_nchannels==1){ + int i; + _nsamples=op_float2short_filter(_of,dst,_dst_sz>>1,_src,_nsamples,1); + for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i]; + } + else{ + if(_nchannels>2){ + _nsamples=OP_MIN(_nsamples,_dst_sz>>1); + _nsamples=op_stereo_filter(_of,_src,_nsamples*2, + _src,_nsamples,_nchannels); + } + _nsamples=op_float2short_filter(_of,dst,_dst_sz,_src,_nsamples,2); + } + return _nsamples; +} + +int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){ + return op_filter_read_native(_of,_pcm,_buf_size, + op_float2short_stereo_filter,NULL); +} + +int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){ + _of->state_channel_count=0; + return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL); +} + +#endif diff --git a/src/opusfile/opusfile.h b/src/opusfile/opusfile.h new file mode 100644 index 00000000..7a645724 --- /dev/null +++ b/src/opusfile/opusfile.h @@ -0,0 +1,2164 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 * + * by the Xiph.Org Foundation and contributors https://xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.h 17182 2010-04-29 03:48:32Z xiphmont $ + + ********************************************************************/ +#if !defined(_opusfile_h) +# define _opusfile_h (1) + +/**\mainpage + \section Introduction + + This is the documentation for the libopusfile C API. + + The libopusfile package provides a convenient high-level API for + decoding and basic manipulation of all Ogg Opus audio streams. + libopusfile is implemented as a layer on top of Xiph.Org's + reference + libogg + and + libopus + libraries. + + libopusfile provides several sets of built-in routines for + file/stream access, and may also use custom stream I/O routines provided by + the embedded environment. + There are built-in I/O routines provided for ANSI-compliant + stdio (FILE *), memory buffers, and URLs + (including URLs, plus optionally and URLs). + + \section Organization + + The main API is divided into several sections: + - \ref stream_open_close + - \ref stream_info + - \ref stream_decoding + - \ref stream_seeking + + Several additional sections are not tied to the main API. + - \ref stream_callbacks + - \ref header_info + - \ref error_codes + + \section Overview + + The libopusfile API always decodes files to 48 kHz. + The original sample rate is not preserved by the lossy compression, though + it is stored in the header to allow you to resample to it after decoding + (the libopusfile API does not currently provide a resampler, + but the + the + Speex resampler is a good choice if you need one). + In general, if you are playing back the audio, you should leave it at + 48 kHz, provided your audio hardware supports it. + When decoding to a file, it may be worth resampling back to the original + sample rate, so as not to surprise users who might not expect the sample + rate to change after encoding to Opus and decoding. + + 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 + Vorbis + mappings. + A special stereo API can convert everything to 2 channels, making it simple + to support multichannel files in an application which only has stereo + output. + Although the libopusfile ABI provides support for the theoretical + maximum number of channels, the current implementation does not support + files with more than 8 channels, as they do not have well-defined channel + mappings. + + Like all Ogg files, Opus files may be "chained". + That is, multiple Opus files may be combined into a single, longer file just + by concatenating the original files. + This is commonly done in internet radio streaming, as it allows the title + and artist to be updated each time the song changes, since each link in the + chain includes its own set of metadata. + + libopusfile fully supports chained files. + It will decode the first Opus stream found in each link of a chained file + (ignoring any other streams that might be concurrently multiplexed with it, + such as a video stream). + + The channel count can also change between links. + If your application is not prepared to deal with this, it can use the stereo + API to ensure the audio from all links will always get decoded into a + common format. + Since libopusfile always decodes to 48 kHz, you do not have to + worry about the sample rate changing between links (as was possible with + Vorbis). + This makes application support for chained files with libopusfile + very easy.*/ + +# if defined(__cplusplus) +extern "C" { +# endif + +# include +# include +# include "../libogg/ogg/ogg.h" +# include "../libopus/opus_multistream.h" + +/**@cond PRIVATE*/ + +/*Enable special features for gcc and gcc-compatible compilers.*/ +# if !defined(OP_GNUC_PREREQ) +# if defined(__GNUC__)&&defined(__GNUC_MINOR__) +# define OP_GNUC_PREREQ(_maj,_min) \ + ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min)) +# else +# define OP_GNUC_PREREQ(_maj,_min) 0 +# endif +# endif + +# if OP_GNUC_PREREQ(4,0) +# pragma GCC visibility push(default) +# endif + +typedef struct OpusHead OpusHead; +typedef struct OpusTags OpusTags; +typedef struct OpusPictureTag OpusPictureTag; +typedef struct OpusServerInfo OpusServerInfo; +typedef struct OpusFileCallbacks OpusFileCallbacks; +typedef struct OggOpusFile OggOpusFile; + +/*Warning attributes for libopusfile functions.*/ +# if OP_GNUC_PREREQ(3,4) +# define OP_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__)) +# else +# define OP_WARN_UNUSED_RESULT +# endif +# if OP_GNUC_PREREQ(3,4) +# define OP_ARG_NONNULL(_x) __attribute__((__nonnull__(_x))) +# else +# define OP_ARG_NONNULL(_x) +# endif + +/**@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.*/ +#define OP_EOF (-2) +/**There was a hole in the page sequence numbers (e.g., a page was corrupt or + missing).*/ +#define OP_HOLE (-3) +/**An underlying read, seek, or tell operation failed when it should have + succeeded.*/ +#define OP_EREAD (-128) +/**A NULL pointer was passed where one was unexpected, or an + internal memory allocation failed, or an internal library error was + encountered.*/ +#define OP_EFAULT (-129) +/**The stream used a feature that is not implemented, such as an unsupported + channel family.*/ +#define OP_EIMPL (-130) +/**One or more parameters to a function were invalid.*/ +#define OP_EINVAL (-131) +/**A purported Ogg Opus stream did not begin with an Ogg page, a purported + header packet did not start with one of the required strings, "OpusHead" or + "OpusTags", or a link in a chained file was encountered that did not + contain any logical Opus streams.*/ +#define OP_ENOTFORMAT (-132) +/**A required header packet was not properly formatted, contained illegal + values, or was missing altogether.*/ +#define OP_EBADHEADER (-133) +/**The ID header contained an unrecognized version number.*/ +#define OP_EVERSION (-134) +/*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 + the individual Opus packets contained in it are not all the same.*/ +#define OP_EBADPACKET (-136) +/**We failed to find data we had seen before, or the bitstream structure was + sufficiently malformed that seeking to the target destination was + impossible.*/ +#define OP_EBADLINK (-137) +/**An operation that requires seeking was requested on an unseekable stream.*/ +#define OP_ENOSEEK (-138) +/**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) + +/**Ogg Opus bitstream information. + This contains the basic playback parameters for a stream, and corresponds to + the initial ID header packet of an Ogg Opus stream.*/ +struct OpusHead{ + /**The Ogg Opus format version, in the range 0...255. + The top 4 bits represent a "major" version, and the bottom four bits + represent backwards-compatible "minor" revisions. + The current specification describes version 1. + This library will recognize versions up through 15 as backwards compatible + with the current specification. + An earlier draft of the specification described a version 0, but the only + difference between version 1 and version 0 is that version 0 did + not specify the semantics for handling the version field.*/ + int version; + /**The number of channels, in the range 1...255.*/ + int channel_count; + /**The number of samples that should be discarded from the beginning of the + stream.*/ + unsigned pre_skip; + /**The sampling rate of the original input. + All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz + for playback (unless the target hardware does not support this sampling + rate). + However, this field may be used to resample the audio back to the original + sampling rate, for example, when saving the output to a file.*/ + opus_uint32 input_sample_rate; + /**The gain to apply to the decoded output, in dB, as a Q8 value in the range + -32768...32767. + The libopusfile API will automatically apply this gain to the + decoded output before returning it, scaling it by + pow(10,output_gain/(20.0*256)). + You can adjust this behavior with op_set_gain_offset().*/ + int output_gain; + /**The channel mapping family, in the range 0...255. + Channel mapping family 0 covers mono or stereo in a single stream. + Channel mapping family 1 covers 1 to 8 channels in one or more streams, + using the Vorbis speaker assignments. + Channel mapping family 255 covers 1 to 255 channels in one or more + streams, but without any defined speaker assignment.*/ + int mapping_family; + /**The number of Opus streams in each Ogg packet, in the range 1...255.*/ + int stream_count; + /**The number of coupled Opus streams in each Ogg packet, in the range + 0...127. + This must satisfy 0 <= coupled_count <= stream_count and + coupled_count + stream_count <= 255. + The coupled streams appear first, before all uncoupled streams, in an Ogg + Opus packet.*/ + int coupled_count; + /**The mapping from coded stream channels to output channels. + Let index=mapping[k] be the value for channel k. + If index<2*coupled_count, then it refers to the left channel + from stream (index/2) if even, and the right channel from + stream (index/2) if odd. + Otherwise, it refers to the output of the uncoupled stream + (index-coupled_count).*/ + unsigned char mapping[OPUS_CHANNEL_COUNT_MAX]; +}; + +/**The metadata from an Ogg Opus stream. + + This structure holds the in-stream metadata corresponding to the 'comment' + header packet of an Ogg Opus stream. + The comment header is meant to be used much like someone jotting a quick + note on the label of a CD. + It should be a short, to the point text note that can be more than a couple + words, but not more than a short paragraph. + + The metadata is stored as a series of (tag, value) pairs, in length-encoded + string vectors, using the same format as Vorbis (without the final "framing + bit"), Theora, and Speex, except for the packet header. + The first occurrence of the '=' character delimits the tag and value. + 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 the Vorbis + comment header specification for details. + + In filling in this structure, libopusfile will null-terminate the + #user_comments strings for safety. + However, the bitstream format itself treats them as 8-bit clean vectors, + possibly containing NUL characters, so the #comment_lengths array should be + treated as their authoritative length. + + This structure is binary and source-compatible with a + vorbis_comment, and pointers to it may be freely cast to + vorbis_comment pointers, and vice versa. + It is provided as a separate type to avoid introducing a compile-time + dependency on the libvorbis headers.*/ +struct OpusTags{ + /**The array of comment string vectors.*/ + char **user_comments; + /**An array of the corresponding length of each vector, in bytes.*/ + int *comment_lengths; + /**The total number of comment streams.*/ + int comments; + /**The null-terminated vendor string. + This identifies the software used to encode the stream.*/ + char *vendor; +}; + +/**\name Picture tag image formats*/ +/*@{*/ + +/**The MIME type was not recognized, or the image data did not match the + declared MIME type.*/ +#define OP_PIC_FORMAT_UNKNOWN (-1) +/**The MIME type indicates the image data is really a URL.*/ +#define OP_PIC_FORMAT_URL (0) +/**The image is a JPEG.*/ +#define OP_PIC_FORMAT_JPEG (1) +/**The image is a PNG.*/ +#define OP_PIC_FORMAT_PNG (2) +/**The image is a GIF.*/ +#define OP_PIC_FORMAT_GIF (3) + +/*@}*/ + +/**The contents of a METADATA_BLOCK_PICTURE tag.*/ +struct OpusPictureTag{ + /**The picture type according to the ID3v2 APIC frame: +

      +
    1. Other
    2. +
    3. 32x32 pixels 'file icon' (PNG only)
    4. +
    5. Other file icon
    6. +
    7. Cover (front)
    8. +
    9. Cover (back)
    10. +
    11. Leaflet page
    12. +
    13. Media (e.g. label side of CD)
    14. +
    15. Lead artist/lead performer/soloist
    16. +
    17. Artist/performer
    18. +
    19. Conductor
    20. +
    21. Band/Orchestra
    22. +
    23. Composer
    24. +
    25. Lyricist/text writer
    26. +
    27. Recording Location
    28. +
    29. During recording
    30. +
    31. During performance
    32. +
    33. Movie/video screen capture
    34. +
    35. A bright colored fish
    36. +
    37. Illustration
    38. +
    39. Band/artist logotype
    40. +
    41. Publisher/Studio logotype
    42. +
    + Others are reserved and should not be used. + There may only be one each of picture type 1 and 2 in a file.*/ + opus_int32 type; + /**The MIME type of the picture, in printable ASCII characters 0x20-0x7E. + The MIME type may also be "-->" to signify that the data part + is a URL pointing to the picture instead of the picture data itself. + In this case, a terminating NUL is appended to the URL string in #data, + but #data_length is set to the length of the string excluding that + terminating NUL.*/ + char *mime_type; + /**The description of the picture, in UTF-8.*/ + char *description; + /**The width of the picture in pixels.*/ + opus_uint32 width; + /**The height of the picture in pixels.*/ + opus_uint32 height; + /**The color depth of the picture in bits-per-pixel (not + bits-per-channel).*/ + opus_uint32 depth; + /**For indexed-color pictures (e.g., GIF), the number of colors used, or 0 + for non-indexed pictures.*/ + opus_uint32 colors; + /**The length of the picture data in bytes.*/ + opus_uint32 data_length; + /**The binary picture data.*/ + unsigned char *data; + /**The format of the picture data, if known. + One of +
      +
    • #OP_PIC_FORMAT_UNKNOWN,
    • +
    • #OP_PIC_FORMAT_URL,
    • +
    • #OP_PIC_FORMAT_JPEG,
    • +
    • #OP_PIC_FORMAT_PNG, or
    • +
    • #OP_PIC_FORMAT_GIF.
    • +
    */ + int format; +}; + +/**\name Functions for manipulating header data + + These functions manipulate the #OpusHead and #OpusTags structures, + which describe the audio parameters and tag-value metadata, respectively. + These can be used to query the headers returned by libopusfile, 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. + The contents of this structure are untouched on error. + This may be NULL to merely test the header + for validity. + \param[in] _data The contents of the ID header packet. + \param _len The number of bytes of data in the ID header packet. + \return 0 on success or a negative value on error. + \retval #OP_ENOTFORMAT If the data does not start with the "OpusHead" + string. + \retval #OP_EVERSION If the version field signaled a version this library + does not know how to parse. + \retval #OP_EIMPL If the channel mapping family was 255, which general + purpose players should not attempt to play. + \retval #OP_EBADHEADER If the contents of the packet otherwise violate the + Ogg Opus specification: +
      +
    • Insufficient data,
    • +
    • Too much data for the known minor versions,
    • +
    • An unrecognized channel mapping family,
    • +
    • Zero channels or too many channels,
    • +
    • Zero coded streams,
    • +
    • Too many coupled streams, or
    • +
    • An invalid channel mapping index.
    • +
    */ +OP_WARN_UNUSED_RESULT int opus_head_parse(OpusHead *_head, + const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2); + +/**Converts a granule position to a sample offset for a given Ogg Opus stream. + The sample offset is simply _gp-_head->pre_skip. + Granule position values smaller than OpusHead#pre_skip correspond to audio + that should never be played, and thus have no associated sample offset. + This function returns -1 for such values. + This function also correctly handles extremely large granule positions, + which may have wrapped around to a negative number when stored in a signed + ogg_int64_t value. + \param _head The #OpusHead information from the ID header of the stream. + \param _gp The granule position to convert. + \return The sample offset associated with the given granule position + (counting at a 48 kHz sampling rate), or the special value -1 on + error (i.e., the granule position was smaller than the pre-skip + amount).*/ +ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp) + OP_ARG_NONNULL(1); + +/**Parses the contents of the 'comment' header packet of an Ogg Opus stream. + \param[out] _tags An uninitialized #OpusTags structure. + This returns the contents of the parsed packet. + The contents of this structure are untouched on error. + This may be NULL to merely test the header + for validity. + \param[in] _data The contents of the 'comment' header packet. + \param _len The number of bytes of data in the 'info' header packet. + \retval 0 Success. + \retval #OP_ENOTFORMAT If the data does not start with the "OpusTags" + string. + \retval #OP_EBADHEADER If the contents of the packet otherwise violate the + Ogg Opus specification. + \retval #OP_EFAULT If there wasn't enough memory to store the tags.*/ +OP_WARN_UNUSED_RESULT int opus_tags_parse(OpusTags *_tags, + const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2); + +/**Performs a deep copy of an #OpusTags structure. + \param _dst The #OpusTags structure to copy into. + If this function fails, the contents of this structure remain + untouched. + \param _src The #OpusTags structure to copy from. + \retval 0 Success. + \retval #OP_EFAULT If there wasn't enough memory to copy the tags.*/ +int opus_tags_copy(OpusTags *_dst,const OpusTags *_src) OP_ARG_NONNULL(1); + +/**Initializes an #OpusTags structure. + This should be called on a freshly allocated #OpusTags structure before + attempting to use it. + \param _tags The #OpusTags structure to initialize.*/ +void opus_tags_init(OpusTags *_tags) OP_ARG_NONNULL(1); + +/**Add a (tag, value) pair to an initialized #OpusTags structure. + \note Neither opus_tags_add() nor opus_tags_add_comment() support values + containing embedded NULs, although the bitstream format does support them. + To add such tags, you will need to manipulate the #OpusTags structure + directly. + \param _tags The #OpusTags structure to add the (tag, value) pair to. + \param _tag A NUL-terminated, case-insensitive, ASCII string containing + the tag to add (without an '=' character). + \param _value A NUL-terminated UTF-8 containing the corresponding value. + \return 0 on success, or a negative value on failure. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) OP_ARG_NONNULL(3); + +/**Add a comment to an initialized #OpusTags structure. + \note Neither opus_tags_add_comment() nor opus_tags_add() support comments + containing embedded NULs, although the bitstream format does support them. + To add such tags, you will need to manipulate the #OpusTags structure + directly. + \param _tags The #OpusTags structure to add the comment to. + \param _comment A NUL-terminated UTF-8 string containing the comment in + "TAG=value" form. + \return 0 on success, or a negative value on failure. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_add_comment(OpusTags *_tags,const char *_comment) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Replace the binary suffix data at the end of the packet (if any). + \param _tags An initialized #OpusTags structure. + \param _data A buffer of binary data to append after the encoded user + comments. + The least significant bit of the first byte of this data must + be set (to ensure the data is preserved by other editors). + \param _len The number of bytes of binary data to append. + This may be zero to remove any existing binary suffix data. + \return 0 on success, or a negative value on error. + \retval #OP_EINVAL \a _len was negative, or \a _len was positive but + \a _data was NULL or the least significant + bit of the first byte was not set. + \retval #OP_EFAULT An internal memory allocation failed.*/ +int opus_tags_set_binary_suffix(OpusTags *_tags, + const unsigned char *_data,int _len) OP_ARG_NONNULL(1); + +/**Look up a comment value by its tag. + \param _tags An initialized #OpusTags structure. + \param _tag The tag to look up. + \param _count The instance of the tag. + The same tag can appear multiple times, each with a distinct + value, so an index is required to retrieve them all. + The order in which these values appear is significant and + should be preserved. + Use opus_tags_query_count() to get the legal range for the + \a _count parameter. + \return A pointer to the queried tag's value. + This points directly to data in the #OpusTags structure. + It should not be modified or freed by the application, and + modifications to the structure may invalidate the pointer. + \retval NULL If no matching tag is found.*/ +const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Look up the number of instances of a tag. + Call this first when querying for a specific tag and then iterate over the + number of instances with separate calls to opus_tags_query() to retrieve + all the values for that tag in order. + \param _tags An initialized #OpusTags structure. + \param _tag The tag to look up. + \return The number of instances of this particular tag.*/ +int opus_tags_query_count(const OpusTags *_tags,const char *_tag) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Retrieve the binary suffix data at the end of the packet (if any). + \param _tags An initialized #OpusTags structure. + \param[out] _len Returns the number of bytes of binary suffix data returned. + \return A pointer to the binary suffix data, or NULL if none + was present.*/ +const unsigned char *opus_tags_get_binary_suffix(const OpusTags *_tags, + int *_len) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Get the album gain from an R128_ALBUM_GAIN tag, if one was specified. + This searches for the first R128_ALBUM_GAIN tag with a valid signed, + 16-bit decimal integer value and returns the value. + This routine is exposed merely for convenience for applications which wish + to do something special with the album gain (i.e., display it). + If you simply wish to apply the album gain instead of the header gain, you + can use op_set_gain_offset() with an #OP_ALBUM_GAIN type and no offset. + \param _tags An initialized #OpusTags structure. + \param[out] _gain_q8 The album gain, in 1/256ths of a dB. + This will lie in the range [-32768,32767], and should + be applied in addition to the header gain. + On error, no value is returned, and the previous + contents remain unchanged. + \return 0 on success, or a negative value on error. + \retval #OP_FALSE There was no album gain available in the given tags.*/ +int opus_tags_get_album_gain(const OpusTags *_tags,int *_gain_q8) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Get the track gain from an R128_TRACK_GAIN tag, if one was specified. + This searches for the first R128_TRACK_GAIN tag with a valid signed, + 16-bit decimal integer value and returns the value. + This routine is exposed merely for convenience for applications which wish + to do something special with the track gain (i.e., display it). + If you simply wish to apply the track gain instead of the header gain, you + can use op_set_gain_offset() with an #OP_TRACK_GAIN type and no offset. + \param _tags An initialized #OpusTags structure. + \param[out] _gain_q8 The track gain, in 1/256ths of a dB. + This will lie in the range [-32768,32767], and should + be applied in addition to the header gain. + On error, no value is returned, and the previous + contents remain unchanged. + \return 0 on success, or a negative value on error. + \retval #OP_FALSE There was no track gain available in the given tags.*/ +int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8) + OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Clears the #OpusTags structure. + This should be called on an #OpusTags structure after it is no longer + needed. + It will free all memory used by the structure members. + \param _tags The #OpusTags structure to clear.*/ +void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1); + +/**Check if \a _comment is an instance of a \a _tag_name tag. + \see opus_tagncompare + \param _tag_name A NUL-terminated, case-insensitive, ASCII string containing + the name of the tag to check for (without the terminating + '=' character). + \param _comment The comment string to check. + \return An integer less than, equal to, or greater than zero if \a _comment + is found respectively, to be less than, to match, or be greater + than a "tag=value" string whose tag matches \a _tag_name.*/ +int opus_tagcompare(const char *_tag_name,const char *_comment); + +/**Check if \a _comment is an instance of a \a _tag_name tag. + This version is slightly more efficient than opus_tagcompare() if the length + of the tag name is already known (e.g., because it is a constant). + \see opus_tagcompare + \param _tag_name A case-insensitive ASCII string containing the name of the + tag to check for (without the terminating '=' character). + \param _tag_len The number of characters in the tag name. + This must be non-negative. + \param _comment The comment string to check. + \return An integer less than, equal to, or greater than zero if \a _comment + is found respectively, to be less than, to match, or be greater + than a "tag=value" string whose tag matches the first \a _tag_len + characters of \a _tag_name.*/ +int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment); + +/**Parse a single METADATA_BLOCK_PICTURE tag. + This decodes the BASE64-encoded content of the tag and returns a structure + with the MIME type, description, image parameters (if known), and the + compressed image data. + If the MIME type indicates the presence of an image format we recognize + (JPEG, PNG, or GIF) and the actual image data contains the magic signature + associated with that format, then the OpusPictureTag::format field will be + set to the corresponding format. + This is provided as a convenience to avoid requiring applications to parse + the MIME type and/or do their own format detection for the commonly used + formats. + In this case, we also attempt to extract the image parameters directly from + the image data (overriding any that were present in the tag, which the + specification says applications are not meant to rely on). + The application must still provide its own support for actually decoding the + image data and, if applicable, retrieving that data from URLs. + \param[out] _pic Returns the parsed picture data. + No sanitation is done on the type, MIME type, or + description fields, so these might return invalid values. + The contents of this structure are left unmodified on + failure. + \param _tag The METADATA_BLOCK_PICTURE tag contents. + The leading "METADATA_BLOCK_PICTURE=" portion is optional, + to allow the function to be used on either directly on the + values in OpusTags::user_comments or on the return value + of opus_tags_query(). + \return 0 on success or a negative value on error. + \retval #OP_ENOTFORMAT The METADATA_BLOCK_PICTURE contents were not valid. + \retval #OP_EFAULT There was not enough memory to store the picture tag + contents.*/ +OP_WARN_UNUSED_RESULT int opus_picture_tag_parse(OpusPictureTag *_pic, + const char *_tag) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Initializes an #OpusPictureTag structure. + This should be called on a freshly allocated #OpusPictureTag structure + before attempting to use it. + \param _pic The #OpusPictureTag structure to initialize.*/ +void opus_picture_tag_init(OpusPictureTag *_pic) OP_ARG_NONNULL(1); + +/**Clears the #OpusPictureTag structure. + This should be called on an #OpusPictureTag structure after it is no longer + needed. + It will free all memory used by the structure members. + \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 + certificate checks, etc. + Options are processed in order, and if the same option is passed multiple + times, only the value specified by the last occurrence has an effect + (unless otherwise specified). + They may be expanded in the future.*/ +/*@{*/ + +/**@cond PRIVATE*/ + +/*These are the raw numbers used to define the request codes. + They should not be used directly.*/ +#define OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST (6464) +#define OP_HTTP_PROXY_HOST_REQUEST (6528) +#define OP_HTTP_PROXY_PORT_REQUEST (6592) +#define OP_HTTP_PROXY_USER_REQUEST (6656) +#define OP_HTTP_PROXY_PASS_REQUEST (6720) +#define OP_GET_SERVER_INFO_REQUEST (6784) + +#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.*/ +#define OP_CHECK_INT(_x) ((void)((_x)==(opus_int32)0),(opus_int32)(_x)) +#define OP_CHECK_CONST_CHAR_PTR(_x) ((_x)+((_x)-(const char *)(_x))) +#define OP_CHECK_SERVER_INFO_PTR(_x) ((_x)+((_x)-(OpusServerInfo *)(_x))) + +/**@endcond*/ + +/**HTTP/Shoutcast/Icecast server information associated with a URL.*/ +struct OpusServerInfo{ + /**The name of the server (icy-name/ice-name). + This is NULL if there was no icy-name or + ice-name header.*/ + char *name; + /**A short description of the server (icy-description/ice-description). + This is NULL if there was no icy-description or + ice-description header.*/ + char *description; + /**The genre the server falls under (icy-genre/ice-genre). + This is NULL if there was no icy-genre or + ice-genre header.*/ + char *genre; + /**The homepage for the server (icy-url/ice-url). + This is NULL if there was no icy-url or + ice-url header.*/ + char *url; + /**The software used by the origin server (Server). + This is NULL if there was no Server header.*/ + char *server; + /**The media type of the entity sent to the recepient (Content-Type). + This is NULL if there was no Content-Type + header.*/ + char *content_type; + /**The nominal stream bitrate in kbps (icy-br/ice-bitrate). + This is -1 if there was no icy-br or + ice-bitrate header.*/ + opus_int32 bitrate_kbps; + /**Flag indicating whether the server is public (1) or not + (0) (icy-pub/ice-public). + This is -1 if there was no icy-pub or + ice-public header.*/ + int is_public; + /**Flag indicating whether the server is using HTTPS instead of HTTP. + This is 0 unless HTTPS is being used. + This may not match the protocol used in the original URL if there were + redirections.*/ + int is_ssl; +}; + +/**Initializes an #OpusServerInfo structure. + All fields are set as if the corresponding header was not available. + \param _info The #OpusServerInfo structure to initialize. + \note If you use this function, you must link against libopusurl.*/ +void opus_server_info_init(OpusServerInfo *_info) OP_ARG_NONNULL(1); + +/**Clears the #OpusServerInfo structure. + This should be called on an #OpusServerInfo structure after it is no longer + needed. + It will free all memory used by the structure members. + \param _info The #OpusServerInfo structure to clear. + \note If you use this function, you must link against libopusurl.*/ +void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1); + +/**Skip the certificate check when connecting via TLS/SSL (https). + \param _b opus_int32: Whether or not to skip the certificate + check. + The check will be skipped if \a _b is non-zero, and will not be + skipped if \a _b is zero. + \hideinitializer*/ +#define OP_SSL_SKIP_CERTIFICATE_CHECK(_b) \ + OP_URL_OPT(OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST),OP_CHECK_INT(_b) + +/**Proxy connections through the given host. + If no port is specified via #OP_HTTP_PROXY_PORT, the port number defaults + to 8080 (http-alt). + All proxy parameters are ignored for non-http and non-https URLs. + \param _host const char *: The proxy server hostname. + This may be NULL to disable the use of a proxy + server. + \hideinitializer*/ +#define OP_HTTP_PROXY_HOST(_host) \ + OP_URL_OPT(OP_HTTP_PROXY_HOST_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host) + +/**Use the given port when proxying connections. + This option only has an effect if #OP_HTTP_PROXY_HOST is specified with a + non-NULL \a _host. + If this option is not provided, the proxy port number defaults to 8080 + (http-alt). + All proxy parameters are ignored for non-http and non-https URLs. + \param _port opus_int32: The proxy server port. + This must be in the range 0...65535 (inclusive), or the + URL function this is passed to will fail. + \hideinitializer*/ +#define OP_HTTP_PROXY_PORT(_port) \ + OP_URL_OPT(OP_HTTP_PROXY_PORT_REQUEST),OP_CHECK_INT(_port) + +/**Use the given user name for authentication when proxying connections. + All proxy parameters are ignored for non-http and non-https URLs. + \param _user const char *: The proxy server user name. + This may be NULL to disable proxy + authentication. + A non-NULL value only has an effect + if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_PASS + are also specified with non-NULL + arguments. + \hideinitializer*/ +#define OP_HTTP_PROXY_USER(_user) \ + OP_URL_OPT(OP_HTTP_PROXY_USER_REQUEST),OP_CHECK_CONST_CHAR_PTR(_user) + +/**Use the given password for authentication when proxying connections. + All proxy parameters are ignored for non-http and non-https URLs. + \param _pass const char *: The proxy server password. + This may be NULL to disable proxy + authentication. + A non-NULL value only has an effect + if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_USER + are also specified with non-NULL + arguments. + \hideinitializer*/ +#define OP_HTTP_PROXY_PASS(_pass) \ + OP_URL_OPT(OP_HTTP_PROXY_PASS_REQUEST),OP_CHECK_CONST_CHAR_PTR(_pass) + +/**Parse information about the streaming server (if any) and return it. + Very little validation is done. + In particular, OpusServerInfo::url may not be a valid URL, + OpusServerInfo::bitrate_kbps may not really be in kbps, and + OpusServerInfo::content_type may not be a valid MIME type. + The character set of the string fields is not specified anywhere, and should + not be assumed to be valid UTF-8. + \param _info OpusServerInfo *: Returns information about the server. + If there is any error opening the stream, the + contents of this structure remain + unmodified. + On success, fills in the structure with the + server information that was available, if + any. + After a successful return, the contents of + this structure should be freed by calling + opus_server_info_clear(). + \hideinitializer*/ +#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. + A stream does not need to implement seeking, but the decoder will not be + able to seek if it does not do so. + These functions also include some convenience routines for working with + standard FILE 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. + \param[out] _ptr The buffer to store the data in. + \param _nbytes The maximum number of bytes to read. + This function may return fewer, though it will not + return zero unless it reaches end-of-file. + \return The number of bytes successfully read, or a negative value on + error.*/ +typedef int (*op_read_func)(void *_stream,unsigned char *_ptr,int _nbytes); + +/**Sets the position indicator for \a _stream. + The new position, measured in bytes, is obtained by adding \a _offset + bytes to the position specified by \a _whence. + If \a _whence is set to SEEK_SET, SEEK_CUR, or + SEEK_END, the offset is relative to the start of the stream, + the current position indicator, or end-of-file, respectively. + \retval 0 Success. + \retval -1 Seeking is not supported or an error occurred. + errno need not be set.*/ +typedef int (*op_seek_func)(void *_stream,opus_int64 _offset,int _whence); + +/**Obtains the current value of the position indicator for \a _stream. + \return The current position indicator.*/ +typedef opus_int64 (*op_tell_func)(void *_stream); + +/**Closes the underlying stream. + \retval 0 Success. + \retval EOF An error occurred. + errno need not be set.*/ +typedef int (*op_close_func)(void *_stream); + +/**The callbacks used to access non-FILE stream resources. + The function prototypes are basically the same as for the stdio functions + fread(), fseek(), ftell(), and + fclose(). + The differences are that the FILE * arguments have been + replaced with a void *, which is to be used as a pointer to + whatever internal data these functions might need, that #seek and #tell + take and return 64-bit offsets, and that #seek must return -1 if + the stream is unseekable.*/ +struct OpusFileCallbacks{ + /**Used to read data from the stream. + This must not be NULL.*/ + op_read_func read; + /**Used to seek in the stream. + This may be NULL if seeking is not implemented.*/ + op_seek_func seek; + /**Used to return the current read position in the stream. + This may be NULL if seeking is not implemented.*/ + op_tell_func tell; + /**Used to close the stream when the decoder is freed. + This may be NULL to leave the stream open.*/ + op_close_func close; +}; + +/**Opens a stream with fopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _path The path to the file to open. + On Windows, this string must be UTF-8 (to allow access to + files whose names cannot be represented in the current + MBCS code page). + All other systems use the native character encoding. + \param _mode The mode to open the file in. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_fopen(OpusFileCallbacks *_cb, + const char *_path,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) + OP_ARG_NONNULL(3); + +/**Opens a stream with fdopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _fd The file descriptor to open. + \param _mode The mode to open the file in. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_fdopen(OpusFileCallbacks *_cb, + int _fd,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(3); + +/**Opens a stream with freopen() and fills in a set of callbacks + that can be used to access it. + This is useful to avoid writing your own portable 64-bit seeking wrappers, + and also avoids cross-module linking issues on Windows, where a + FILE * must be accessed by routines defined in the same module + that opened it. + \param[out] _cb The callbacks to use for this file. + If there is an error opening the file, nothing will be + filled in here. + \param _path The path to the file to open. + On Windows, this string must be UTF-8 (to allow access + to files whose names cannot be represented in the + current MBCS code page). + All other systems use the native character encoding. + \param _mode The mode to open the file in. + \param _stream A stream previously returned by op_fopen(), op_fdopen(), + or op_freopen(). + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_freopen(OpusFileCallbacks *_cb, + const char *_path,const char *_mode,void *_stream) OP_ARG_NONNULL(1) + OP_ARG_NONNULL(2) OP_ARG_NONNULL(3) OP_ARG_NONNULL(4); + +/**Creates a stream that reads from the given block of memory. + This block of memory must contain the complete stream to decode. + This is useful for caching small streams (e.g., sound effects) in RAM. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will be + filled in here. + \param _data The block of memory to read from. + \param _size The size of the block of memory. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb, + const unsigned char *_data,size_t _size) OP_ARG_NONNULL(1); + +/**Creates a stream that reads from the given URL. + This function behaves identically to op_url_stream_create(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \note If you use this function, you must link against libopusurl. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will + be filled in here. + \param _url The URL to read from. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, + before passing them to this function. + \param[in,out] _ap A list of the \ref url_options "optional flags" to use. + This is a variable-length list of options terminated + with NULL. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb, + const char *_url,va_list _ap) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2); + +/**Creates a stream that reads from the given URL. + \note If you use this function, you must link against libopusurl. + \param[out] _cb The callbacks to use for this stream. + If there is an error creating the stream, nothing will be + filled in here. + \param _url The URL to read from. + Currently only the , , and schemes + are supported. + Both and may be disabled at compile time, + in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, before + passing them to this function. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated with + NULL. + \return A stream handle to use with the callbacks, or NULL on + error.*/ +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 + stream). + Something like 512 bytes will give more reliable results for multiplexed + streams. + This function is meant to be a quick-rejection filter. + Its purpose is not to guarantee that a stream is a valid Opus stream, but to + ensure that it looks enough like Opus that it isn't going to be recognized + as some other format (except possibly an Opus stream that is also + multiplexed with other codecs, such as video). + \param[out] _head The parsed ID header contents. + You may pass NULL if you do not need + this information. + If the function fails, the contents of this structure + remain untouched. + \param _initial_data An initial buffer of data from the start of the + stream. + \param _initial_bytes The number of bytes in \a _initial_data. + \return 0 if the data appears to be Opus, or a negative value on error. + \retval #OP_FALSE There was not enough data to tell if this was an Opus + stream or not. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL The stream used a feature that is not implemented, + such as an unsupported channel family. + \retval #OP_ENOTFORMAT If the data did not contain a recognizable ID + header for an Opus stream. + \retval #OP_EVERSION If the version field signaled a version this library + does not know how to parse. + \retval #OP_EBADHEADER The ID header was not properly formatted or contained + illegal values.*/ +int op_test(OpusHead *_head, + const unsigned char *_initial_data,size_t _initial_bytes); + +/**Open a stream from the given file path. + \param _path The path to the file to open. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + The failure code will be #OP_EFAULT if the file could not + be opened, or one of the other failure codes from + op_open_callbacks() otherwise. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_file(const char *_path,int *_error) + OP_ARG_NONNULL(1); + +/**Open a stream from a memory buffer. + \param _data The memory buffer to open. + \param _size The number of bytes in the buffer. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_memory(const unsigned char *_data, + size_t _size,int *_error); + +/**Open a stream from a URL. + This function behaves identically to op_open_url(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \note If you use this function, you must link against libopusurl. + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always + fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, + with internationalized domain names encoded in + punycode, before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \param[in,out] _ap A list of the \ref url_options "optional flags" to + use. + This is a variable-length list of options terminated + with NULL. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_vopen_url(const char *_url, + int *_error,va_list _ap) OP_ARG_NONNULL(1); + +/**Open a stream from a URL. + \note If you use this function, you must link against libopusurl. + \param _url The URL to open. + Currently only the , , and schemes + are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, + before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated with + NULL. + \return A freshly opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url, + int *_error,...) OP_ARG_NONNULL(1); + +/**Open a stream using the given set of callbacks to access it. + \param _stream The stream to read from (e.g., a FILE *). + 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. + read() must + be implemented. + seek() and + tell() may + be NULL, or may always return -1 to + indicate a stream is unseekable, but if + seek() is + implemented and succeeds on a particular stream, then + tell() must + also. + close() may + be NULL, 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 + stream. + Applications can read some number of bytes from the + start of the stream to help identify this as an Opus + stream, and then provide them here to allow the + 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 + 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. + You may pass in NULL if you don't want + the failure code. + The failure code will be one of +
    +
    #OP_EREAD
    +
    An underlying read, seek, or tell operation + failed when it should have succeeded, or we failed + to find data in the stream we had seen before.
    +
    #OP_EFAULT
    +
    There was a memory allocation failure, or an + internal library error.
    +
    #OP_EIMPL
    +
    The stream used a feature that is not + implemented, such as an unsupported channel + family.
    +
    #OP_EINVAL
    +
    seek() + was implemented and succeeded on this source, but + tell() + did not, or the starting position indicator was + not equal to \a _initial_bytes.
    +
    #OP_ENOTFORMAT
    +
    The stream contained a link that did not have + any logical Opus streams in it.
    +
    #OP_EBADHEADER
    +
    A required header packet was not properly + formatted, contained illegal values, or was missing + altogether.
    +
    #OP_EVERSION
    +
    An ID header contained an unrecognized version + number.
    +
    #OP_EBADLINK
    +
    We failed to find data we had seen before after + seeking.
    +
    #OP_EBADTIMESTAMP
    +
    The first or last timestamp in a link failed + basic validity checks.
    +
    + \return A freshly opened \c OggOpusFile, or NULL on error. + libopusfile does not take ownership of the stream + if the call fails. + The calling application is responsible for closing the stream if + this call returns an error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_stream, + const OpusFileCallbacks *_cb,const unsigned char *_initial_data, + size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); + +/**Partially open a stream from the given file path. + \see op_test_callbacks + \param _path The path to the file to open. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + The failure code will be #OP_EFAULT if the file could not + be opened, or one of the other failure codes from + op_open_callbacks() otherwise. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_file(const char *_path,int *_error) + OP_ARG_NONNULL(1); + +/**Partially open a stream from a memory buffer. + \see op_test_callbacks + \param _data The memory buffer to open. + \param _size The number of bytes in the buffer. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure codes. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_memory(const unsigned char *_data, + size_t _size,int *_error); + +/**Partially open a stream from a URL. + This function behaves identically to op_test_url(), except that it + takes a va_list instead of a variable number of arguments. + It does not call the va_end macro, and because it invokes the + va_arg macro, the value of \a _ap is undefined after the call. + \note If you use this function, you must link against libopusurl. + \see op_test_url + \see op_test_callbacks + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always + fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, + with internationalized domain names encoded in + punycode, before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \param[in,out] _ap A list of the \ref url_options "optional flags" to + use. + This is a variable-length list of options terminated + with NULL. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_vtest_url(const char *_url, + int *_error,va_list _ap) OP_ARG_NONNULL(1); + +/**Partially open a stream from a URL. + \note If you use this function, you must link against libopusurl. + \see op_test_callbacks + \param _url The URL to open. + Currently only the , , and + schemes are supported. + Both and may be disabled at compile + time, in which case opening such URLs will always fail. + Currently this only supports URIs. + IRIs should be converted to UTF-8 and URL-escaped, with + internationalized domain names encoded in punycode, + before passing them to this function. + \param[out] _error Returns 0 on success, or a failure code on error. + You may pass in NULL if you don't want the + failure code. + See op_open_callbacks() for a full list of failure + codes. + \param ... The \ref url_options "optional flags" to use. + This is a variable-length list of options terminated + with NULL. + \return A partially opened \c OggOpusFile, or NULL on error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url, + int *_error,...) OP_ARG_NONNULL(1); + +/**Partially open a stream using the given set of callbacks to access it. + This tests for Opusness and loads the headers for the first link. + It does not seek (although it tests for seekability). + You can query a partially open stream for the few pieces of basic + information returned by op_serialno(), op_channel_count(), op_head(), and + op_tags() (but only for the first link). + You may also determine if it is seekable via a call to op_seekable(). + You cannot read audio from the stream, seek, get the size or duration, + get information from links other than the first one, or even get the total + number of links until you finish opening the stream with op_test_open(). + If you do not need to do any of these things, you can dispose of it with + op_free() instead. + + This function is provided mostly to simplify porting existing code that used + libvorbisfile. + For new code, you are likely better off using op_test() instead, which + is less resource-intensive, requires less data to succeed, and imposes a + hard limit on the amount of data it examines (important for unseekable + streams, where all such data must be buffered until you are sure of the + stream type). + \param _stream The stream to read from (e.g., a FILE *). + 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. + read() must + be implemented. + seek() and + tell() may + be NULL, or may always return -1 to + indicate a stream is unseekable, but if + seek() is + implemented and succeeds on a particular stream, then + tell() must + also. + close() may + be NULL, 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 + stream. + Applications can read some number of bytes from the + start of the stream to help identify this as an Opus + stream, and then provide them here to allow the + stream to be tested more thoroughly, 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 + 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. + You may pass in NULL if you don't want + the failure code. + See op_open_callbacks() for a full list of failure + codes. + \return A partially opened \c OggOpusFile, or NULL on error. + libopusfile does not take ownership of the stream + if the call fails. + The calling application is responsible for closing the stream if + this call returns an error.*/ +OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_stream, + const OpusFileCallbacks *_cb,const unsigned char *_initial_data, + size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2); + +/**Finish opening a stream partially opened with op_test_callbacks() or one of + the associated convenience functions. + If this function fails, you are still responsible for freeing the + \c OggOpusFile with op_free(). + \param _of The \c OggOpusFile to finish opening. + \return 0 on success, or a negative value on error. + \retval #OP_EREAD An underlying read, seek, or tell operation failed + when it should have succeeded. + \retval #OP_EFAULT There was a memory allocation failure, or an + internal library error. + \retval #OP_EIMPL The stream used a feature that is not implemented, + such as an unsupported channel family. + \retval #OP_EINVAL The stream was not partially opened with + op_test_callbacks() or one of the associated + convenience functions. + \retval #OP_ENOTFORMAT The stream contained a link that did not have any + logical Opus streams in it. + \retval #OP_EBADHEADER A required header packet was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An ID header contained an unrecognized version + number. + \retval #OP_EBADLINK We failed to find data we had seen before after + seeking. + \retval #OP_EBADTIMESTAMP The first or last timestamp in a link failed basic + validity checks.*/ +int op_test_open(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Release all memory used by an \c OggOpusFile. + \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 + seekability, the number of links (for chained streams), plus the size, + duration, bitrate, header parameters, and meta information for each link + (or, where available, the stream as a whole). + Some of these (size, duration) are only available for seekable streams. + You can also query the current stream position, link, and playback time, + and instantaneous bitrate during playback. + + Some of these functions may be used successfully on the partially open + 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 +
      +
    1. The seek() and + tell() callbacks are both + non-NULL,
    2. +
    3. The seek() callback was + successfully executed at least once, and
    4. +
    5. The tell() callback was + successfully able to report the position indicator afterwards.
    6. +
    + This function may be called on partially-opened streams. + \param _of The \c OggOpusFile whose seekable status is to be returned. + \return A non-zero value if seekable, and 0 if unseekable.*/ +int op_seekable(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Returns the number of links in this chained stream. + This function may be called on partially-opened streams, but it will always + return 1. + The actual number of links is not known until the stream is fully opened. + \param _of The \c OggOpusFile from which to retrieve the link count. + \return For fully-open seekable streams, this returns the total number of + links in the whole stream, which will be at least 1. + For partially-open or unseekable streams, this always returns 1.*/ +int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Get the serial number of the given link in a (possibly-chained) Ogg Opus + stream. + This function may be called on partially-opened streams, but it will always + return the serial number of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the serial number. + \param _li The index of the link whose serial number should be retrieved. + Use a negative number to get the serial number of the current + link. + \return The serial number of the given link. + If \a _li is greater than the total number of links, this returns + the serial number of the last link. + If the stream is not seekable, this always returns the serial number + of the current link.*/ +opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the channel count of the given link in a (possibly-chained) Ogg Opus + stream. + This is equivalent to op_head(_of,_li)->channel_count, but + is provided for convenience. + This function may be called on partially-opened streams, but it will always + return the channel count of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the channel count. + \param _li The index of the link whose channel count should be retrieved. + Use a negative number to get the channel count of the current + link. + \return The channel count of the given link. + If \a _li is greater than the total number of links, this returns + the channel count of the last link. + If the stream is not seekable, this always returns the channel count + of the current link.*/ +int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the total (compressed) size of the stream, or of an individual link in + a (possibly-chained) Ogg Opus stream, including all headers and Ogg muxing + overhead. + \warning If the Opus stream (or link) is concurrently multiplexed with other + logical streams (e.g., video), this returns the size of the entire stream + (or link), not just the number of bytes in the first logical Opus stream. + Returning the latter would require scanning the entire file. + \param _of The \c OggOpusFile from which to retrieve the compressed size. + \param _li The index of the link whose compressed size should be computed. + Use a negative number to get the compressed size of the entire + stream. + \return The compressed size of the entire stream if \a _li is negative, the + compressed size of link \a _li if it is non-negative, or a negative + value on error. + The compressed size of the entire stream may be smaller than that + of the underlying stream if trailing garbage was detected in the + file. + \retval #OP_EINVAL The stream is not seekable (so we can't know the length), + \a _li wasn't less than the total number of links in + the stream, or the stream was only partially open.*/ +opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the total PCM length (number of samples at 48 kHz) of the stream, or of + an individual link in a (possibly-chained) Ogg Opus stream. + Users looking for op_time_total() should use op_pcm_total() + instead. + Because timestamps in Opus are fixed at 48 kHz, there is no need for a + separate function to convert this to seconds (and leaving it out avoids + introducing floating point to the API, for those that wish to avoid it). + \param _of The \c OggOpusFile from which to retrieve the PCM offset. + \param _li The index of the link whose PCM length should be computed. + Use a negative number to get the PCM length of the entire stream. + \return The PCM length of the entire stream if \a _li is negative, the PCM + length of link \a _li if it is non-negative, or a negative value on + error. + \retval #OP_EINVAL The stream is not seekable (so we can't know the length), + \a _li wasn't less than the total number of links in + the stream, or the stream was only partially open.*/ +ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the ID header information for the given link in a (possibly chained) Ogg + Opus stream. + This function may be called on partially-opened streams, but it will always + return the ID header information of the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the ID header + information. + \param _li The index of the link whose ID header information should be + retrieved. + Use a negative number to get the ID header information of the + current link. + For an unseekable stream, \a _li is ignored, and the ID header + information for the current link is always returned, if + available. + \return The contents of the ID header for the given link.*/ +const OpusHead *op_head(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Get the comment header information for the given link in a (possibly + chained) Ogg Opus stream. + This function may be called on partially-opened streams, but it will always + return the tags from the Opus stream in the first link. + \param _of The \c OggOpusFile from which to retrieve the comment header + information. + \param _li The index of the link whose comment header information should be + retrieved. + Use a negative number to get the comment header information of + the current link. + For an unseekable stream, \a _li is ignored, and the comment + header information for the current link is always returned, if + available. + \return The contents of the comment header for the given link, or + NULL if this is an unseekable stream that encountered + an invalid link.*/ +const OpusTags *op_tags(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Retrieve the index of the current link. + This is the link that produced the data most recently read by + op_read_float() or its associated functions, or, after a seek, the link + that the seek target landed in. + Reading more data may advance the link index (even on the first read after a + seek). + \param _of The \c OggOpusFile from which to retrieve the current link index. + \return The index of the current link on success, or a negative value on + failure. + For seekable streams, this is a number between 0 (inclusive) and the + value returned by op_link_count() (exclusive). + For unseekable streams, this value starts at 0 and increments by one + each time a new link is encountered (even though op_link_count() + always returns 1). + \retval #OP_EINVAL The stream was only partially open.*/ +int op_current_link(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Computes the bitrate of the stream, or of an individual link in a + (possibly-chained) Ogg Opus stream. + The stream must be seekable to compute the bitrate. + For unseekable streams, use op_bitrate_instant() to get periodic estimates. + \warning If the Opus stream (or link) is concurrently multiplexed with other + logical streams (e.g., video), this uses the size of the entire stream (or + link) to compute the bitrate, not just the number of bytes in the first + logical Opus stream. + Returning the latter requires scanning the entire file, but this may be done + by decoding the whole file and calling op_bitrate_instant() once at the + end. + Install a trivial decoding callback with op_set_decode_callback() if you + wish to skip actual decoding during this process. + \param _of The \c OggOpusFile from which to retrieve the bitrate. + \param _li The index of the link whose bitrate should be computed. + Use a negative number to get the bitrate of the whole stream. + \return The bitrate on success, or a negative value on error. + \retval #OP_EINVAL The stream was only partially open, the stream was not + seekable, or \a _li was larger than the number of + links.*/ +opus_int32 op_bitrate(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1); + +/**Compute the instantaneous bitrate, measured as the ratio of bits to playable + samples decoded since a) the last call to op_bitrate_instant(), b) the last + seek, or c) the start of playback, whichever was most recent. + This will spike somewhat after a seek or at the start/end of a chain + boundary, as pre-skip, pre-roll, and end-trimming causes samples to be + decoded but not played. + \param _of The \c OggOpusFile from which to retrieve the bitrate. + \return The bitrate, in bits per second, or a negative value on error. + \retval #OP_FALSE No data has been decoded since any of the events + described above. + \retval #OP_EINVAL The stream was only partially open.*/ +opus_int32 op_bitrate_instant(OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Obtain the current value of the position indicator for \a _of. + \param _of The \c OggOpusFile from which to retrieve the position indicator. + \return The byte position that is currently being read from. + \retval #OP_EINVAL The stream was only partially open.*/ +opus_int64 op_raw_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1); + +/**Obtain the PCM offset of the next sample to be read. + If the stream is not properly timestamped, this might not increment by the + proper amount between reads, or even return monotonically increasing + values. + \param _of The \c OggOpusFile from which to retrieve the PCM offset. + \return The PCM offset of the next sample to be read. + \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 + support it. + Seeking is implemented for all built-in stream I/O routines, though some + individual streams may not be seekable (pipes, live HTTP streams, or HTTP + streams from a server that does not support Range requests). + + op_raw_seek() is the fastest: it is guaranteed to perform at most one + physical seek, but, since the target is a byte position, makes no guarantee + how close to a given time it will come. + op_pcm_seek() provides sample-accurate seeking. + The number of physical seeks it requires is still quite small (often 1 or + 2, even in highly variable bitrate streams). + + Seeking in Opus requires decoding some pre-roll amount before playback to + allow the internal state to converge (as if recovering from packet loss). + This is handled internally by libopusfile, but means there is + little extra overhead for decoding up to the exact position requested + (since it must decode some amount of audio anyway). + It also means that decoding after seeking may not return exactly the same + 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 compressed data. + This also scans packets to update the PCM cursor. + It will cross a logical bitstream boundary, but only if it can't get any + packets out of the tail of the link to which it seeks. + \param _of The \c OggOpusFile in which to seek. + \param _byte_offset The byte position to seek to. + This must be between 0 and #op_raw_total(\a _of,\c -1) + (inclusive). + \return 0 on success, or a negative error code on failure. + \retval #OP_EREAD The underlying seek operation failed. + \retval #OP_EINVAL The stream was only partially open, or the target was + outside the valid range for the stream. + \retval #OP_ENOSEEK This stream is not seekable. + \retval #OP_EBADLINK Failed to initialize a decoder for a stream for an + unknown reason.*/ +int op_raw_seek(OggOpusFile *_of,opus_int64 _byte_offset) OP_ARG_NONNULL(1); + +/**Seek to the specified PCM offset, such that decoding will begin at exactly + the requested position. + \param _of The \c OggOpusFile in which to seek. + \param _pcm_offset The PCM offset to seek to. + This is in samples at 48 kHz relative to the start of the + stream. + \return 0 on success, or a negative value on error. + \retval #OP_EREAD An underlying read or seek operation failed. + \retval #OP_EINVAL The stream was only partially open, or the target was + outside the valid range for the stream. + \retval #OP_ENOSEEK This stream is not seekable. + \retval #OP_EBADLINK We failed to find data we had seen before, or the + bitstream structure was sufficiently malformed that + 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. + The general functions, op_read() and op_read_float() return 16-bit or + floating-point output, both using native endian ordering. + The number of channels returned can change from link to link in a chained + stream. + There are special functions, op_read_stereo() and op_read_float_stereo(), + which always output two channels, to simplify applications which do not + wish to handle multichannel audio. + These downmix multichannel files to two channels, so they can always return + samples in the same format for every link in a chained file. + + If the rest of your audio processing chain can handle floating point, the + floating-point routines should be preferred, as they prevent clipping and + other issues which might be avoided entirely if, e.g., you scale down the + volume at some other stage. + However, if you intend to consume 16-bit samples directly, the conversion in + libopusfile provides noise-shaping dithering and, if compiled + against libopus 1.1 or later, soft-clipping prevention. + + libopusfile can also be configured at compile time to use the + fixed-point libopus API. + If so, libopusfile's floating-point API may also be disabled. + In that configuration, nothing in libopusfile will use any + floating-point operations, to simplify support on devices without an + adequate FPU. + + \warning HTTPS streams may be be vulnerable to truncation attacks if you do + not check the error return code from op_read_float() or its associated + functions. + If the remote peer does not close the connection gracefully (with a TLS + "close notify" message), these functions will return #OP_EREAD instead of 0 + when they reach the end of the file. + If you are reading from an 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.*/ +#define OP_DEC_FORMAT_SHORT (7008) +/**Indicates that the decoding callback should produce 32-bit native-endian + float samples.*/ +#define OP_DEC_FORMAT_FLOAT (7040) + +/**Indicates that the decoding callback did not decode anything, and that + libopusfile should decode normally instead.*/ +#define OP_DEC_USE_DEFAULT (6720) + +/**Called to decode an Opus packet. + This should invoke the functional equivalent of opus_multistream_decode() or + opus_multistream_decode_float(), except that it returns 0 on success + instead of the number of decoded samples (which is known a priori). + \param _ctx The application-provided callback context. + \param _decoder The decoder to use to decode the packet. + \param[out] _pcm The buffer to decode into. + This will always have enough room for \a _nchannels of + \a _nsamples samples, which should be placed into this + buffer interleaved. + \param _op The packet to decode. + This will always have its granule position set to a valid + value. + \param _nsamples The number of samples expected from the packet. + \param _nchannels The number of channels expected from the packet. + \param _format The desired sample output format. + This is either #OP_DEC_FORMAT_SHORT or + #OP_DEC_FORMAT_FLOAT. + \param _li The index of the link from which this packet was decoded. + \return A non-negative value on success, or a negative value on error. + Any error codes should be the same as those returned by + opus_multistream_decode() or opus_multistream_decode_float(). + Success codes are as follows: + \retval 0 Decoding was successful. + The application has filled the buffer with + exactly \a _nsamples*\a + _nchannels samples in the requested + format. + \retval #OP_DEC_USE_DEFAULT No decoding was done. + libopusfile should do the decoding + by itself instead.*/ +typedef int (*op_decode_cb_func)(void *_ctx,OpusMSDecoder *_decoder,void *_pcm, + const ogg_packet *_op,int _nsamples,int _nchannels,int _format,int _li); + +/**Sets the packet decode callback function. + If set, this is called once for each packet that needs to be decoded. + This can be used by advanced applications to do additional processing on the + compressed or uncompressed data. + For example, an application might save the final entropy coder state for + debugging and testing purposes, or it might apply additional filters + before the downmixing, dithering, or soft-clipping performed by + libopusfile, so long as these filters do not introduce any + latency. + + A call to this function is no guarantee that the audio will eventually be + delivered to the application. + libopusfile may discard some or all of the decoded audio data + (i.e., at the beginning or end of a link, or after a seek), however the + callback is still required to provide all of it. + \param _of The \c OggOpusFile on which to set the decode callback. + \param _decode_cb The callback function to call. + This may be NULL to disable calling the + callback. + \param _ctx The application-provided context pointer to pass to the + callback on each call.*/ +void op_set_decode_callback(OggOpusFile *_of, + op_decode_cb_func _decode_cb,void *_ctx) OP_ARG_NONNULL(1); + +/**Gain offset type that indicates that the provided offset is relative to the + header gain. + This is the default.*/ +#define OP_HEADER_GAIN (0) + +/**Gain offset type that indicates that the provided offset is relative to the + R128_ALBUM_GAIN value (if any), in addition to the header gain.*/ +#define OP_ALBUM_GAIN (3007) + +/**Gain offset type that indicates that the provided offset is relative to the + R128_TRACK_GAIN value (if any), in addition to the header gain.*/ +#define OP_TRACK_GAIN (3008) + +/**Gain offset type that indicates that the provided offset should be used as + the gain directly, without applying any the header or track gains.*/ +#define OP_ABSOLUTE_GAIN (3009) + +/**Sets the gain to be used for decoded output. + By default, the gain in the header is applied with no additional offset. + The total gain (including header gain and/or track gain, if applicable, and + this offset), will be clamped to [-32768,32767]/256 dB. + This is more than enough to saturate or underflow 16-bit PCM. + \note The new gain will not be applied to any already buffered, decoded + output. + This means you cannot change it sample-by-sample, as at best it will be + updated packet-by-packet. + It is meant for setting a target volume level, rather than applying smooth + fades, etc. + \param _of The \c OggOpusFile on which to set the gain offset. + \param _gain_type One of #OP_HEADER_GAIN, #OP_ALBUM_GAIN, + #OP_TRACK_GAIN, or #OP_ABSOLUTE_GAIN. + \param _gain_offset_q8 The gain offset to apply, in 1/256ths of a dB. + \return 0 on success or a negative value on error. + \retval #OP_EINVAL The \a _gain_type was unrecognized.*/ +int op_set_gain_offset(OggOpusFile *_of, + int _gain_type,opus_int32 _gain_offset_q8) OP_ARG_NONNULL(1); + +/**Sets whether or not dithering is enabled for 16-bit decoding. + By default, when libopusfile is compiled to use floating-point + internally, calling op_read() or op_read_stereo() will first decode to + float, and then convert to fixed-point using noise-shaping dithering. + This flag can be used to disable that dithering. + When the application uses op_read_float() or op_read_float_stereo(), or when + the library has been compiled to decode directly to fixed point, this flag + has no effect. + \param _of The \c OggOpusFile on which to enable or disable dithering. + \param _enabled A non-zero value to enable dithering, or 0 to disable it.*/ +void op_set_dither_enabled(OggOpusFile *_of,int _enabled) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream. + \note Although \a _buf_size must indicate the total number of values that + can be stored in \a _pcm, the return value is the number of samples + per channel. + This is done because +
      +
    1. The channel count cannot be known a priori (reading more samples might + advance us into the next link, with a different channel count), so + \a _buf_size cannot also be in units of samples per channel,
    2. +
    3. Returning the samples per channel matches the libopus API + as closely as we're able,
    4. +
    5. Returning the total number of values instead of samples per channel + would mean the caller would need a division to compute the samples per + channel, and might worry about the possibility of getting back samples + for some channels and not others, and
    6. +
    7. This approach is relatively fool-proof: if an application passes too + small a value to \a _buf_size, they will simply get fewer samples back, + and if they assume the return value is the total number of values, then + they will simply read too few (rather than reading too many and going + off the end of the buffer).
    8. +
    + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed native-endian 16-bit values at 48 kHz + with a nominal range of [-32768,32767). + Multiple channels are interleaved using the + Vorbis + channel ordering. + 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. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (5760 + values per channel). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + libopusfile may return less data than + requested. + If so, there is no guarantee that the remaining data + in \a _pcm will be unmodified. + \param[out] _li The index of the link this data was decoded from. + You may pass NULL if you do not need this + information. + If this function fails (returning a negative value), + this parameter is left unset. + \return The number of samples read per channel on success, or a negative + value on failure. + The channel count can be retrieved on success by calling + op_head(_of,*_li). + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for all channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of, + opus_int16 *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream. + \note Although \a _buf_size must indicate the total number of values that + can be stored in \a _pcm, the return value is the number of samples + per channel. +
      +
    1. The channel count cannot be known a priori (reading more samples might + advance us into the next link, with a different channel count), so + \a _buf_size cannot also be in units of samples per channel,
    2. +
    3. Returning the samples per channel matches the libopus API + as closely as we're able,
    4. +
    5. Returning the total number of values instead of samples per channel + would mean the caller would need a division to compute the samples per + channel, and might worry about the possibility of getting back samples + for some channels and not others, and
    6. +
    7. This approach is relatively fool-proof: if an application passes too + small a value to \a _buf_size, they will simply get fewer samples back, + and if they assume the return value is the total number of values, then + they will simply read too few (rather than reading too many and going + off the end of the buffer).
    8. +
    + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples as + signed floats at 48 kHz with a nominal range of + [-1.0,1.0]. + Multiple channels are interleaved using the + Vorbis + channel ordering. + 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. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (5760 + samples per channel). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \param[out] _li The index of the link this data was decoded from. + You may pass NULL if you do not need this + information. + If this function fails (returning a negative value), + this parameter is left unset. + \return The number of samples read per channel on success, or a negative + value on failure. + The channel count can be retrieved on success by calling + op_head(_of,*_li). + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for all channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of, + float *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream and downmixes to stereo, if necessary. + This function is intended for simple players that want a uniform output + format, even if the channel count changes between links in a chained + stream. + \note \a _buf_size indicates the total number of values that can be stored + in \a _pcm, while the return value is the number of samples per + channel, even though the channel count is known, for consistency with + op_read(). + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed native-endian 16-bit values at 48 kHz + with a nominal range of [-32768,32767). + The left and right channels are interleaved in the + buffer. + 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. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (11520 + values total). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \return The number of samples read per channel on success, or a negative + value on failure. + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for both channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of, + opus_int16 *_pcm,int _buf_size) OP_ARG_NONNULL(1); + +/**Reads more samples from the stream and downmixes to stereo, if necessary. + This function is intended for simple players that want a uniform output + format, even if the channel count changes between links in a chained + stream. + \note \a _buf_size indicates the total number of values that can be stored + in \a _pcm, while the return value is the number of samples per + channel, even though the channel count is known, for consistency with + op_read_float(). + \param _of The \c OggOpusFile from which to read. + \param[out] _pcm A buffer in which to store the output PCM samples, as + signed floats at 48 kHz with a nominal range of + [-1.0,1.0]. + The left and right channels are interleaved in the + buffer. + 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. + It is recommended that this be large enough for at + least 120 ms of data at 48 kHz per channel (11520 + values total). + Smaller buffers will simply return less data, possibly + consuming more memory to buffer the data internally. + If less than \a _buf_size values are returned, + libopusfile makes no guarantee that the + remaining data in \a _pcm will be unmodified. + \return The number of samples read per channel on success, or a negative + value on failure. + The number of samples returned may be 0 if the buffer was too small + to store even a single sample for both channels, or if end-of-file + was reached. + The list of possible failure codes follows. + Most of them can only be returned by unseekable, chained streams + that encounter a new link. + \retval #OP_HOLE There was a hole in the data, and some samples + may have been skipped. + Call this function again to continue decoding + past the hole. + \retval #OP_EREAD An underlying read operation failed. + This may signal a truncation attack from an + source. + \retval #OP_EFAULT An internal memory allocation failed. + \retval #OP_EIMPL An unseekable stream encountered a new link that + used a feature that is not implemented, such as + an unsupported channel family. + \retval #OP_EINVAL The stream was only partially open. + \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that + that did not have any logical Opus streams in it. + \retval #OP_EBADHEADER An unseekable stream encountered a new link with a + required header packet that was not properly + formatted, contained illegal values, or was + missing altogether. + \retval #OP_EVERSION An unseekable stream encountered a new link with + an ID header that contained an unrecognized + version number. + \retval #OP_EBADPACKET Failed to properly decode the next packet. + \retval #OP_EBADLINK We failed to find data we had seen before. + \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with + a starting timestamp that failed basic validity + checks.*/ +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 +# endif + +# if defined(__cplusplus) +} +# endif + +#endif diff --git a/src/opusfile/opusfile.pc b/src/opusfile/opusfile.pc new file mode 100644 index 00000000..398f8c44 --- /dev/null +++ b/src/opusfile/opusfile.pc @@ -0,0 +1,15 @@ +# opusfile installed pkg-config file + +prefix=/usr/local +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: opusfile +Description: High-level Opus decoding library +Version: 0.12 +Requires.private: ogg >= 1.3 opus >= 1.0.1 +Conflicts: +Libs: -L${libdir} -lopusfile +Libs.private: +Cflags: -I${includedir}/opus diff --git a/src/opusfile/stream.c b/src/opusfile/stream.c new file mode 100644 index 00000000..9421d8fa --- /dev/null +++ b/src/opusfile/stream.c @@ -0,0 +1,415 @@ +/******************************************************************** + * * + * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. * + * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * + * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * + * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * + * * + * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2018 * + * by the Xiph.Org Foundation and contributors https://xiph.org/ * + * * + ******************************************************************** + + function: stdio-based convenience library for opening/seeking/decoding + last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $ + + ********************************************************************/ +//#ifdef HAVE_CONFIG_H +#include "config.h" +//#endif + +#include "internal.h" +#include +#include +#include +#include +#include +#if defined(_WIN32) +# include +#endif + +typedef struct OpusMemStream OpusMemStream; + +#define OP_MEM_SIZE_MAX (~(size_t)0>>1) +#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX) + +/*The context information needed to read from a block of memory as if it were a + file.*/ +struct OpusMemStream{ + /*The block of memory to read from.*/ + const unsigned char *data; + /*The total size of the block. + This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while + seeking.*/ + ptrdiff_t size; + /*The current file position. + This is allowed to be set arbitrarily greater than size (i.e., past the end + of the block, though we will not read data past the end of the block), but + is not allowed to be negative (i.e., before the beginning of the block).*/ + ptrdiff_t pos; +}; + +static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){ + FILE *stream; + size_t ret; + /*Check for empty read.*/ + if(_buf_size<=0)return 0; + stream=(FILE *)_stream; + ret=fread(_ptr,1,_buf_size,stream); + OP_ASSERT(ret<=(size_t)_buf_size); + /*If ret==0 and !feof(stream), there was a read error.*/ + return ret>0||feof(stream)?(int)ret:OP_EREAD; +} + +static int op_fseek(void *_stream,opus_int64 _offset,int _whence){ +#if defined(_WIN32) + /*_fseeki64() is not exposed until MSVCRT80. + This is the default starting with MSVC 2005 (_MSC_VER>=1400), but we want + to allow linking against older MSVCRT versions for compatibility back to + XP without installing extra runtime libraries. + i686-pc-mingw32 does not have fseeko() and requires + __MSVCRT_VERSION__>=0x800 for _fseeki64(), which screws up linking with + other libraries (that don't use MSVCRT80 from MSVC 2005 by default). + i686-w64-mingw32 does have fseeko() and respects _FILE_OFFSET_BITS, but I + don't know how to detect that at compile time. + We could just use fseeko64() (which is available in both), but it's + implemented using fgetpos()/fsetpos() just like this code, except without + the overflow checking, so we prefer our version.*/ + opus_int64 pos; + /*We don't use fpos_t directly because it might be a struct if __STDC__ is + non-zero or _INTEGRAL_MAX_BITS < 64. + I'm not certain when the latter is true, but someone could in theory set + the former. + Either way, it should be binary compatible with a normal 64-bit int (this + assumption is not portable, but I believe it is true for MSVCRT).*/ + OP_ASSERT(sizeof(pos)==sizeof(fpos_t)); + /*Translate the seek to an absolute one.*/ + if(_whence==SEEK_CUR){ + int ret; + ret=fgetpos((FILE *)_stream,(fpos_t *)&pos); + if(ret)return ret; + } + else if(_whence==SEEK_END)pos=_filelengthi64(_fileno((FILE *)_stream)); + else if(_whence==SEEK_SET)pos=0; + else return -1; + /*Check for errors or overflow.*/ + if(pos<0||_offset<-pos||_offset>OP_INT64_MAX-pos)return -1; + pos+=_offset; + return fsetpos((FILE *)_stream,(fpos_t *)&pos); +#else + /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer + it except on Windows.*/ + return fseeko((FILE *)_stream,(off_t)_offset,_whence); +#endif +} + +static opus_int64 op_ftell(void *_stream){ +#if defined(_WIN32) + /*_ftelli64() is not exposed until MSVCRT80, and ftello()/ftello64() have + the same problems as fseeko()/fseeko64() in MingW. + See above for a more detailed explanation.*/ + opus_int64 pos; + OP_ASSERT(sizeof(pos)==sizeof(fpos_t)); + return fgetpos((FILE *)_stream,(fpos_t *)&pos)?-1:pos; +#else + /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer + it except on Windows.*/ + return ftello((FILE *)_stream); +#endif +} + +static const OpusFileCallbacks OP_FILE_CALLBACKS={ + op_fread, + op_fseek, + op_ftell, + (op_close_func)fclose +}; + +#if defined(_WIN32) +# include +# include + +/*Windows doesn't accept UTF-8 by default, and we don't have a wchar_t API, + so if we just pass the path to fopen(), then there'd be no way for a user + of our API to open a Unicode filename. + Instead, we translate from UTF-8 to UTF-16 and use Windows' wchar_t API. + This makes this API more consistent with platforms where the character set + used by fopen is the same as used on disk, which is generally UTF-8, and + with our metadata API, which always uses UTF-8.*/ +static wchar_t *op_utf8_to_utf16(const char *_src){ + wchar_t *dst; + size_t len; + len=strlen(_src); + /*Worst-case output is 1 wide character per 1 input character.*/ + dst=(wchar_t *)_ogg_malloc(sizeof(*dst)*(len+1)); + if(dst!=NULL){ + size_t si; + size_t di; + for(di=si=0;si=0x80U){ + /*This is a 2-byte sequence that is not overlong.*/ + dst[di++]=w; + si++; + continue; + } + } + else{ + int c2; + /*This is safe, because c1 was not 0 and _src is NUL-terminated.*/ + c2=(unsigned char)_src[si+2]; + if((c2&0xC0)==0x80){ + /*Found at least two continuation bytes.*/ + if((c0&0xF0)==0xE0){ + wchar_t w; + /*Start byte says this is a 3-byte sequence.*/ + w=(c0&0xF)<<12|(c1&0x3F)<<6|c2&0x3F; + if(w>=0x800U&&(w<0xD800||w>=0xE000)&&w<0xFFFE){ + /*This is a 3-byte sequence that is not overlong, not a + UTF-16 surrogate pair value, and not a 'not a character' + value.*/ + dst[di++]=w; + si+=2; + continue; + } + } + else{ + int c3; + /*This is safe, because c2 was not 0 and _src is + NUL-terminated.*/ + c3=(unsigned char)_src[si+3]; + if((c3&0xC0)==0x80){ + /*Found at least three continuation bytes.*/ + if((c0&0xF8)==0xF0){ + opus_uint32 w; + /*Start byte says this is a 4-byte sequence.*/ + w=(c0&7)<<18|(c1&0x3F)<<12|(c2&0x3F)<<6&(c3&0x3F); + if(w>=0x10000U&&w<0x110000U){ + /*This is a 4-byte sequence that is not overlong and not + greater than the largest valid Unicode code point. + Convert it to a surrogate pair.*/ + w-=0x10000; + dst[di++]=(wchar_t)(0xD800+(w>>10)); + dst[di++]=(wchar_t)(0xDC00+(w&0x3FF)); + si+=3; + continue; + } + } + } + } + } + } + } + } + /*If we got here, we encountered an illegal UTF-8 sequence.*/ + _ogg_free(dst); + return NULL; + } + OP_ASSERT(di<=len); + dst[di]='\0'; + } + return dst; +} + +/*fsetpos() internally dispatches to the win32 API call SetFilePointer(). + According to SetFilePointer()'s documentation [0], the behavior is + undefined if you do not call it on "a file stored on a seeking device". + However, none of the MSVCRT seeking functions verify what kind of file is + being used before calling it (which I believe is a bug, since they are + supposed to fail and return an error, but it is a bug that has been there + for multiple decades now). + In practice, SetFilePointer() appears to succeed for things like stdin, + even when you are not just piping in a regular file, which prevents the use + of this API to determine whether it is possible to seek in a file at all. + Therefore, we take the approach recommended by the SetFilePointer() + documentation and confirm the type of file using GetFileType() first. + We do this once, when the file is opened, and return the corresponding + callback in order to avoid an extra win32 API call on every seek in the + common case. + Hopefully the return value of GetFileType() cannot actually change for the + lifetime of a file handle. + [0] https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-setfilepointer +*/ +static int op_fseek_fail(void *_stream,opus_int64 _offset,int _whence){ + (void)_stream; + (void)_offset; + (void)_whence; + return -1; +} + +static const OpusFileCallbacks OP_UNSEEKABLE_FILE_CALLBACKS={ + op_fread, + op_fseek_fail, + op_ftell, + (op_close_func)fclose +}; + +# define WIN32_LEAN_AND_MEAN +# define WIN32_EXTRA_LEAN +# include + +static const OpusFileCallbacks *op_get_file_callbacks(FILE *_fp){ + intptr_t h_file; + h_file=_get_osfhandle(_fileno(_fp)); + if(h_file!=-1 + &&(GetFileType((HANDLE)h_file)&~FILE_TYPE_REMOTE)==FILE_TYPE_DISK){ + return &OP_FILE_CALLBACKS; + } + return &OP_UNSEEKABLE_FILE_CALLBACKS; +} +#else +static const OpusFileCallbacks *op_get_file_callbacks(FILE *_fp){ + (void)_fp; + return &OP_FILE_CALLBACKS; +} +#endif + +void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){ + FILE *fp; +#if !defined(_WIN32) + fp=fopen(_path,_mode); +#else + fp=NULL; + { + wchar_t *wpath; + wchar_t *wmode; + wpath=op_utf8_to_utf16(_path); + wmode=op_utf8_to_utf16(_mode); + if(wmode==NULL)errno=EINVAL; + else if(wpath==NULL)errno=ENOENT; + else fp=_wfopen(wpath,wmode); + _ogg_free(wmode); + _ogg_free(wpath); + } +#endif + if(fp!=NULL)*_cb=*op_get_file_callbacks(fp); + return fp; +} + +void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){ + FILE *fp; + fp=fdopen(_fd,_mode); + if(fp!=NULL)*_cb=*op_get_file_callbacks(fp); + return fp; +} + +void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode, + void *_stream){ + FILE *fp; +#if !defined(_WIN32) + fp=freopen(_path,_mode,(FILE *)_stream); +#else + fp=NULL; + { + wchar_t *wpath; + wchar_t *wmode; + wpath=op_utf8_to_utf16(_path); + wmode=op_utf8_to_utf16(_mode); + if(wmode==NULL)errno=EINVAL; + else if(wpath==NULL)errno=ENOENT; + else fp=_wfreopen(wpath,wmode,(FILE *)_stream); + _ogg_free(wmode); + _ogg_free(wpath); + } +#endif + if(fp!=NULL)*_cb=*op_get_file_callbacks(fp); + return fp; +} + +static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){ + OpusMemStream *stream; + ptrdiff_t size; + ptrdiff_t pos; + stream=(OpusMemStream *)_stream; + /*Check for empty read.*/ + if(_buf_size<=0)return 0; + size=stream->size; + pos=stream->pos; + /*Check for EOF.*/ + if(pos>=size)return 0; + /*Check for a short read.*/ + _buf_size=(int)OP_MIN(size-pos,_buf_size); + memcpy(_ptr,stream->data+pos,_buf_size); + pos+=_buf_size; + stream->pos=pos; + return _buf_size; +} + +static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){ + OpusMemStream *stream; + ptrdiff_t pos; + stream=(OpusMemStream *)_stream; + pos=stream->pos; + OP_ASSERT(pos>=0); + switch(_whence){ + case SEEK_SET:{ + /*Check for overflow:*/ + if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1; + pos=(ptrdiff_t)_offset; + }break; + case SEEK_CUR:{ + /*Check for overflow:*/ + if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1; + pos=(ptrdiff_t)(pos+_offset); + }break; + case SEEK_END:{ + ptrdiff_t size; + size=stream->size; + OP_ASSERT(size>=0); + /*Check for overflow:*/ + if(_offset<-size||_offset>OP_MEM_DIFF_MAX-size)return -1; + pos=(ptrdiff_t)(size+_offset); + }break; + default:return -1; + } + stream->pos=pos; + return 0; +} + +static opus_int64 op_mem_tell(void *_stream){ + OpusMemStream *stream; + stream=(OpusMemStream *)_stream; + return (ogg_int64_t)stream->pos; +} + +static int op_mem_close(void *_stream){ + _ogg_free(_stream); + return 0; +} + +static const OpusFileCallbacks OP_MEM_CALLBACKS={ + op_mem_read, + op_mem_seek, + op_mem_tell, + op_mem_close +}; + +void *op_mem_stream_create(OpusFileCallbacks *_cb, + const unsigned char *_data,size_t _size){ + OpusMemStream *stream; + if(_size>OP_MEM_SIZE_MAX)return NULL; + stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream)); + if(stream!=NULL){ + *_cb=*&OP_MEM_CALLBACKS; + stream->data=_data; + stream->size=_size; + stream->pos=0; + } + return stream; +} diff --git a/tests/host/Makefile b/tests/host/Makefile index 24196635..9a219465 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -26,13 +26,59 @@ libflac=../../src/libflac/md5.c ../../src/libflac/window.c ../../src/libflac/mem ../../src/libflac/format.c ../../src/libflac/lpc.c ../../src/libflac/crc.c ../../src/libflac/bitreader.c ../../src/libflac/bitmath.c \ ../../src/libflac/stream_decoder.c ../../src/libflac/float.c +libogg=../../src/libogg/framing.c ../../src/libogg/bitwise.c + +libopus=../../src/libopus/opus_decoder.c ../../src/libopus/opus_projection_decoder.c ../../src/libopus/opus.c ../../src/libopus/opus_multistream.c \ +../../src/libopus/opus_multistream_encoder.c ../../src/libopus/repacketizer.c ../../src/libopus/opus_multistream_decoder.c \ +../../src/libopus/mapping_matrix.c ../../src/libopus/opus_projection_encoder.c ../../src/libopus/silk/NLSF_VQ_weights_laroia.c \ +../../src/libopus/silk/decode_core.c ../../src/libopus/silk/resampler_down2_3.c ../../src/libopus/silk/resampler_private_down_FIR.c \ +../../src/libopus/silk/tables_other.c ../../src/libopus/silk/resampler_private_up2_HQ.c ../../src/libopus/silk/init_encoder.c \ +../../src/libopus/silk/tables_NLSF_CB_WB.c ../../src/libopus/silk/control_codec.c ../../src/libopus/silk/decode_frame.c \ +../../src/libopus/silk/table_LSF_cos.c ../../src/libopus/silk/resampler_private_AR2.c ../../src/libopus/silk/NLSF_del_dec_quant.c \ +../../src/libopus/silk/VQ_WMat_EC.c ../../src/libopus/silk/encode_indices.c ../../src/libopus/silk/sort.c ../../src/libopus/silk/NSQ.c \ +../../src/libopus/silk/NLSF_unpack.c ../../src/libopus/silk/bwexpander_32.c ../../src/libopus/silk/tables_NLSF_CB_NB_MB.c \ +../../src/libopus/silk/ana_filt_bank_1.c ../../src/libopus/silk/resampler_down2.c ../../src/libopus/silk/stereo_encode_pred.c \ +../../src/libopus/silk/bwexpander.c ../../src/libopus/silk/PLC.c ../../src/libopus/silk/pitch_est_tables.c ../../src/libopus/silk/NLSF2A.c \ +../../src/libopus/silk/stereo_quant_pred.c ../../src/libopus/silk/debug.c ../../src/libopus/silk/LPC_analysis_filter.c \ +../../src/libopus/silk/control_audio_bandwidth.c ../../src/libopus/silk/decode_indices.c ../../src/libopus/silk/sigm_Q15.c \ +../../src/libopus/silk/resampler_private_IIR_FIR.c ../../src/libopus/silk/log2lin.c ../../src/libopus/silk/A2NLSF.c \ +../../src/libopus/silk/quant_LTP_gains.c ../../src/libopus/silk/NLSF_stabilize.c ../../src/libopus/silk/fixed/find_pred_coefs_FIX.c \ +../../src/libopus/silk/fixed/autocorr_FIX.c ../../src/libopus/silk/fixed/burg_modified_FIX.c ../../src/libopus/silk/fixed/vector_ops_FIX.c \ +../../src/libopus/silk/fixed/find_LTP_FIX.c ../../src/libopus/silk/fixed/find_pitch_lags_FIX.c ../../src/libopus/silk/fixed/schur64_FIX.c \ +../../src/libopus/silk/fixed/noise_shape_analysis_FIX.c ../../src/libopus/silk/fixed/find_LPC_FIX.c \ +../../src/libopus/silk/fixed/residual_energy16_FIX.c ../../src/libopus/silk/fixed/apply_sine_window_FIX.c \ +../../src/libopus/silk/fixed/regularize_correlations_FIX.c ../../src/libopus/silk/fixed/k2a_Q16_FIX.c \ +../../src/libopus/silk/fixed/encode_frame_FIX.c ../../src/libopus/silk/fixed/k2a_FIX.c ../../src/libopus/silk/fixed/pitch_analysis_core_FIX.c \ +../../src/libopus/silk/fixed/process_gains_FIX.c ../../src/libopus/silk/fixed/LTP_scale_ctrl_FIX.c \ +../../src/libopus/silk/fixed/warped_autocorrelation_FIX.c ../../src/libopus/silk/fixed/schur_FIX.c \ +../../src/libopus/silk/fixed/LTP_analysis_filter_FIX.c ../../src/libopus/silk/fixed/corrMatrix_FIX.c \ +../../src/libopus/silk/fixed/residual_energy_FIX.c ../../src/libopus/silk/LPC_fit.c ../../src/libopus/silk/tables_gain.c \ +../../src/libopus/silk/decode_parameters.c ../../src/libopus/silk/tables_pitch_lag.c ../../src/libopus/silk/stereo_MS_to_LR.c \ +../../src/libopus/silk/dec_API.c ../../src/libopus/silk/code_signs.c ../../src/libopus/silk/shell_coder.c \ +../../src/libopus/silk/stereo_find_predictor.c ../../src/libopus/silk/init_decoder.c ../../src/libopus/silk/decode_pulses.c \ +../../src/libopus/silk/gain_quant.c ../../src/libopus/silk/check_control_input.c ../../src/libopus/silk/tables_LTP.c \ +../../src/libopus/silk/resampler_rom.c ../../src/libopus/silk/NSQ_del_dec.c ../../src/libopus/silk/decode_pitch.c ../../src/libopus/silk/VAD.c \ +../../src/libopus/silk/NLSF_decode.c ../../src/libopus/silk/sum_sqr_shift.c ../../src/libopus/silk/stereo_LR_to_MS.c \ +../../src/libopus/silk/encode_pulses.c ../../src/libopus/silk/control_SNR.c ../../src/libopus/silk/tables_pulses_per_block.c \ +../../src/libopus/silk/LP_variable_cutoff.c ../../src/libopus/silk/enc_API.c ../../src/libopus/silk/interpolate.c \ +../../src/libopus/silk/LPC_inv_pred_gain.c ../../src/libopus/silk/NLSF_VQ.c ../../src/libopus/silk/lin2log.c \ +../../src/libopus/silk/resampler.c ../../src/libopus/silk/NLSF_encode.c ../../src/libopus/silk/CNG.c ../../src/libopus/silk/stereo_decode_pred.c \ +../../src/libopus/silk/process_NLSFs.c ../../src/libopus/silk/HP_variable_cutoff.c ../../src/libopus/silk/biquad_alt.c \ +../../src/libopus/silk/inner_prod_aligned.c ../../src/libopus/silk/decoder_set_fs.c ../../src/libopus/celt/celt.c \ +../../src/libopus/celt/mdct.c ../../src/libopus/celt/cwrs.c ../../src/libopus/celt/rate.c ../../src/libopus/celt/vq.c \ +../../src/libopus/celt/quant_bands.c ../../src/libopus/celt/celt_decoder.c ../../src/libopus/celt/celt_lpc.c \ +../../src/libopus/celt/celt_encoder.c ../../src/libopus/celt/entenc.c ../../src/libopus/celt/bands.c ../../src/libopus/celt/kiss_fft.c \ +../../src/libopus/celt/pitch.c ../../src/libopus/celt/entdec.c ../../src/libopus/celt/laplace.c ../../src/libopus/celt/entcode.c \ +../../src/libopus/celt/modes.c ../../src/libopus/celt/mathops.c ../../src/libopus/opus_encoder.c + +opusfile=../../src/opusfile/opusfile.c ../../src/opusfile/stream.c ../../src/opusfile/internal.c ../../src/opusfile/info.c CCOPTS=-g -Wunused-parameter -Wall -m32 -include Arduino.h CPPOPTS=-g -Wunused-parameter -Wall -std=c++11 -m32 -include Arduino.h .phony: all -all: mp3 aac wav midi +all: mp3 aac wav midi opus mp3: FORCE rm -f *.o @@ -60,7 +106,16 @@ midi: FORCE rm -f *.o echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./midi +opus: FORCE + rm -f *.o + gcc $(CCOPTS) -DUSE_DEFAULT_STDLIB -c $(libogg) -I ../../src/ -I. + gcc $(CCOPTS) -DUSE_DEFAULT_STDLIB -c $(libopus) -I ../../src/ -I. + gcc $(CCOPTS) -DUSE_DEFAULT_STDLIB -c $(opusfile) -I ../../src/ -I. + g++ $(CPPOPTS) -o opus opus.cpp Serial.cpp *.o ../../src/AudioFileSourceSTDIO.cpp ../../src/AudioOutputSTDIO.cpp ../../src/AudioGeneratorOpus.cpp ../../src/AudioLogger.cpp -I ../../src/ -I. + rm -f *.o + echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./opus + clean: - rm -f mp3 aac wav midi *.o + rm -f mp3 aac wav midi opus *.o FORCE: diff --git a/tests/host/opus.cpp b/tests/host/opus.cpp new file mode 100644 index 00000000..45e8d712 --- /dev/null +++ b/tests/host/opus.cpp @@ -0,0 +1,25 @@ +#include +#include "AudioFileSourceSTDIO.h" +#include "AudioOutputSTDIO.h" +#include "AudioGeneratorOpus.h" + +#define OPUS "../../examples/PlayOpusFromSPIFFS/data/gs-16b-2c-44100hz.opus" + +int main(int argc, char **argv) +{ + (void) argc; + (void) argv; + + AudioFileSourceSTDIO *file = new AudioFileSourceSTDIO(OPUS); + AudioOutputSTDIO *out = new AudioOutputSTDIO(); + out->SetFilename("opus.wav"); + AudioGeneratorOpus *opus = new AudioGeneratorOpus(); + + opus->begin(file, out); + while (opus->loop()) { /*noop*/ } + opus->stop(); + + delete out; + delete opus; + delete file; +} From a0a06a9832fc27d8d932af8927197c8a0150a4c7 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 11 Aug 2020 22:04:41 -0700 Subject: [PATCH 017/150] Reduce OpusFile RAM by only allowing mono/stereo (#295) --- src/opusfile/internal.h | 2 +- src/opusfile/opusfile.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/opusfile/internal.h b/src/opusfile/internal.h index e73989c0..1c47eecb 100644 --- a/src/opusfile/internal.h +++ b/src/opusfile/internal.h @@ -109,7 +109,7 @@ void op_fatal_impl(const char *_str,const char *_file,int _line); (OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount)) /*The maximum channel count for any mapping we'll actually decode.*/ -# define OP_NCHANNELS_MAX (8) +# define OP_NCHANNELS_MAX (2) /*Initial state.*/ # define OP_NOTOPEN (0) diff --git a/src/opusfile/opusfile.c b/src/opusfile/opusfile.c index 23f05ef9..bfd3c9e5 100644 --- a/src/opusfile/opusfile.c +++ b/src/opusfile/opusfile.c @@ -3001,7 +3001,7 @@ static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={ #endif #if defined(OP_FIXED_POINT) - +#if 0 /*Matrices for downmixing from the supported channel counts to stereo. The matrices with 5 or more channels are normalized to a total volume of 2.0, since most mixes sound too quiet if normalized to 1.0 (as there is generally @@ -3037,7 +3037,7 @@ static const opus_int16 OP_STEREO_DOWNMIX_Q14 {3183,5515},{4502,4502} } }; - +#endif int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){ return op_read_native(_of,_pcm,_buf_size,_li); } @@ -3055,6 +3055,7 @@ static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i]; } else{ +#if 0 for(i=0;i<_nsamples;i++){ opus_int32 l; opus_int32 r; @@ -3070,6 +3071,8 @@ static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz, dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767); dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767); } +#endif + // noop, removed for RAM savings } } return _nsamples; From 197b7fe7940ec067be8e25b38adebe41e0038fd4 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 12 Aug 2020 16:59:03 -0700 Subject: [PATCH 018/150] Fix seek behavior in Opus, STDIO (#296) --- src/AudioFileSourceSTDIO.cpp | 2 +- src/AudioGeneratorOpus.cpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/AudioFileSourceSTDIO.cpp b/src/AudioFileSourceSTDIO.cpp index 75d0cd12..cd93ca93 100644 --- a/src/AudioFileSourceSTDIO.cpp +++ b/src/AudioFileSourceSTDIO.cpp @@ -69,7 +69,7 @@ uint32_t AudioFileSourceSTDIO::read(void *data, uint32_t len) bool AudioFileSourceSTDIO::seek(int32_t pos, int dir) { - return fseek(f, pos, dir); + return fseek(f, pos, dir) == 0; } bool AudioFileSourceSTDIO::close() diff --git a/src/AudioGeneratorOpus.cpp b/src/AudioGeneratorOpus.cpp index c8b80e89..8ce2e420 100644 --- a/src/AudioGeneratorOpus.cpp +++ b/src/AudioGeneratorOpus.cpp @@ -84,7 +84,7 @@ bool AudioGeneratorOpus::loop() if (ret == OP_HOLE) { // fprintf(stderr,"\nHole detected! Corrupt file segment?\n"); continue; - } else if (ret < 0) { + } else if (ret <= 0) { running = false; goto done; } @@ -120,7 +120,6 @@ bool AudioGeneratorOpus::isRunning() return running; } - int AudioGeneratorOpus::read_cb(unsigned char *_ptr, int _nbytes) { if (_nbytes == 0) return 0; _nbytes = file->read(_ptr, _nbytes); From cdf71d6bcfba1ad78a487f0b116b39d977ee24c4 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 15 Aug 2020 21:05:12 -0700 Subject: [PATCH 019/150] Fix AAC mono decode (#297) As noted by Marc Madaule (thanks!), the mono AAC decode was not functioning properly. Adjust the output stuff loop to fix. --- src/AudioGeneratorAAC.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/AudioGeneratorAAC.cpp b/src/AudioGeneratorAAC.cpp index 98f72078..c7568676 100644 --- a/src/AudioGeneratorAAC.cpp +++ b/src/AudioGeneratorAAC.cpp @@ -144,8 +144,13 @@ bool AudioGeneratorAAC::loop() // If we've got data, try and pump it out... while (validSamples) { - lastSample[0] = outSample[curSample*2]; - lastSample[1] = outSample[curSample*2 + 1]; + if (lastChannels == 1) { + lastSample[0] = outSample[curSample]; + lastSample[1] = outSample[curSample]; + } else { + lastSample[0] = outSample[curSample*2]; + lastSample[1] = outSample[curSample*2 + 1]; + } if (!output->ConsumeSample(lastSample)) goto done; // Can't send, but no error detected validSamples--; curSample++; From cd42e28ca5ac09f5b6267ea2eb2b665c90cdb6b1 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 16 Aug 2020 11:59:47 -0700 Subject: [PATCH 020/150] Release 1.5.1 (#298) Bugfixes to AAC and Opus codec addition --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 3cdf7a46..9aa7c913 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.5.0", + "version": "1.5.1", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { "SPI": "1.0" diff --git a/library.properties b/library.properties index 0eb36bee..baf9c748 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.5.0 +version=1.5.1 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines. From 96d036087b265b21662fc86672c7b1378b111432 Mon Sep 17 00:00:00 2001 From: Gianni Ceccarelli Date: Fri, 28 Aug 2020 20:51:12 +0100 Subject: [PATCH 021/150] Fix memory loading (#300) --- src/libtinysoundfont/tsf.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index e1a43221..4ac232d1 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -486,16 +486,17 @@ struct tsf_stream_memory { const char* buffer; unsigned int total, pos; }; static int tsf_stream_memory_read(struct tsf_stream_memory* m, void* ptr, unsigned int size) { if (size > m->total - m->pos) size = m->total - m->pos; TSF_MEMCPY(ptr, m->buffer+m->pos, size); m->pos += size; return size; } static int tsf_stream_memory_tell(struct tsf_stream_memory* m) { return m->pos; } static int tsf_stream_memory_size(struct tsf_stream_memory* m) { return m->total; } -static int tsf_stream_memory_skip(struct tsf_stream_memory* m, unsigned int count) { if (m->pos + count > m->total) return 0; m->pos += count; return 1; } +static int tsf_stream_memory_skip(struct tsf_stream_memory* m, unsigned int count) { if (m->pos + count > m->total) count = m->total - m->pos; m->pos += count; return 1; } static int tsf_stream_memory_seek(struct tsf_stream_memory* m, unsigned int pos) { if (pos > m->total) return 0; else m->pos = pos; return 1; } -static int tsf_stream_memory_close(struct tsf_stream_memory* m) { (void)m; return 1; } +static int tsf_stream_memory_close(struct tsf_stream_memory* m) { TSF_FREE(m); return 1; } TSFDEF tsf* tsf_load_memory(const void* buffer, int size) { struct tsf_stream stream = { TSF_NULL, (int(*)(void*,void*,unsigned int))&tsf_stream_memory_read, (int(*)(void*))&tsf_stream_memory_tell, (int(*)(void*,unsigned int))&tsf_stream_memory_skip, (int(*)(void*,unsigned int))&tsf_stream_memory_seek, (int(*)(void*))&tsf_stream_memory_close, (int(*)(void*))&tsf_stream_memory_size }; - struct tsf_stream_memory f = { 0, 0, 0 }; - f.buffer = (const char*)buffer; - f.total = size; - stream.data = &f; + struct tsf_stream_memory* f = (struct tsf_stream_memory*)TSF_MALLOC(sizeof(struct tsf_stream_memory)); + f->pos = 0; + f->buffer = (const char*)buffer; + f->total = size; + stream.data = f; return tsf_load(&stream); } From 1c51669729ba7c0047d37047a1e4fba7b1dfe742 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Mon, 31 Aug 2020 00:07:11 +0200 Subject: [PATCH 022/150] test/run on host, output to null device (#299) * test/run on host to null device * compilation fix --- examples/StreamOnHost/StreamOnHost.ino | 108 +++++++++++++++++++++++++ examples/StreamOnHost/onHost | 50 ++++++++++++ src/AudioGeneratorMP3.cpp | 2 +- 3 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 examples/StreamOnHost/StreamOnHost.ino create mode 100755 examples/StreamOnHost/onHost diff --git a/examples/StreamOnHost/StreamOnHost.ino b/examples/StreamOnHost/StreamOnHost.ino new file mode 100644 index 00000000..4f79777d --- /dev/null +++ b/examples/StreamOnHost/StreamOnHost.ino @@ -0,0 +1,108 @@ +#include + +#ifdef ESP32 + #include +#else + #include +#endif +#include "AudioFileSourceICYStream.h" +#include "AudioFileSourceBuffer.h" +#include "AudioGeneratorMP3.h" +#include "AudioOutputNull.h" + +// To run, set your ESP8266 build to 160MHz, update the SSID info, and upload. + +// Enter your WiFi setup here: +#ifndef STASSID +#define STASSID "" +#define STAPSK "" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +// Randomly picked URL +const char *URL="http://icecast.radiofrance.fr/franceinter-lofi.mp3"; +//const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; + +AudioGeneratorMP3 *mp3; +AudioFileSourceICYStream *file; +AudioFileSourceBuffer *buff; +AudioOutputNull *out; + +// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc. +void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string) +{ + const char *ptr = reinterpret_cast(cbData); + (void) isUnicode; // Punt this ball for now + // Note that the type and string may be in PROGMEM, so copy them to RAM for printf + char s1[32], s2[64]; + strncpy_P(s1, type, sizeof(s1)); + s1[sizeof(s1)-1]=0; + strncpy_P(s2, string, sizeof(s2)); + s2[sizeof(s2)-1]=0; + Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2); + Serial.flush(); +} + +// Called when there's a warning or error (like a buffer underflow or decode hiccup) +void StatusCallback(void *cbData, int code, const char *string) +{ + const char *ptr = reinterpret_cast(cbData); + // Note that the string may be in PROGMEM, so copy it to RAM for printf + char s1[64]; + strncpy_P(s1, string, sizeof(s1)); + s1[sizeof(s1)-1]=0; + Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1); + Serial.flush(); +} + + +void setup() +{ + Serial.begin(115200); + delay(1000); + Serial.println("Connecting to WiFi"); + + WiFi.disconnect(); + WiFi.softAPdisconnect(true); + WiFi.mode(WIFI_STA); + + WiFi.begin(ssid, password); + + // Try forever + while (WiFi.status() != WL_CONNECTED) { + Serial.println("...Connecting to WiFi"); + delay(1000); + } + Serial.println("Connected"); + + audioLogger = &Serial; + file = new AudioFileSourceICYStream(URL); + file->RegisterMetadataCB(MDCallback, (void*)"ICY"); + buff = new AudioFileSourceBuffer(file, 4096); + buff->RegisterStatusCB(StatusCallback, (void*)"buffer"); + out = new AudioOutputNull(); + mp3 = new AudioGeneratorMP3(); + mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); + mp3->begin(buff, out); +} + + +void loop() +{ + static int lastms = 0; + + if (mp3->isRunning()) { + if (millis()-lastms > 1000) { + lastms = millis(); + Serial.printf("Running for %d ms...\n", lastms); + Serial.flush(); + } + if (!mp3->loop()) mp3->stop(); + } else { + Serial.printf("MP3 done\n"); + delay(1000); + } +} + diff --git a/examples/StreamOnHost/onHost b/examples/StreamOnHost/onHost new file mode 100755 index 00000000..5220cb6a --- /dev/null +++ b/examples/StreamOnHost/onHost @@ -0,0 +1,50 @@ +#!/bin/bash + +ino=${PWD##*/} + +if [ ! -d "${ESP8266ARDUINO}/tests/host" ]; then + echo "\${ESP8266ARDUINO} should point to ESP8266 Arduino core directory" + exit 1 +fi + +THISLIB=$(pwd)/../.. +MAD=$(ls ${THISLIB}/src/libmad/*.c) + +cd ${ESP8266ARDUINO}/tests/host + +if [ "$1" = "clean" ]; then + make clean + cd ${THISLIB} + rm -f src/*.o src/libmad/*.o + exit 0 +fi + +if [ "$1" = "-h" ]; then + echo "usage:" + echo " $0" + echo " $0 clean" + echo " FORCE32=0 $0 (run with valgrind)" + echo " FORCE32=1 $0 (run in 32 bits)" + echo "variable ESP8266ARDUINO must point to esp8266 Arduino core directory" + exit 0 +fi + +[ -z "${FORCE32}" ] && FORCE32=0 + +if [ "${FORCE32}" = 0 ]; then + run=valgrind +else + run= +fi + +eval make FORCE32=${FORCE32} V=1 -j \ + USERCSOURCES=\"${MAD}\" \ + USERCXXSOURCES=\"${THISLIB}/src/AudioFileSourceBuffer.cpp ${THISLIB}/src/AudioLogger.cpp ${THISLIB}/src/AudioGeneratorMP3.cpp ${THISLIB}/src/AudioFileSourceICYStream.cpp ${THISLIB}/src/AudioFileSourceHTTPStream.cpp\" \ + USERCFLAGS=\"-I${THISLIB}/src/\" \ + ${THISLIB}/examples/${ino}/${ino} + +set -x + +$run ./bin/${ino}/${ino} "$@" +stty sane + diff --git a/src/AudioGeneratorMP3.cpp b/src/AudioGeneratorMP3.cpp index 7c09289c..44e3f6ff 100644 --- a/src/AudioGeneratorMP3.cpp +++ b/src/AudioGeneratorMP3.cpp @@ -302,7 +302,7 @@ extern "C" { { return 8192; } -#elif defined(ESP8266) +#elif defined(ESP8266) && !defined(CORE_MOCK) #include extern cont_t g_cont; From 93a540da9b43936cb85eeee25e3e6a5b2bedcf46 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 3 Sep 2020 08:37:15 -0700 Subject: [PATCH 023/150] Add FLAC host test (#302) --- src/libflac/bitreader.c | 6 ++++++ src/libflac/crc.c | 4 +++- src/libflac/stream_decoder.c | 3 +++ tests/host/Makefile | 16 ++++++++++++++-- tests/host/flac.cpp | 24 ++++++++++++++++++++++++ tests/host/gs-16b-2c-44100hz.flac | Bin 0 -> 1336528 bytes 6 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/host/flac.cpp create mode 100644 tests/host/gs-16b-2c-44100hz.flac diff --git a/src/libflac/bitreader.c b/src/libflac/bitreader.c index a64c1ce5..b2a751d4 100644 --- a/src/libflac/bitreader.c +++ b/src/libflac/bitreader.c @@ -121,6 +121,8 @@ struct FLAC__BitReader { void *client_data; }; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" static inline void crc16_update_word_(FLAC__BitReader *br, brword word) { unsigned crc = br->read_crc16; @@ -149,6 +151,7 @@ static inline void crc16_update_word_(FLAC__BitReader *br, brword word) #endif br->crc16_align = 0; } +#pragma GCC diagnostic pop static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br) { @@ -338,6 +341,8 @@ void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed) br->crc16_align = br->consumed_bits; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br) { FLAC__ASSERT(0 != br); @@ -353,6 +358,7 @@ FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br) } return br->read_crc16; } +#pragma GCC diagnostic pop inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br) { diff --git a/src/libflac/crc.c b/src/libflac/crc.c index 1b531e3d..88ef8cfb 100644 --- a/src/libflac/crc.c +++ b/src/libflac/crc.c @@ -136,7 +136,8 @@ FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len) return crc; } - +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" unsigned FLAC__crc16(const FLAC__byte *data, unsigned len) { unsigned crc = 0; @@ -146,3 +147,4 @@ unsigned FLAC__crc16(const FLAC__byte *data, unsigned len) return crc; } +#pragma GCC diagnostic pop diff --git a/src/libflac/stream_decoder.c b/src/libflac/stream_decoder.c index eabcf092..ec172fe8 100644 --- a/src/libflac/stream_decoder.c +++ b/src/libflac/stream_decoder.c @@ -2021,6 +2021,8 @@ FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) return true; } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode) { uint32_t channel; @@ -2167,6 +2169,7 @@ FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FL decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; return true; } +#pragma GCC diagnostic pop FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) { diff --git a/tests/host/Makefile b/tests/host/Makefile index 9a219465..835724fa 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -73,12 +73,17 @@ libopus=../../src/libopus/opus_decoder.c ../../src/libopus/opus_projection_decod opusfile=../../src/opusfile/opusfile.c ../../src/opusfile/stream.c ../../src/opusfile/internal.c ../../src/opusfile/info.c +libflac=../../src/libflac/md5.c ../../src/libflac/window.c ../../src/libflac/memory.c ../../src/libflac/cpu.c \ +../../src/libflac/fixed.c ../../src/libflac/format.c ../../src/libflac/lpc.c ../../src/libflac/crc.c \ +../../src/libflac/bitreader.c ../../src/libflac/bitmath.c ../../src/libflac/stream_decoder.c ../../src/libflac/float.c + + CCOPTS=-g -Wunused-parameter -Wall -m32 -include Arduino.h CPPOPTS=-g -Wunused-parameter -Wall -std=c++11 -m32 -include Arduino.h .phony: all -all: mp3 aac wav midi opus +all: mp3 aac wav midi opus flac mp3: FORCE rm -f *.o @@ -94,6 +99,13 @@ aac: FORCE rm -f *.o echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./aac +flac: FORCE + rm -f *.o + gcc $(CCOPTS) -DUSE_DEFAULT_STDLIB -c $(libflac) -I ../../src/ -I ../../src/libflac -I. + g++ $(CPPOPTS) -o flac flac.cpp Serial.cpp *.o ../../src/AudioFileSourceSTDIO.cpp ../../src/AudioOutputSTDIO.cpp ../../src/AudioFileSourceID3.cpp ../../src/AudioGeneratorFLAC.cpp ../../src/AudioLogger.cpp -I ../../src/ -I. + rm -f *.o + echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./flac + wav: FORCE rm -f *.o g++ $(CPPOPTS) -o wav wav.cpp Serial.cpp ../../src/AudioFileSourceSTDIO.cpp ../../src/AudioOutputSTDIO.cpp ../../src/AudioGeneratorWAV.cpp ../../src/AudioLogger.cpp -I ../../src/ -I. @@ -116,6 +128,6 @@ opus: FORCE echo valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all ./opus clean: - rm -f mp3 aac wav midi opus *.o + rm -f mp3 aac wav midi opus flac *.o FORCE: diff --git a/tests/host/flac.cpp b/tests/host/flac.cpp new file mode 100644 index 00000000..2d7110da --- /dev/null +++ b/tests/host/flac.cpp @@ -0,0 +1,24 @@ +#include +#include "AudioFileSourceSTDIO.h" +#include "AudioOutputSTDIO.h" +#include "AudioGeneratorFLAC.h" + +#define AAC "gs-16b-2c-44100hz.flac" + +int main(int argc, char **argv) +{ + (void) argc; + (void) argv; + AudioFileSourceSTDIO *in = new AudioFileSourceSTDIO(AAC); + AudioOutputSTDIO *out = new AudioOutputSTDIO(); + out->SetFilename("out.flac.wav"); + AudioGeneratorFLAC *flac = new AudioGeneratorFLAC(); + + flac->begin(in, out); + while (flac->loop()) { /*noop*/ } + flac->stop(); + + delete flac; + delete out; + delete in; +} diff --git a/tests/host/gs-16b-2c-44100hz.flac b/tests/host/gs-16b-2c-44100hz.flac new file mode 100644 index 0000000000000000000000000000000000000000..1771321465b8a38b39609dc1ba48551d9cb20516 GIT binary patch literal 1336528 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�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%0DqTO3n%=1J5R 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

    rsn<`gq^TMy zv=GXnPl;@l+U*^75E|Jfsa>$|l+Gg_E5BX8zkDW~^USYMc?wlZtp+71Wmxb3h}Cxo z>aXqDI?J~-d?njflN$!f?Y?PdrkEl#>8!W00e83JuXcAY8^+L4l47uKZ}XLvkurTu zu-|64W?F&hrZFMKGN~>THltadC5KwFNRBAM zI4;W>N7yvb=r>A2u&pJCF-=;O8VtglWSjTY($;^n+Lgu)1ue}+1`>qTQ@Ga-5wVrM zR_qb_LUD!;`kMR}5D<^>F2JctqN_?h4L4RUa#&eP=lr#u1@_6!>2>OZEZXwcZ=>K@ zX^&e&4>#F`4|?ZIPTsTV#~1)cI>{lrA{ ze?qBp?<(X*brd#^zKR836ol!avt5P9a+|EZy3=Ut5ZS~xh8V{8yJcVdD#sJE8n*5F zK4V!a-Y?xfG+$;j1Px9Y=TCaLCjpn%x2C@mD5x#~xF8G7jV$e3)V8qeVYkLqeon(F zZ&50#?q!0{s%7Bb)}kb$W_iETUeTY|9_PATrJvy%KH{uCy`mbaV7dG8S)l>jbd=_o zVJHTtl>PXxVSqZz2KG(bA1|cF9c(GiL-;B?M|HiD^nF>T-OVED7vZ~OOM1t)(`$Kx zy+u!bqrQIH%VIqZ25qnxK#5#6Eexzf1rA7GKqhmwNh&}Z1L(a8$2= zC25WgGt!ri4!cJM+8}2@sLKH&-O|CsiMlZqnO;{syvUCF=fY`Y_D(MavP%7iL5S8` z;)Z4C3Z1({6QbP4&k7v$%%yYAX~AODzC63tc-0Du4tHm=cvoW^tcJITuq+u~Cwc8Z zPv!Wah_^aJ`01h*T=>$R9+BYt2AyVl=Hq{xkb#w0S@Q=CtHTSvpI{W0@o+D`L#D>! zJv{^L7A4ylBNZzyeX-7pI$VsHnZ)o_Jj!wOR~8$g_PVMzRl9!vPJ4>S$$yA?45^e_ zqC^)-FhQp8J?pVG_fSG}E!dO0>-zkt@2KpL@cTDeG=@RJKx-cRT;&R)ds8$ojj3b(N_ainT>c>q+nNfSFo zM7KF!PDS#Uf<6D!oPyM)F&XJCtLQ7M$(rdN#Q7TIk#c^XV14T#ii-_a39Bat-0HwF zv%UeV2B3XlR6L=II|I^PFU@bV5at7@R_>#$3$GOnD3Fo3DcOhy&^03~A_>HCsjA16 z{JGraE_Ny`>MA8K0dKx>vrzTnevag_9kmKK@&^O}UmoeSmic-f6T8GnUBrq}kT==Q zt7L&T*})k#Hv>@X0u&Kv@)K;#Dk(1?ZENMg5fRgu8aFZaRGl6D&GusHrZX(>K^g8^ zIP-E3X%^YFSs+|D3rs<7WgrT(y>f73mwWjV?$Xfj`0=|Q=MwQgB*BWpR}X4K3qptb z&^iY8`*y1sehf+8f3l4VsBnc8%oL^%C+p3wcU}vhwcKQd8SnGUx;4&=0H3NV0)$cj z2}(`boN3RntQkd?5~%q}v4~bBvftOG%bZFJ+XQF#Jh4+1s#lh3%bLK4VL2lK8uFn| z0rfTYBd(^8NVbDHuV;=>sFY|S3nyG~kib3azV;p0cotnej`@wDz<+__k{n;qRbwmh zvn)XViJI;X*+va8>fhlZ!z2L&8PhiOsRFP)qQj|C-4@98mDHkbZxB&DH~?Z$5yAN>su8{P%ZA*iwS~kT=bG1Njy5RXPBt1h5`X23=@H3 zG|KJ}t3-X`dN3p|2R1+2vea#?q5M~m$xLf_@+ZW~3BZ5%<6TO86@C~y{R@8P_UXjfKhefL>xWuP;R88p(YINeTCgB z44Ws(BIDnwNzh)+(j2Nv;!r3|_gelDytNWlma)4Mms z0t_ZsQnv!}46?2aS%hto!v(EFgDh?zBp|`5YjdPt6p|DJ1iGAYPJ|*s5OFWx6audT zM}>P3Fv561GeIG1$|pnX0B5eIAZ#Ux1f^U$vG9O|mnC~Lt3C3#BgXn?>0$qAI>it7 z`1E|{^V2eQQb#!jB+UDAJcIzVkaaH7p}vMmpx7OeGjQLLg`q^M*U4Ox9dm^@2k@+q z%l}OAmnlQ9MQ_za>KD*qcO*%2qYOIoun2sdCD`%F(`K?ubi|V`O|ZCq+p#1gVgd-F z&^0yU_kc}A^wBC+$H}$sY_!3c3^XxALQr4jX3*!V>h;dG_cg^~3L8f-_aqELKov8_ zDv;fgTx=L8X(-}*Nx1ZZBv zT0liqv)0Sjp$jw&BgLat=IMFqf}As!*?hS>>A2gX?@)s=geeGbavjwjB7m-|3z$aS zGG?!aj45SK0;E1D}>Y}12pKjh)Xg-Z{~EI&&F+k zPHpKV!V|gHBs!!@!RTjmQ8sLa6WwDdF6oh=T>~kD+PA@R=&y#)5G|Uv`8Qf;8B;iph*N3LQC7z6eID)K=M0E0L@6vs+5e2p4q@n#OK2BLI{4& zGsr50^&d~UG-_+UXP+nYMeWxd`>oqWjvxQWUTb|)6+Oun^56JWWJQ{uj)oChH}-{rmVUJZ<5Oirt2 zfvZgeF2M{^KMX1wV6F64625^I8lLN_FGZ=%Km|H;@03E~bAJL?w+Fg#IxaxLDKoKP zKhWbyq$Q<7;9Uix83T#-({O^$HqY4PDWldilZ8<4R!1qmrK#m-cdZ?>um}gW3@;Pp zxqyC}Jo)CoMqP$ubR~h>K;jA!SSyr-R4AKl$5E@hKS;1@tsYZg51lMrIxm5uN1Tta zv}77Fenv)Sa(>c7$R0TW-JX`pT#OPFZ-lPSjt5iHTX;Q%29=9*UKZiDQ4B@irXWqx ztvX{XC4mgsGs=MeM*qTvO4p$~?#tI}#8| z@vSTi7}Ce|sBDIIBm+v8m(JNvx*64I$7T$&tB)w z3W9z>86rX_ua!RqiK8IY4BK&-6nEo-c%y+2}>yd#Ruh{e?kWMF73 zVAj!*>dVSAeA^YtT6!Y5!E7WG4!z8gOX7u6lrp~dWbKu;=a6(#xS0FO(m`Wgm8ec| zk+M92H`0sPL&f=-j5x-Onq2!NNK|F#;cf3EuTGk#gJCxfnK>cA~M%72S zuu0Qa*6G_D(ri5$y7*ls^E22GC<25+ViTKY2a@Kdmg541a&ssxIY`*1m(#r6Vc&8k0-Q z9q5%igeaqRY@330NJvP#Gqgx@!bfnlD|)C}{IrG5N@hUmwziV%eoMb-W8TbECNoYH!<`CiyjgGC0ED{a z(ZaUy9#?hsd<}8WYsm9Mk$%FvB^7%Fa9d7fu=j})E3pyp42dN%?eTjsVJ)OAx*pmyGVYSyhkPfa;?wFR$%Z8H%I7$1vK;zS(N zW=<-oyd|4OOPW%cEsl!*`($EmrQM3Jms2c_Vq@`33qc2ytmHQ2cg!yd2j26whMg;A zYpipTL?o`!*Py>BShNrjpn#XN%frRr6jKX0?P(_Lgo-*r!5^p zt2D!;o?KrP+|-E+fXAC!_$PbSNadMNqmNODj7iil$UL`#q-;*d}IOsU%1dlRD~c#Dw!7C28)%KbGL65~m>yG^slZ z5*SvDSVcsU6|Pg;+?g)$NgSqBU;E^lU!f7~0(QjTk@yk-nGLp6T1B^`$BR=Nq7hiA z0{-#*CAOu(d5o$}RKI{6zFmM?ELZR4sSVe<1KUDcjTlqi*buK_b>YQz;8G^?3A z+2Etdd8?B^I%SChHK{^38xIA_QWNYfXl5&ZM#BTfAGiHfB732HiZpS9dL8iXulB>v zqEMw;a(Xmafe|QOcc0dt%LvGLPoPSfkz9#hiXnB25J9sr6MS3Q4C0?EE$uT$NyHsd z2x4jcULW(#F^B>r^FhTCE>>u|8`9djh{D31xYUCHW03?M%`v+<$(t`LEdh#TgaJRg z9xVc0y1=Bfp-v~4WcYLxOkqw$4pTTu1p=jmn#xmdrzpq;V1c;hEJb!kw%qU%=JTji z2MM5h0%+M*6(O~?#vc+6CadS_m7JiaEeRm(AF?Lmll7L}hKM6?d1gpXdGcZ>r6CZf z@=T6%FRu}4Fr}8JJu6B>KP-|M{NKowql3VV$4SZ-i;bE#@8|ghD3B0OrwdfLN8H7l zj+(>bqIy0TVsChP^jz)#al3^Cv0(~IN9#=7rgb)_5L}`oZQjw6Ym&KEMek!65(L1@ zFpD9hZ3w^?yPPAQigvFHLMwhpEVcnyx8=}IaXjxI0<4<4!E$g20g@0zSt&PcxxJ?o z$W4lMC)Jf!)R31{B+50e4Usn)278RV2`G%=lM;s#A*gfpi54W@Mj?e~ooWdy{l^)! z;!TtKe`L{msj#t;HVGj}nc}~Rq!yz^J!)`Zu9X|F%pwSX`C5iA$9jmk)D%D3QOqpFbe5J9 zUO~op5_%^RqfFO)O|hhUyd0t6G;BL|QCtymu^6nHl~5FT+UXZ)y=G?2d)KsRlg?lH z=(jQ|(MWSdkWm8)Nl@?1Mv!Bbr~H`{Q6Z_rXI0jZ2)IN<@%&}pYc$EK9`{FpxRVrN zR%(jy))J=om=XtOE#4ON0T!^k)v^}BR?8g~1c~1aGS)L?jYkqXf&;_(l~>H6s_ieo zk5Sds|0FefMHR8iQd7G*Czz3!{J+#8wkLK`DoxhEUzMmU?T&djU!qFE2D3YX2%jc` z9EKaEalzr3_}?g^^|7x=n$C8oHF?M21f=h0+>fx z2FZUDOy01A4a&n<6kMIMHY&^>I2i|wZi3xVHk2-8Tq=fV_5sfFYt=(LV1nBqOgeOs$g=ZtSx?A7=REzS>bG8R!8o zYp&*ufbh#7bYjrb)g%<9i96E&)4ANfRxtHDo1;vfn)bccV?k*#TZ8Z&zXDFpdb| z)aIBqOuNNrwiDfeQVG`WxTUtb1*|P|^{2BCy>~4Zrt92@WR&(9LdDPA3Ks73cY$YE zxVNDYA&sN(Fp|wcSQSr^Ao0}D<)y8j?8t23ltF1@QO1paK9Y15Pwtg8*96Jovld1X zZh01oVnKM1Zld{QvBTdistOtsTg#d>Ei#c)W1jID`4 ziazJV?7fmkXM|>}yF-NK7DEl<5(`(5k0{Wk=)*-P$9lnxXe|nN@MeS{g&jb36M|er z2$p#sS|G#@V}n)huuRebf(U_%Uk&3(>O;}Il+3i^;%MwfX}YQ$1KoZBmB|x>wMHwFMcR`(B!Ne(Nz>-%Yyng?r5J$g6 zgCVRe_7Baf>KQ)E7g+(KX{UQJ?ioyx_MyAd(3Aqv{@zVv(JM{T*{UB?OkAx1+9U)a z$yBKW_GIxi&CkbB#D&L1G`nP`q*7Rly8gPGgX`iQvEPJ6n4(xl@Uv_5=v)l>T(7~F zV#Vx1$fbM~1#ZgA>P1rbIu6(`xz)yh z3$dGeI3F7x6ou-9>dvpPUGavTcWD06zgHD5h4hjc_^>5IMHh=@$d;M{+?z_kOIwlx zNy7s2O4Z;axF_aNH7x;5*0|(i(pLb&KiTorQ%r#%W!MUTpRs}zQ_Agg#E^Arsj#PJ z!GxhZI7eY;q%6y1@^jnjAfB*gN0{UpstSNnrxh4nP7v3)C!PypKeT8hi0G0=aPb zt~cQ!Dk{@3b3)&-pE1-| zRw_=?vnIH9%`vdBy!lQjbpDXCoi*e*B|!{CPaB;p-+nD3w_0W!NMH!FDnTCpw*^_S&JPu_p)Qc39`l$0G8YAKw zQ7}z)%O_n%bVZ&QF6c&DSLa&A!ZSic+6m&Na#} zSnLqCMYuGHsY)QzJ8VqiD$4yljbZ~|yv(=)u#SmVfr&wcx|l_=UIa}<_qJm35)Aq# zI6@&IQFQW2E-mK7HaNCXzSE@>46ufU5$wC!FF&nuGiZa=CBd^dAFo=9&rYaYO#Js1 zW`b{O^m+c|sy&9auc@PB54jV_hUWLBSGz<;R?1ha+qzlnT2gMf=3ed(P$m+^`DwA& z>&Y@!X0qwnc#g7!yBKtqu+5zJPJEEl!$--@$-L`wBC)E8DnIAaR+kcNn8v8Z&njd^ZLj;gKBi7x@Br$eY1 z$46YNl0ytBj8`Hh*RO4?65^PmtjDDOmtw*tz2^BkXG*BR^-f%!MWVgkW_3=fle=Uq zpwHl3;&8fnOU*f$^VP~T;@y*d1n)6r7|wr|b3l~1qgNq$K|aNZ2NVgbu15k>A%D*5 z7Z72j+t?x}w7EtEQm#zSUFB(AgR*KJW)=?{u&6)H(M&!-+l&)zzPbAkWQG#^M) zSjG0lS8bzr5?t>0q-g?7z6oD18Pi_<+*rVMNB(rNOWK(S7iIR>^o+~c|2;K5;%ibP zoV1B2|4l?}P9b}>d6?`i7)R*K?C!~eYRgA5%XhkytXr0FJW(0gH|TJxcIUk)$2UJezaKolqEYO6Rzx-;AGLbcnZN3+cv6xER-S)e&hVGH*v_KE%gjBlVY;4Uc zxJOg(w`=Hc%)-I)`qHePy1j{~K6CYXoX~Gh3wG9>{`sDUdW#gOIeL#ROA>;e3sF$9 zRMdF%Jj~fiQV<{kI5XAjNc-@%fZkpS$$|~r!JazIO%g(nepe8;_~S%}KuZGAQzJzO z_eSwIq4Wx0Dg=?1kDiU;2(@>zV%0x2L2jITFb#^iG2XeYm~EV<&CT2#l!{1ZWL{KM zP*rXxkaloV+X<9ilUb00gt!Ky`_3W+`CSNz1sV`YLQkNMb(N6AwjDXl64-y@86uyG zNj^jJ8+|Yx@yQ4YrO<*#G!ua1z$6>R<{46gGJZiGz-3G|GXZaynNb|Fca$AM++IxG zp!b|w@NU8LkeYblN{L8*tcbIO3Bl7&D45iM)*T9}y1^p8(i#c?z7jmO!SX>k5@u$^ z)I4&f=WCOFqmfgp>k9PfUEBa+he>L`)RdGIOhREID@_sI?>CZtjE}>S;-G@hZA?tL z&Uj9K34&;@u>ikuRuuZOJs{wA^J979l;p~IT7t)IvM+vBp)sYWZc8I1*P2Xk-VyYs z(Kcp&|CU0+~8n)i&gJvZ+;O>px zs7)?4rMWRhbb{^um`%PC0%SqOX;LHNK&g-zMk_QUB$%)Y*;9~$ws9!23$3t;4x*4; zY7DoKQH&GWSA>^Z7sjfuCx<2DrV{t(kDs3f?Y&u`mYI?&KPE#E{#fNibLOMfe^6D1`su2u%Mt?An*_QLJJm^VQw zqGxb|39D3wR4Ph)lSG)JR6C3>?OQA0YqeOmksD4U3BZ87re!Y@nf56Q%w0r&uzV2STS_6eqPb2nn(KT%N%(7t(2 zG8$jaE<4r#6$;Z?kpmI(wBB&8nza9rS}yT;@d`33jvSR!H@N{SLOxp!(aJxGb5lx~ zC!>!+H1Y`{%g(JZ&IFwrl9MY-E>vd)j;0oJAw^euNLAUOBFNRjq=eE`e9fQktJgHE zvRyjXP@752*82B6 z!Y!8mh4`inwpG0Y%tx1Nerzl?b}RocSpM_l$>EhKkWpzy2wwh-H9OC?7zs3iC}V^t@*+ z$Ik41Nt%T+Ek7DcSe+@NX^0zTXA0ablVfGCK4pJ|H0=&6HY(_F@L|SJ@T&xacm0iE z3K;L1&xnFaZN>5aWKmYLtpaVX_P0jQ*|F1FPpH7x3o~qIx#$miPhzk-9aEOuG+LS?9#xTX-^?R(w5bB%O zr;X^H+XvnxIYK1v+t#t^=u@=Sl{WZlTvWa{jzBQ`vDDWEenA(*`~N1^!-YmQR8Lse z*ryj)KgE$@SeB7Hvs^3lR5;?#hX`}9qA>3WR@_(q%ch9l?22@UTRWSk5jna9>9;bX za7h^a*}IQNS_!&f=8m&K)C*c-Q@fo2rdHYvCM2M=iPC|n zcBOuSE2e&S#l>K9OONLIkf7a>D_hzPCq=_TIYIJQOnl5x;F?C15=C%{|A;BN)EN#R z*}M4yCSCDdVM4^I?r_PgQX@%Oj}hCrSWMEHV^CGYVn+G27^3 zPafY#4sJND_Y$B&)4?-+(ypXDS4 zjOp#0!IF1+Ha97hW}YREkqkgy-xS?4N?QwUb1IRi=GpdEqFK3DHd-6-MK%3MXLUbIxdvkY%d`Tnpuqlxy>9ZHZU3ngzyIY&?_L>!2Qmt!TtO^B0cMXlUFT_AuU{5A`lFrg>k7}0C51QGb_32u}3DIQd&(wZM& zVp=UIUt&+*>M_bZa(|Hs(y&WDO$zAXnmePdQLbU z(PmV##KK>SE46`&B~R>B)B5nVhuFl9Lh=^AkDHyXtWFuu1ksa=clYFlmF%F#u~K^9 zNxi?3f2erEwcU3(TON_9(mg0$C%wg$c94r^jbVoWw2?B9&l60-6>XU7P{}PkYC$w9 z)fXsl>n44KR@@@!5R^eP!Fb%c#z1L>M_f=Fh&-*kO-sDZ9>doR4%f`a97$A;=W|ks ztqC~hUyAA4`rUA`B+dE%k-WCv81bt$XX|w_&VGQo)LILNxD4&Z!5f8yaSUpo_ML?M zvfZqmPUxGq^n@`gz+l*yCcCX}d$d^%vaMCZFs&NK>DAYyZsc~E_3u^E!MaCia3pB{ z!b=qI-KI6(D~GoUv;ScUz}#Hr_+p~ura80H<*wrvyqJ=m=-C4e?`i?@_wo^5tVT&` zvWDpV3TlS+5jUES`#m+^bmd#wGQ8jRolE9P3<&R zYK)gO<5WyJ(MV`H?hs|$%gipA}P0v_odi7{a#k+;=XxX zQ_nVNoud>$hM^s|4(poQqv;a7RX-zC<<2M6*?9DNvUx;XDMZf=4O5W;C){pe!R3kN zZ_Wfy5bOr}qL9%FniDkaT$6`(b15L+QlXQ@<Lv*s!T5PB8Hpr^Eqo7#P0u5#LSre|g z?49YM5?#x{{Ixq@WhXTRp{h^#3?!4UWJ}L3^XqbXRM}xhU0|gvqvg zXe4H(n6ebllpLeuwD`G3nvH~^JorAPY-~=lkdb{CX2wcu6xw4dn{}Z%E&N~mFE%Ol z$6OQc#{408CcHWj|M*!LA2v=0$O+L4a|_oCQw!M)(F`T#Cv%qi?#3p|59^m@K|Iz6 z8!-^DwPxGW)x#C_dlVygVu7wKF08;+SL8@yP~SMoqugP)M+mLZ+$HFeNbHB8iGP!> zB_HmBa){Yi3l}|mJWGnXx;nA3!yOTBLQYz(l+41y+Yxe~iLL#&hFD%_tZvm`?Gt-<&R(@?$VUikZM;e4Dy6@VEIoB2#@NPfz*7q9B6NozIj_pYP1yPwnE zNN4F==Dl3glmn2@q3tqO?aAsXKNHQNRoYHc!EVHf^N}*@myJYpmveNec}q6^qDnt9 zqANF*nGj1ZKM*TPwoGCpt~ynMg zvC?>SHqYe4;jGuV(Lm$*kqBVaG9e9d3R*doue_Mg$V4}rviP#31Y`aok&=E71Q41h zO5XoYq>$6U?U+$xfRF#I1$}fb-P6CwNA%@{(a0xfK z*-#huYG6TIeoOXpGGHTBxs}UN2_UXtrbOPW-ron#yem2MO>_{!rXwXC08C(3z*EGAguFO zz=WZ{(tkDJ-w;lOkL?8OlMpG6Re*im7BA3x~Q@7gko zMyWH!Vf@_s$_9}?&OyG4m5p*j^Vgp*S&rLaOgExLdQ`bf@0p3((AytzLhNBElLtZArt&RM%HC)~*vl1?CnS5Vgq+U!h49FadO+uTd-7%u4| z8J-;`{U(y{#?ckdq+YW>oL@tKWC;pNOb;PrqzzTv3jwBUU=!rr3<^#i5fZfQJ|F&WgOp=0IVlni^ zPvD2eVHC2)!-QR_L*Ji?6|TnQs7j>}|JVmcdwU{kXi!mX8%f98CsAzcD2cjg4aJ*a zSF@v+GISLR5J)rxuuvVu(zO@go@A@CgeI(-*BBSlPOgM6lE2CMU%#w=yq~tG1XcQ> zXBU!Q-Pq`KgninF&s6KDy#z*I$npc=Ni{6h-t>Gt{UNBl{XK#sgZ0`IjT%79k{0;rA^X2X?<+Y566oB%amC zfa)niOglm>geZe7g*QT>k1oWLC(P}7Ws+uHP;_(x07*t!ZuANE3r(e}GZ1>K?8_n` z##`4R?%bM%!FwEn#?`b$c7I|`)jx`c&`Dl+BNmA*1Wt5`Z0Lyz>{$)@Yx!#~@b&df zu)F??l1wgNg8f(&8?u5yMn+f}l_4UDSqa+}QS!eSdomr8EL66E9K*$2Nn#FVBKaXu z_fomEYN`(82>-3aaZ9_p@0!`G#{zz7X(8_r%usX1lzhR z$N39A-?ew-)b*?Aug7$gu7cGS6hq8o2t*W)B}^xAxKb+csa%F~UhBtKRngPi<4|a^ z2zz+;@Wuau4>s(X@lH59o|H3M16 z0lU&G=9l)U+=;D^Jl9vKE^_F61d1?u9lsLJLg1nA;EU|y4bxOoG*L(W&A$D$_wzSQ z=1iSSqLcHyXA*seA7U(yBQra(YV^#FQ|D{!>0__G;fJ{L=wwLOmBqtpUFOw>!eYG$u_ra`-8p zz>&j9XY5gzCn!2uBM^>1EbMM}(W_%7f4_HeJ`4;n!4x+klZzTH`(&0!1o0G=uayhv z^b~y{njxei^H@~|UK=AkrZi|qM5DA}{rZL-C05HH_?^N35yV-U{*=+Dd}GWh@o9_N z<*4Hb!401n<;G0e(yu_N-G4^E7DC+Ak!t*(%Mr$62h1QEs(JV&=z>oZ(5qqtzCY)G zJPNW#2GWGW(yyMTfjLqW#+wBj0q)B_5=O64b&5f-Sd*5PS$lE$5D#0-V|#5 zjzl@JK zAbv^Ts{68tW6!$kSduyDVLh0bvkE~QRFtHbc+34!aWrab99R=&@Px@lZ+<>K=5+To zO1t{^`mED6(t`Y{j73X0m(&sR{z?c!ay8vv6$Q+Rlq5vonP-0zDde7nBq;{2K&s+2 z@z$5OgymgwMlh-AGq(_SK9uYKMxR^lBYl;y=2p_xbjV zPtA%Zu;69fGdHXk=W2{B!Z(k*hL@Zo2LpFQ95XcQ$uR_N{bvD4Z+Py#Eo*j{7D;HE z(T&pU=|)sq$e1!8qQ-L#aZ|6lPiWO7krT!9Wl=Gx-$4%Usp%EofH$ku0I|R^GC(^SU_1or>?iMi$WLik_$`A-Md$C^qdbnr%F4iXRXf!i%KDLv z^rjZ+@$HA$OHj(-K|-G*m1sB9b(_hxo=I2$k~+|o2ej_>Xk8(z$ha%}nT=&VLMi5Y z+X!*h0aWBm#(!rV)YRLmY6lJ`(uye$g;XOQq{=xH$>F=HShhIwy*yLV)O}loq0+3C zCvh2%KW0M?H0Al`o6ewLE*p9O4Uvyf&6@=DX@WYxP;OO#c~^=bMr;wmx-$5+f0@Y# zrcBf2*{ghn{*}7xKLulBwk5Z%+l4DFD`pFhU787c5+7pcmDtqfSg3YzqPIOq$e)He(_#<)BrTQy$`OtACK!)m*-EY#*5EMbQu9 zf-%GrK0C`%yqY6u=1N}yo!aTGLvcN0gfgVrLxRSCxxY*GoJ|*+`)H}6C-HA1km%V& z5ZPF9mGHN91tl>Is{~fVD@_wuXC)MK{U6(Yo6{m9JA8u@b2<(vvTl3ix)<)(KY|?e zU5+9v84)BsoNd_`$oG~qwk34bqJE5bHiD_XJ%Ka?jU-g(#K=!r2o8+bVrIP?1|xoi zF|2-i-nQGBb8?X`b{7|x8LQ?nBS(#Zkk;?hK8tZiDQM#3cuw862;-1qz?6T#Eio{{ zW*NO%_Yh#Jo)o?FEgBxlG>?`o3jQ)o)ddE#I;To=!&RN%D_+iwLZ0Vt3)st}M-bkW zlAmh-u&fC`jSnh<5dcp>u)h`L##S|EB|S3=K!-}4sv+CT6;f!oyseclqPOJ?>Pj-2 zf{dRJ5A1}rN}5j&RZx@|dX15g1pu|yeAD#Dw8`sp$;nqV<6iu`C~3_dHkIQ-4bK%a z_9EEyjO&%tPRX$(-CWTlJ3V4kl4R-$bD+x~<3@(Gkk!jpYwR?$uuvV6&@t6&`+$Yu zd#&fwCS#p+&u``XFNos)2CSWX_jJd5>Q_jT_bizh1lKRY07zUWW5n|UB@J)84E>e z)C0s|XzC8IU6@R6$&GeNO>K$f;Qw%QQt%ccB)?;6=mJz>`|Fo%ZEamGY|j7fiR z)6#O)M~ZlWc~NVE$AAn>pC%b~?np|>IqXQ;F&Pyz)b6)ssJ5Y2-FX1j7vpfMLl&4( zGda}MxQ8ixp)a;}r2EBXnLhY|i&yMT9j)IY&5{o8Z^!{~b_{a&y(|Codf$d@Ojgm8 z$sZvHEf~{wm{j)VXy1;Srq-$94p-Y2dsw@3xR`=PKxR=5g^BnWhg|)`-JAPMSFD)) zw$!Yr?D349v6oagZ-p_%X3JS?#%Mqb0z^)c(pp3zhqcc)IA)~+U6dc$iNgI0a=DB6 zS<&SD#L;_c)ny447jd6s+=Hg?K2|f;nzkscy1Y0{S2FHCukxf(QxG)jDXk~Hcwt)iP%S)E>n)uRO2gng?P&|gOsLI*gNsxGdtK03Nc=g)pl%Ud6K7$S{Z#3S1U1t_A%aF%Ia(O&)kIgk z`BIkxf4*p%c6TP{i>@uLVqaIG=nYG^F7j4SPq%6i1EeG1`;3?k0f+~50EdEFEr1F@ ziaemJfR&g_@NNuupNisdgv<&cc8nJN(w#rhK+8eqFT*1<0i8u%Mi~fK& zL-9lzn(vI*5&%^Jyc9hg$)BAK(+fE(M-V=arwJ8LYX84ajVC2$$vi3IpyjkIz_6mB zNmJ#j+H(by+r;w@?St*1oET@+Cs4O{$`rlotgjY;t}jQBRUUG9hkH)>z5PA_X@x-T z60`EEu62S6PzwXWl4nGX1$_>YWEtgD!z9s>kTj+Yd&^sCgJFA1G(naLfjAdU>CM0d zBp85~5SEd-7X!Ie-6r)La7#Jw3IO@43E-eM<9-z}2LwEonQJS|W0<2PWZVb4V|+KI z%u8O}n2ncL4}opVH{Iaw|tTC{}-Y!0DsT2i`w`9+K)@&QEE70l^`h}S7Kcv)2{&UExw6NGEtB>e{k zgLqZR(wdiuJUWo5s?FZF0AJYU{s7f6SQL7FH#L%#E#hpeW*WjV5^Db;Mmt zt{kppAisoMwId58XJnABu%M8c%9x797&3t0N;@^;YpS}{G3ga_pFyQ86coW;kNym( zyOVc-R-(T60+CTUiH%L+C*?$!oRgnjy^z$hN7#(#iqa6Ic($(IpGTFfmcA-CR0i$xu@@BegOV}`>* z&tnDNl6G{$7D@XLS(mr(Fv{}j8=53Aaf%zk(chcB<%~~@okaMBH*@T5^5!ebnd_r zTbj&}mF9BTLzJPi?;?*uT2psK!K+%SK7vEfhn5nWfar}3FCysZm|A=-FK&^}i5*7J z^i>;S=D*~HsKMf02@`|ZFl49^mmbg^$NJ>8u#7PZxBfP$$ zDaAPZm>UD?(G%h*QJ0U$Xp7sHate-_-h}?TV6Q52>6=?1ssfdT(x1G82 z;`k8h6tkw4Q>W1)FjDGrvXk_|-!g36oipQ8xyG@?oLD@~4Ry9==8F7nsIdGpRpN-wlD(VJxe)%V{ zR{n-2Y`maV*SGFZ*1YG5A`Op#T#(X zKKA4Y8;bwz(-RLwEIA~1#C{Ug;!xW24SI>=C*~C+m_od%?|$-}sSxYpRRD=YJvM60 zyIPasBX-H|k^Eeu^?77{z>y0R>+PPhdUG>(Z1O9O{_xw6132m~&~KLk9)gp@YhZAy|^ zO?~W?pQ}Nqrg$CNr((r=MKjvV^#6pQzZJppImg>zTuG*+-pJ)mu3UR$OES8(T0hgNOS<@GW;nT`>_nQXaFDiz4ozFs{2+67!4Ba&C?eDn6x0pfc;lUNjC-*OV?N)v1{nvGem&`t;%~;4Enc45j4ELW(&aWA_=1T z`bM&E#@ytPL#hh9B0IDi6-28NG06(USIQh`1m?FV-HdreEaX-wE0u_(g^od|F{?wc zS%DZGfaW9$K9IkTJpSZ+#;?w9c6HSPgJBSHL9X}`*HDBA`Y)(MR+>x&nf7SfEXg}h}& z0;_9m4PHfkDd|8~N-ll<5>L1@bO3Eu(Y9*Ye}=eAC&_p4b@j96pX_A6Za-Ee{ z%Dzhk0E~`B=tE3&K#HY^PW5>vCrYeWTqNGA4S@C!@Fx~G(0Yk>u@qDYrSXQV618~Z zBSgvY;Ocs9MjCo4fkGF8HO9Fz-tY3U7R8lfapz2Jn`WW{EEu7(B2HAn3s%uu2`fuX zHz{l}hk}TQW|L`0esoQ&;*`dBOJTS?0P_$5Kn1G=? z1xR8$F~;1%mr-G3GwZq1BrH4b6E+-f%Ur%Fuck9ZI9y6fa`{X(!?RK+T~ob}pCvvg zJ8-j}e~qieFSaBuU1&~}oc5^lIy~fTgi$yWvo=DF+X6_*(l5uS^yB)U3$aNr?{?e} zt`{=IJ|zgvowry*$=V#!e>i^M5@*E4A%?*CW1@7)?zBM;MIe3-&E{!{SkvOeo2^)lkv~Bfc9!l%J)F~n> zf%3VQBMD%ItkjMnk3FWEncqh`u~@tRS?Z(uuY>D;O1Njr3uu_;#s zq@;)>qfB5qavkVJ+3}eq_Pne4hE(ECyVpr)ZrFA;WNkU?pVy<56M?b`;Ep1OprUKi zhu`}GF1^+i67fxQL{)&l5FsYfmFoJnsC6R5O8u3qO%8yk;F}e~X|h({=(nF8*iFF`Ht=p0tA}~q0;16JnIerc)?V-s71(` z7h`Byi}&gXq(I}7+?%sWXX$=o*m~rQ z<`d@du~{tIiTtvO&8wF{9l%{j3~SejUX&wMvLb7d2dbt@F- zv|7l>$C#bU_k~pLdY#qT;D5gZ95qe=LxuzVokpU{%B(waQyJV%yTDZ#WkEumAWA=r&^Vjht34n9IK@e!PaeWS#m#g4A&EVZ)JR~{M<;hf7zl{aiF8;>p zAx<$wR^rE-cixK}GE2k>A<)hygQ#R( z(^>*e^vl5}wuPGMNnHi8*5-|tav|mlYe0V{MUE8`&$$yDz;k{%&Bt7-)uy5fbtDzb zgJ0b{NO^F_8w0lxa0NjFA6Z}y769wpP_X291DS#Rk?0!K9zd4oIq24GVxjzH)3OxA ze`;GbiJU?kjzrQK$R<&uNGw(+ol`2yt0iG>(o@xIeZ_|N-ZZqcbs#W3r@0)<9w5J$ zXVdZM)G1UMz>3U$Iu-$;Fcb(?*{OyN4@~u5hBG#K%?nt7{^}aK%+LOCNl}xQI`Kq! zWh{dt1s<3w*rzOUjFG(&Jpm-1|nPk``MF`3-!#A%29-oU}fW(C8f%q5LR9DY-F{<=tTw zRnu|Kq{?|fiC?QVw#y@y(<=aH5+aM(LBlcxC>BMQ(dsd>$g!pX96QP2`V`L<0>^Ku z_ixO}d*V};J$J#5mi@v+BrO8>L-eK~pj7dV&ZMvovCrI33}G%@fd_w|M2ezHIE8B( zNo}=J@`@b%w7py(TRQar^|BjkKlUy$`7Z|JpcYC1Dd#w?Iu_#kt{9Pv%#6Jb0m*gU z3+Wht#K!Leg0kv?HitK@k*a4Y$A37uf_pV#1`9-wnlP2c1Q8;~wasM-)2SCA+K1|s za}4y5I-UpMzszFg~AA7S|)^=!HOMDt}uL3h;YnQr6L z=!0S>8D>WWcHr0SEK(Wb@m=OuO&N81(|`8LS!GlF2{hWi%|zpf^G_f> zcUpVoBa2x$`p}d1!pL#RYsxGY`{CCURw7Q01C%1CajGP&kdqT7fi@#&T)?eL5(mce zzZ$3$sVAPIobHX7T!}GA6!i{%Y4Nok&4NZ;S%%;Al7ZcfVoe)7Pas0TIzY(5WRd~O z2TECLc%l%=rXqC4UY99rpqn>N?ihf*2Hq&}WkHWwa2W>=>4=^?fpLgaXqGW1Ua$@W zGZy>3rFAzXqlZ>xG$A95wDf2_ahK*aV$?aR&s>R zaC=AusYJ#yeUO2KA%TNIB3k12avd27(HnOORKzD`>Pt>(OeKuh`dxd+oN(!rm83`P zmgl%&sFylfTXzKlYR`E%u6g3l;TI`vizHfP5DZ{eOW9!(kb(&N6#m@#wEn1SbcrhY zb^k6T5t9Z+6q*T1Xgi49Nf{9}2RO)jl?K;hC>yqpd3_ND!=VW20BnF+r6$szPTWEo z4v2EXcS$Eplf1h{UL>$i!rqa$b&Byr#*JbvIg0KXZ^j@@uCj5!6XHm17#2?|SjCVl z20haS)NWxC`SnLeRiq-k7GhGH%T;`SxUxvLMKAv90#8Bx5%nIFI5cexmz(29_$uO+ zGOZ7lL1ru8`RY~zczOE>n49M9mlG!ja%s&%3CT$!pRO$_W0p=-8(IFcQLMieu25`c zQ?Awrbfsun|D)Y%_foSkwrTZPq7+%Lk6lioYT+k&*6f>_<}saCwFwaBFUbXnf7PN% zBohlde~)-`HAnP^5bSZ&S4#X_L3NzbVH=KgOFn08CIJa30TA(Vu#@Pt}Fio+> zA;gozPS{UN12l{+T@F$l^#PI?LG}^M2ctcY1Yyu)u@!lt!YBa4at0p8`xA`;iG*7z zG(QFuBtbwkf^5b%!Rj^+P+$VMd4_WOf$ZKG1elR%xk4Yr*nb3oFkaVi(|O9?!?lBRU4CiXuWUEakqk+)fo|@-r|I5Yu-wAjq&SY4E2ng zDYBrHw`#Wq2!fST=u^qsD}^j?$cbYO+s1f9-v6+6{uibzU3}1fYH!N(E$bSc>~sbi z$A4N+$p=)#oS+qE!9XJj$th)A#k|h*#}sYJ4_#{rIl*=zr@&1$0OtZZ#0sRqlB|&p z;!uQ(>yHU5+2%}zVi0C7V(Jk)W8SyKl8$9qi0dx?+PXL7tG4z87c3BnzrL#<2G52NGqOL7v zJZ8j|(SR7^*}#OysoZ$C5vdRqsGf^?0+V;~C;vKF~RCpM9UB$=a646D&sYz8NkI*sWvz_yii|_R%#g*wE8nbH_JW zNv?bJYYR1U3-Qz(z)^w#OOP*}I<%PZDdy+V0pvlkO((iT3>z1(5rnlQOIybBsEc7z zHNrhUUjzWQco>YeZnv0qN%>_eaH0hF&Ht{wV;<5Tzx)3SvK69D z2;*^a`MUEXAq#`$GfxHD{Z*>u@Esq_wHFjqX57=}zQZhAzcGgOtAom02&u6yt|10a zyet}o(h6%KRdT`Ge;@buwTC-XS2KPBv*+5qOQpZX@yWNFbIt#JJqv9gWiW$tPeSx= z2mwSV>G+~fEJJ$vTlCjy-m0RLFbf)c0R|&gd_b%;wNL#i>-}98|YKEp1 z!GAv_^`HLhNYo7u{%}Y=O^%RTVR$>aq(hL5-@vmFN*zHJB61onB_>OaAkI4l>6U}E zBYqM1XHQFSOLX3w%yl+vDYzf(J|7uYgLo?dggr#qfFC0eAQOpSoR;Ee73(pPV$ za2x^vmuSRg<$6=|knk$pY-Yj+-u${WGW}JoQK=?~NVsS>Hgpaai}U!$6s@0 z6LYiYVM;kE5wpTDZw%?zSZJ+!@FNB|SP;%cqf-;|ZXsmmF16y*_w>uAJLW3gVTLs5 z+Oi0#kv*k_kGxKVKtBNhG(y0qZ8rMW1j3_h>gUaQ#J?EP`C_PP5n4(~@tLLdh$KC# zY#4{5KX{3>^gl8k>i9sc(Fv#TZf{Hv%->qx0 zQ9>X@>6*(B$#*lUc%Uk)ytb`eS|)2+?yZnCW<;D2rf?+;qJa*^?7FN!Z1114D_xyjqr~WA=)vEq%^@h-q} zaafvqRY8fUV{%Si6T%=Bpy?PD}c)(V@i1vT2@Gi&7A?Dv<&5M7`^Y zD;nOKXT&iEP@WuT5KNq9!fnr?$H}}|4P5g5nW9}PseJA>?2=?%r2UNMSyEH9jk4=R zmtuDpo-RZ8fVPgt$*3Q zkz5QjWX?a>iVkto1lDA~DwB&F9WxM&M9oRY| zz`5iVStsMNN=zvErSA+wH1`d%#M*R`m8VXf%GjI@eHVIYja-vTjmj1Otw%QXux$5L z0Z1m89@J_Q9o7ofK*k^s#fLA7Y1s@Evrn-1d6Xg*!>n!=i$O4QJUg2R?$`+A@)MSR zZEW5;k0A6Sw-3so>=jdl#hDx`m&k1v%@$bm8vpoNs362n1z-jY2TTbz3bG2k3Ns1X z<|VPMqL+^KNq`;x;+eic2KK#3WJBLf>Dk|i+gz`tyM#2m=td>=Q28Y*x>Y|<08lTp z)J~7}fyVryB%z}eN~BhsveEB5KvHlO0jT2Vk!MKeF`XP_It*8+nznGdGFB(%hSB{e zu^pY3CgdTy*R@2Iji(X`6}RO`ur3uT{raB7zDgxpm>{m0qUbPTGrqO{tq~E;LlIRh|EEavAu#R`$X>bE;UCDx#GHis zC@5b15SiBIW>}SAh5L01iOa*7_YxG$Q$Y_(h)^iWIu;CUN-r%(pGdkXK3zQaX7(yh zjGN2czIl`_`@TdP$e75t?0h5WBP9npo_>o`l+%s%+ozPAa6KS~3hx@hqxVQN$aZay zM(#dg0CptfCR*M^i96clH#Lp8OT1X;Jkh3Iu)R$Dh%=m)C z=r)>4R6A!BPTAC&Y}bOa`oEg12`bG-ONwZcwogSka!P)n>x^K!imx)bklhDIR0Qe7 zc$Q>{QKhb`ZcDP>bX8RfA#jnG&&t>FS1Qu)dluI;$FZ=UN5w;tgyD}1N5Yg+G|x2Z z1(1-&oqXpmLLn3yegjVr^%@ykZ+T2J&{_t)g7A=<2FO|lc`Cj z9Q?GCUQ%zyb8lfwlBrn7RpT{G9RHKL;z3@cE(yXCdAZm9?3kYtvq{ktV-)zivY|#A(%57d1Gz+!#la^i zl2dFn3JA`oKLiFcMLt7FxgAf6y%*TuoN2&DsCTLa^XO9wik;~^LWD@A3Y9#*TLEb^ zH*~6R*xO}%5bs2-b3qkSXSnuJ6vcQ_6HG$=MTdgceorw;5cPY|x$P7?ttn!IEJ$b~ z@%US#%{#&~_ML0PdKy-0soLdBwA9ymF-yCRZ^^*|ch(~h!R4>8h0U$Jdd2@wa_SCGCbvZJcU8pum$SYRvJoHcd3vCefN7EQ}Vc3ZlH zSCJ04$V%BPHNMOejAF+ueC4$KwA+@s8;u#JRlx!ib!++YC&Ec=qN9+`Z{EM&WCSYe z`5`)yhAP@SuI;HYxFftyzx4d$GoqM5ljB6C*VUq4$88rzW7tD~5&67v?fKLPyc$J) zvu?QTZ$KHex+v>uPX#(sIoU3YgO)Nc@B%32U)!M@OHM-L%*!`M?hm{}{ci?K3ZlaB z#QC!JV0k}y5~`F;6GBTW@oaN$&&pmTEND0r6BAiS8xQRa`nW9uqL1FEkr-}Y8%k3x zYT;s7erdoYwF}M5r8RD?pMmC9u8aO(TV%FZRw)7e|EY{wFTG)LYvg~VP8WUK%6eoW z7@lShl{}Roq@b|c7v48}v|lV4RR;wgGEN)Z#btE5}HM_N$+Nn$?<8;)(JN_J+I&pRBv zv_eQ;u?=4K;@FzlTwfy>R{DZ{|2(!=FowYmTzJJXsM~4N^A7XIV}4g72KMGBtVw5b~oCwa?t;aXh&_ z^+hfxuANCY{q<-p7(|w)^PIY0iMCfcFVl)%ZzCWl9^Nh5eWqd-a;yJfyvic{NZ;d9 zbRh*c_#z>Uxd!t*AV8>@SX`TRBN#ad2HD#{DS|LfgyklnN!?Et|p)kvF}9OdT1Bk)NONZh6SvYQ4e*I}tA?#(4_ z4d^bw;6rh(@3z>=BT5jZ?Gim`KHciIPXbzj2nkIL57j)N$4|Mw+jWPPvPhJRB{p{H zYK^LzUxb-#p4^w&<#9L_q5%4WktNv+pYP{_)Qv38c4vwi9!K*_kw-P?_L`A_%@Jju zQm$NW`oAnW7Lu+9ZLfSnk)K+vvo@o$AFTQRW`v0pZ%MyzVOBqrEr%&eDa;jHbeuEP z@mX)HF5=4O)^>>dD_UD=H~KRHg8J#ae;MTU@6u8eRr^GvuizhhTrYmEtt=0(!ya}< z7MOHR30B#zou!q#dDh?TFrwVdWJ+%zyiKHkjJ92i8XIXLa%Cu2LPAQ{1+!X?$W$($*r^TbJ*rww|q3*GCbEUYfHgr$YvB=H6(Qy8KZn#)ijl~~n= z1I0;$fO&GjDfCg0^aP#0TAB3*cJs;38zt$PMT>a0=;tGBk~c- zq;2w9SVVLa3rQUc55b3tut%jx)}u1(;zW*@m)6HFy?>y3XFGoh7I_V($~zc?$ha`c zwH05Zh^FrxELU3Z&oiY)n3cd{e3f3zd}(5w!*4*;w^U~&{wXOg#<*U`L8PSI~xo3wgLj-bkrUzaw%C?z1UG{V(7BJuaSHb`1Tg1d5z!gAR!e?=>|iHpX8z7Q60 zlz9@aoXCkbb)M>_!Ce7_BH*ijxub%?*?d#mN7$$gs8OqqYMrc(o+lr_mYLC5qI*Qs zGdBcW9C51>VY#%UO>UCdqIa>Yy_JxgFy`d0Q(fPDgLzj|jV`6>BDTezGZ)R$CH63Q zKVV2^Um1zaRc#&xk|x}cK1J#AT)ojmm=cwrnkELa)qRa@l+sl45ELw`6}lsET5ya3 zgqSK(x=(dh!!V^a^u;YNU!oU}Bb-=iS%QJS%uGR^Bo38XB60h0XsnW}2N80nYm+Ba zx5rP1DVIWEweQF+4B_bNwGg~FDYEHt_<6h7^Rt%g13eSf7PgZ&ypgF!o`9`zm4*rH zYcTeoJJ*bV^(rJ=Kme93fS+T5+GYXl2O-n|1y1?m{&7F#Wz%6OLz_?V=5IphU|t7! zV0VwXGrSMrRW+ADpC-QqY6SxJWn0^-xUAe5zjlRiZh7XCP56;sPd3Wks_0S&^gibb zrVD|K%>E;`P+^2I7Dd5Ac#l2I7h83|Jg5poN;Lq(usaUH*#OKiik}=MMi`?gVB^shKlj#WwIN7!S3q7oMETyOC(PC?BRqrKohV!* zotm#u5LLRFzYWgRNd}unnI2Xll;WI&>eyH=hP8k|!5Oi{O1s3 z?g0iM%a=N;4=`7MkV>NMMB|R$C`(kjF7M6KQ`UP20<63VY=ae}=hxL5j4nlv2|saS z{))sJE$U(;ZbgUeGg=iMsT7OLRT8))iUy%Y#L(QLu1pLL$3?TqzC0Fsw20FWT+trxI_X?aVro$MJP==1)Nx`KX1dzFUZ?Iuf&I^-R}-NM&Si zq18C76IA~cW!aa37S|OY#Osdf%b>RUfeSaOcB8kBScu!(H?p#;a?j?aPQ?p2&Gp>o z;>k5kPA;z@XyPxH7nSQ-4gWY#He5!_N;MEaEkg|RYOZ;&u?=(ly*N{B{U^F@O@OLG z9mYq-ZnAve;gdzvuJ{z%Ps6bUxT(s{-W*pMoEJQijCKjTEKO@fh$eMdgGkMsI~ou} zC9Wg>S2ge@F4A=@Wk3aE8fu~((=1>6uCZ>thICA3I3P9mqp!`Pv*T-6k}M)76!K4F z(L|03g{A6Dq`5CWk8ELETtlgAvN^;G4KlX6y~L59!Lt)%hbL6gwfTy;Vcbqa9Oe5) z9SoC_eWPGhF2bB4(w7lPqJcEwE?av+GL}UXXNYx%DEZ4l`GVa9uj<2WRU5#o{l87w7MNtK}g2Y1f7zE*P|F0)! z8A5P`eMdJ8A-pYv3ZSxicU9ikeXsBN%c8?%tTv8C*Vzdqz84<|A^b#HsiNq;3*l76 zCV{|SC07MjV2UUQS2AA#k1(B9Ep0EVM55uyUr;MP6(-sb>0ZU#S`?5>VI1;qZs777 z2UO-=ozLNTu>?zZuzqtq$55mYV6`Texfz8<@Ge4ckC+Uw6609_J>6(QHB7?SMG>Ie z66_hVepKu3h5&*hP#n?=G)Xc>saHKv0hSf>KVjk%u%7 zr4GjA0#-ht0K@?G00iwK00T?`9{>l82M7rgjx>i<5>u!zp(zM~S`(hCHWB?+QKKeE zaS#jZwT@Ng6p<$g;39+rfaV6=h8LK)vr^O z;vZ##%;L7xRw~>PT;NA36eE<>MAyW1a*+`rnNQ6*gi zwpQXI0N<_XV^2E}vU&s2?EuAv$)ydb0NEQbQ$VW(jSviwdvtH5A%p}3H(|`bfMHIs z9$_(Z&22nu3CRV<0;(x!#x2KUM*L{y;wXw5^(78YlUC(<`YRH=DaGQLk+&zw*g|ef zNawT8*L5gg$Mq{m;-)=8c~Dh#&q0yH4*uwn%gu~s)sRPoD;^NAhKd3;4k@4}aHT;c z%5_DV7?#y&ejz_oMe(g9v!ymrVb6?(6Gth+K63w$wrrC!A<1J=78;D0nbr;P)IeSd zY-d`Qw=rL`M$1H$ROtsrd9Io^zujrKYm^#jn9?QWwO!8I^dsBBMP8H`U-|AcWAj>* z3G4@T$3dtzRO{NE{Muo-fHt}L0?_$Yw<`rFu2Gm&mljv+ycfo0qLgw3_@Qj5Fp`8v z9fiwhRc$3aR5NOn=NM$!#;w{KDXxw~anzQ!4eR?^T$$sdD|_s!xC9yHPgKXKgOY`1 ztVvP}Y`pBWF{`Ad&2u`)mP7cm342)FvxqYv$|+v*5t{-eC%)I} z>5II`=@i10^|GiO>rS2^WJ3aw!Ug|dbB@cC2_xW5 zTa>I-{FFr21ydm-oNoB5>lluD&$3iA@>v;&c_(a~o5NBv_qF{dZC(_QmP<(EsD$~R zc8~`5m?WerTT*yWP?WE!3e?psZ4F&E2+wbXbERQ1Wb-XafqzhDT!53JX4g45Me$(P zjZ9w1dX<}6tgobHSr$KfL{c&;sW0g7eDV_ihX+_PZmUh`*;OI%C}dsgM{xGpC1)1I z2@p$aff`A$WTSi|jp-|I&6ub-`T2=X%)9)Wa6FzG)}wv)FXz7Mo-k06<^m0?2ig2_64No)TNRKc?4a)I9CgaW4m!6$V^0xL2i9DCTGkLKB zc3vjer9X>7+?@>305INjblh9bD!II*eb@X z=S6ySPX!4o*N+uSodr967DS>PbdC?zvB>2 zk8a1XzG)tfm83I-A(dPc!#PkD;*?J;@gN1@D?Ykc1hGBCQE)V{_78yj;}9Yg;EwhL zpnf$RO+#2gp+z!SegmWEk}5=HsX*ilfg_Hf1^VnkofH>`sgaR{OZ zFBSabLUK^rj+ipkg%u@;rpQ`yfi zAOe^}tOD1a26f4qy4Rh=+wRBI#nO%p5Maf@HkNfyxf5Ut#{rxkMe&B5nU&SY@*Tz1 zr}pHbPa^ShR$91QPrBVgY@}XM60Bt4+|uKxnCa#!g5>TlbvkaMM<=M^=g<^0jU`dn z6?0`%$Ro@526eAl+ul6GxPnC+ zhTp?EPdEgL8>Y+dn48Lcz{2dvAr$W@SOwXZ_AVLH)=1Us+*|CJ`789aUC6i;EJX5dwLXUPE6HLbuZ;)NK|6;IrdK*QUfuh>MVGvO=+83D!hY2=ui;xeCRx zu|_6vO=HpUn_7e*Q#S)qGl(-!mE#~ejG}*no}k)eZZjP?HaiXn7(g{8M^i488KBp^ zD(S@OzLfZfXMO13+4-_mxshIPLa8`FCKo|FSq-^j~d(GQ|#=lvQgodc)2^lb+hdgbqH1Qw8_=;CYojp^Oz62j5w z-PzkSUogKlt`SS4z_Tfp_MC*zaVWeQomg4_pZa2fe`{wQBXTA6Cf5g~PI^#Wr(j{$ zS!CH7|EPSFH9w52QWg7nDGb#T*qqwmE>`bXc{`wVo|1x2Pt|64jIo;Yy+?z1kc2j- zjb@2r#;r;i>_%hETX7Di)0bno{D7X~r|*w}X)el!fC()}wdv!;!3a+Tl4z_Unnp)D z0I_9QsnP_TCK+_}q>v$CtiZ*7a4yxO4)Cr~q3Rt3iCa{VTnI8;w^gX#1AB2Qe9fuY2=wQI$K<;2pqso!epG-f%=#;zQQ?!9E z;At;shg+-hswK87(*j2fSwAaQf@Ra(trtPCG4djUFWobUfMRs~=Vp0rJqmD(v;hNI!6aYdy zCti&9KakDZGYpZ<=KmQ0+tPj7?Twu=cT%M6J{VVSLf}oLJ`UH=;Rz;jI)7V_;y|S= zDuys8m7|!kHCp|QObn7x7mB5!yUj$WD3p%Jwh|fcJu(Xq=PeZvIRPNZ4s$CRs zkwpvZI75vQY)TIa0VIcSy8+_nO$qfG(tatKH~$#7t9&Su`)o4QU#z(`}Ux_CHv;~OVyqk zOJaGsc0N-C+hH38zcdFDLqwevA_YSgMMADes|L#XUWs?4u|#dqN`H@%BzVYNqzznl(Ov(psJZLvtmzY--(uc$7F(uDalC?Lt4B*J|_n+?~+cu96k3N7#* zPYE4Ewm9isTJm!v34aF{ilbKBYsO$d%9%18Jh(2p-FTqCh~06z#WzZ0nAf^3TL>mR zCEYG1c*EH)aSII+!3@LzMKRpz+T>8L(J2y6J?sHyNqYF+lKoeW{IVwsFV`_^~Ix%c_4pM!5eXcYeO ziZ~nGb0k2r*_o7VWt4N6r5J^+Vw6Gz5z5jE{IR9KCyPLr)edr9j%|;MbM>-S zjqs7M&?LybGg#@be(k|DNuqxy$R+s3iYBgD#7o*BSOK^|qU~B{8%OYApeA1wnuZA3 zhNM;rQ$z~UmtO1gV1Sj1B>e@cB5_=*&GMwkRlu)Rh6YlbP6Vr5Ns4!hEJZ4*-s?LMV1)Cje0>J!)X0B^p+5RF zh_S?$b{-ZMlf@Ho6Wg2zpSEB(=MT+W`Idk+Pf(|VjQMM9x`g|k@_33(TO0@w^ zmRUQ4NPrY{aL74E<_#GT_X3$Fbr>Raqi_U)29GVn&UzRs1U6P#7hW26ODIM7(-KZ; z5htN4AwQZV^0i5TW2#&2x$Vx$V!EgX#rh{kx?MJ9Aye2#;n{Rn9=Op3hY4mOL5h{t zb^<7ZMzsvbXlsThl-x4hVrj5e$}ueIw&1rQHRKDvv=KHw8|73I`1pSBlfDhR^iV{Q zMtN-3vr37&$&894{?tIkUX23TrtBtVN0{{{2@|ZXyBfu+GxV{KDD_v`Wy96-)Bj=p zgk)LVDZ2tvb4X1jz?h$z=bSswnVA_=iFKSJG`L^GO+6qzc510@7b9pQd5 zNTD^Nv~Q%INc4g=TzEUvuDxUZ$)j3nNPy%%c*8=yL>WD{-X%EX65;heH|1GWE%ha~MyP=#Ac#+X1lMKzyW&YbnP}wgy({v$_<+H3mxm4a8KEL0;u{QMO<#-hM;KoEHtLd6xbqKyU;*|J6{ef=?`hI-){`Y0QpLLF*+ z_AZc0ZU3UE1&8o#+GC|2GfG=ta`=>Vl1I7++hCd$VWKF;+hqoQFm>DI9*8FG8${fD zL|7wkIxaJlOJiB;T3ZvH-ohD#E4ejT0(cceb*fkGWp9f@#tiC8NqaVjKB4~VB$)Bh z1H6hffS?%%4e4D|j!cYcEDiY8GWE8){9rJ6S9av_gQzoUFf??JAM)9h7extLFvDNpdxxe;}tN)i$rBqJIcf?H_N#nh74}5XBPP+dzWueXXkK6kcq{ z+PiFT4}}288-Oi{F8RG_0xdDK5ZhoRvDk-pVEW=fQl*3X#gpcAeFkCv)3Ao1aPkEK) zcx$4PfVwRej;TRxCvwTEf`1XVDkerOiN>3{$9vSHE=e%aG#=>#NL$8`2ceJ@VpTwe zN|xI7q=En|qD#vPQkb3*MXAaJxJ-mv9sF0CrE5h39O#8{iwF6ztjEw<#3-2LQhi9& zUMeYufaC??05tM}IQP81E*{U1s<8c2tpN|BAEsMcT z(jd5lvSr6SD_^6`ln69?3UWP@X6b-dChMvDI`94K0`r@horDF z$FV0}iq1l`{}sw6yZHdUrCc_>CV^yqJ-%Fa|FVr0u($J>?}1ql*6mN6&$Ae=o9rj@8tHR_ndQv7@3pv1xc^iew01W^npa1}Yb)W$i z1WroBga9eAzn*Z4H%Sp=7d-#g4_7(}7}H_0lsbLwN_P%t4K!g8zw&C-CEeuLa$eyk25|PNn;n`KfkV0Y%k`gJ<$;Aa0+47cARZhQi zEvs@kX@Jlh1B+7{po7`UyuXy^hTl zWm^W=;Ii39nbE2>+4Ov;QZtC{?bSfxoQw6h~HhPKyW1#fAf3DVhsmzkmwa@|M|X@i)a zJ|sjkCGn&Ud8d#}j2qG90qdX;{o<~YpIl0$c>Smj*$Mp1j!_vOefd`JR_{O+tZBc$608Z)96 zGhgJpZ@^2}>=O_u|59ItWE2awHtx|vPleA?)E(Y}MRaO3nA+P1X<0J2^^mzcwFL8s zI_AEDXqb)0Tqr*D#y#-3 zMeSfT=CVd*nX27JwMgd{DFxX^=)0unUJ&WggFV4&@j~wwhM0>%VsJ~hSE`XNlZ8XG z`qfk&jc#e(JEhl&v|E>s=`UfSFU&N+oZ7cr zyvJFwQY938 zMGi(xakXO!xGZckjd!gSq_GGR}*l%Jg03lk_xKc!YzQU9dt3UeMWM zGBZbH)Cz}SZIY4IPYFu7=((rY-fN32Zj+L4E6V=lUpb?7Dz)At)x)Oj(vuYXr`o(%0+jy7?Mz zFKnop(bzW40P_@KHo4w&_Da!ro32kWl;E~dw#~#P^Ypg1(D+I99;&=jhp6VK(&KHe zHz=Lh{V{FkPJwcY{mA@T0BO(sn<%%4mH{s`+`F>YjY*bTOkSo<(Djcd{|rv1HJ+91 z1fkd z_5g{(kb=?cX`&#*V$tO91n(=vr8DTNg$5~#6X3JwHXyWX56Z~IB*Pn$*AJ6HtP-#C zRej3e7()8f1+m@riFG|h)ts$c(tb7_hO+jcy@w+r+`>#n0Mfem0yOVRGWY#2jbEU< zYYMC2qR*Z!%K8of_sZ5$6Rh2EN@s>6TSCQgd%r+Ww!_{Ih9%~z9v<}X*(ax#T)&52 zZC3k{CtfXq?L(*TAZ)F8I%!R6z^jK=5rjMK5d~}uA?(L*X*V#;nk=N!fZ}V0=t+p- z@jd=8ovew6u`N0g6ftb62{dUGcRO7Q(=-40Sr{RVPPOE-2d%5A_^8sR|E371T;?f4 zn$*W;jgm|3+{2iC--|J^G&WD%rBWgZNxbywNN85&Z{(+iT(d--HU#_sKOs?Kn2p zRJ|v6lRx=kMLJufNU0Dlv_-fj16dU=3El(F8fHAM?#IjLu#0EnLcDdCiCR>q(^hSjatx_Rd02+FMCl`#MX ztd#d+A@;2_%_yJ5-W{HHs`u6S4Z5`5v7nkamlEo7StbD_4k-4GP*gYon8eiKnL^3R z95^0OvQR)cA<#Aer{5;0+O`xlX>XNWFihCu#Ff{TFAGr0DSM29F7nM;u1@(XCa|*6 zvk=?xolY3^Ji!nHj}P)UYCh@Qr0nMY$AbO*nd0>@iP1X@@uWw9Of+ckE^}k& zF4C~-8|%?j34iL72-$w=vU0n?^8#5R{pOgLKlO@mizMn|rpr5wq=$wlLi9F8AMWb{ z_FNKqZ99=+W5ZDBtwIGJ)i976`rd#AfFS1WkYWcSzbHA{PZHcxk*IGC z2iZ#5I3y*d$!Q$j%=bKAucIR?m<|OXR{c!pgYr~p2Ql}_#xAB%oA1WaueP&&%HbV^ zqeCTzP2iDX$G-KWMbP`o%?AtYt(pEVrGM@55kdxM)e5#H!6CjY^P_1VwwxhH z@?@E*WRB~iB2lY@sJ#%-tB~=a?|wsvhQm8^5u269$c&s)Os(2b(iN3AurG~hs;V{^ z`iIR3FRWZY2M!|4IUG$<6BD;##~PZSF*jYS;=Yiuq7+xY8YgWnA!NQ!1pfXA@X><; zSm+KhJ0~NWukT~DHc;3LP(ZfE~<4B7VI~Mg}rnvW@%XF9|X++nsgj=f7_Z$q3E5c)u60*j4+r&}#yI^@MSEjkB@Cbl!>?kl#F8lq6Ic4QN)-S&x2HPb z@v!Kt|HJej>On1xg}seLIYT*huVk~zIoEi~1Hg`i zHZKorlqg0j>o-ogkwt%Fl_u$tFrKb7)=l=U^r^0Sb{2&b+j~|pP^92n6p?#)nDU*X zL+p%to$J+zV^p$7>d?F-0pdGKjLF`GbvlvT$R{4RP|GCwN*|K%1IbDeIE$4X~-JhuI(`2t19)%BENBm*Gwjrl^lh zc6`b)KG`8i)V*Y;QWW_#z6Mq(gi7|^kYY$ujD8hMwbO`#;1Ko9;L1qSHe3~SQILVa zq0k0Ezfl@mxZ0u>HJ%Xn;W!?hWjLoikUp>1dxSx%v2|5%P>H;``t3B^cv>8-saf-v zjdr=)nRb8bK_iEv>>3vjny{-pn@~eSqIiw)e6<9CRlG5t*e>1Sb`h7=I^o*qMa2vwI@zuoJ3cpjYdo@?WI9B zcncREn#uO{+C`%XAy(yQ`EY_VzTSD+D)}w^1*!aCRYlBTG z7GAtxNI}TeTy2}fZegV9%(Y~j>Ys}t#xs5NwJXXI-TBYXDGsg*@nU+P2(eqfJ|y)w z8oieD+iTn9o3B=+k;fNQVZ&q0XG38@&=TL?hDv@fNUkcmaeCB<4dY2t*om7;%g&*_ zF7D|!m`P@Z0y>XfS+Egh z4pp3#(G?a?A$G`QYf&jW`bGM zMG%Y8C%2?3bb=WHN$^CMnw?vl#4;36GyN!?iLTand#`t4npHPwwMSOjUau1@jpBsH zCA1h+Ys8ZUsXJy=NMnAj{E!suMCL919ggK_=U8HBOga+jQtD*0IJ8I>(t3i}S=kCW zfZnQ&@S9b+)`$LeT}!hzSvNq==;uWSB91f1p?#C}uS*OkP&)rgDzzFCOT|Rd0uIEp zt|dB4tNy4^-E|t~qmkZz=z_BMWB)3iE?ii7;=I9A_N<)L(?wc5TUB)RJw*_)%1;Ir zJYAhJLFsa54(6Ex42o|6sZ@yhlM}upTO1_@2S}q)81;6}WnV;4s_5o8xz>7O;gRXI zGWguK8WPJWu}r!s=_gz8b|bu=#3|6eOVb-%ZrGUtwO#H-^pRboY`b^bg1ynZDI`|u zKhxh7s4RUCY1CBFs$|~8)q@?*EL-%H#}-u950d?Qu2$Ge{x!rPg@D^C@sEJl>*dTp)WhP~7_xJ_YIhN+Mm0bG zbdAY1Q2|f;qG^Xg*(sB>`g1oe9@$ak14&2F+`^ zG94MTKT8_)=P(W4*3F&qMhvlmXZGt$iDk#PEt@4tDg^tqu|_l4|H`+mM?WxxBB?dN z^Q=}>v0!yl41z5M8!dD5rhxfpjktlt+$})J2BTOF^s<;j9M!CV16-{m5Efgf5c8uc zPge2ZCW3SMw87;b`6lqgWM-lu_lL%CR5{ZH9e1P8p zRwoxwrEoKf@xObTZzk92fO6e&$j?Hb#g_|kA=)VaWC>FJCWgXsd}by)7-@ax0|LS~ z?E;38F6~>gKxI9mJ--`9oqGUpk;%~@7R-&{YY&WR=$|UPJU9Ax`=N#;OQN(t-upP{aSlf zfdZY_d#TXDlthN<_#7?b91(aT%>{u%X&TK`A%y*tM2E}cRtYRFuL-*&&l29eemMZz;=>|4JGb#+BbI$);i0)Z}Bx z%AOQvb{{#@TW|EzJB z#4Qe8PmcFfzlmh=S=qW2#oQ_Plk{1fpuv&TY<6(BvlX zMky04(~2J%Fn~%`tE3Udi`WGX!IEy%4_cIbG$es+ut`yVPN3%! zi2QPqc@Y{##y7lVzQ&g%xuzKPMIK`CypCfCMiPwjRe$7HS(Xw^Wm(mJ$g*o&Y_&4+ z1dyvRxN=2nl~Jmd2~1&uPy#`dh@Q@`giCLk=;tX^dAy{Sy%;NG(b`w8@)P&$M@nSh%xQyfZnYbz-fjsUoe$jeTZ9UfEc> z9+OQapMf&NqUA#Xn3CM`4*f!vw;=k@b&`|?Pt8ON>XJgYskn2awbe4R){Wo0kY!1{ z0-(oB+|B6=Z=>4DcdiA_BX~tIxm=2kL6Rfo%Fwsu6{b#8HoVcaZQ>dd{gc;b*r{<< zf599~ZmcKjFt#N5<{cZPOgiaRcFhc$Fj*p)N~bp%qmk=hCKJdk|25KAAj^(Jsky>e zq^!y>zMIiJlSG{eTH5)u_uPPc)XTc$^=Bn2bHPE9BO)?7c70`90(_KHo z)k)0bmRm{H6V^eW3x+X3i(UF@TJX~#wO+E}@)?vBhEz-eq#0UNe3~DOXU0OJOQx6+ zbPHcowLa>)fRC)^!ploSIkpN_r!=3C0?_HHXczLW{BSGXFEj?@viETK#Eg#G5b4h) zvyHwFv@Iy3dhEZIAv~G4>xVt*he+du6&jJ1f3A@x#ia?yOO)99#N}gX2`Ph|N)omi zRwoSn0W^iF?X<&+LUJHWWLZ276S(RlY+s+W$RR|+fHLYqkmXg03elG) z_z94{Cajc9Q{8Tq#b1em;!Novr3SDnge5JvMqqpNk84l6Y^YG8E1sqBVI*-%YmI{` zTHU`^Br?ewlTZt-G}=+Hz7`=UbSoAku#W{uly}!+9l|dtZDDUWkir7lNhn|gj5fx0 zP(JI~MRBBpH7qlrri~*`hf+Y^D;yPfD(`jqI0U4Hc})1PJ@Q7;@StpsN!ig?*Ws0H z<34v6Pb7V66|U%#y+QUW$`Kxrjg>9RfLkz;9fTm6xPKT-+Xk;hvs_il^$rJg+o=Ha z0|bU6H$|9=62NS%*Pg~puFxB6cQH7OY8r;0;KVgXYiy`&pX}7=f!J&brum}iP@@-f zw`g_i(tyQ|G474JWB9#EPw50WN0-D3#dbmkI52IBmg1%0M0ww=YGJ1h;Sej-I_gmS z>);e2_xi^pY+i!F(^T^px7Ci2-)*|)TCED)B?C=#XJ{0RBiMLCcj2_`B_pnipolweN^=Tt8rL(iD%2J)(T9AuW1{823>Vu9z&vQH65MY3uh6v5l zM*M~*;Fy4Iu)xZOu$ToMVScF{l0>s&%yS~N#e#!~MP`7Nq0&4sN|C_4ad6Q@myIMA ze3r-j4dQ;LS)iXyn5?!VJzWeGM-Cq!) z=rYIDPm$%V+v;EfB1&uru&v^X!%bPRQ?T&v2P_inFzX2H*snTor#WUS?D{H0v7CN$ zT4t@7tz!-&uyvfnXjEx>IZ=r{HF)A@(#py7VL@!=O;F#_T zV~V+_A$G@F>*0-TZc%Wrnpm?7N?rfDFpcP!7RtgUNggTJwV2-bB-Sd0B4cgl&$YWh z(%jZ7b!cmcJH(BJX6>`CXjiMlk_%6QJZs=2D2YQV3|BQ3eAa;Fz#DZ;fY`ulGN%~G z8U#b5V&1@Dp!Bkw&VixGd>j}-u!kcG4D=Axne&VdIoCkDArF)({YYUL*c%_BXw660 z`yxm?EUU&|T%Hn$_Il|VnU?D{6GhAW<$7d=$c9M+iX`D$^{05AaT&1Cv+^pcKP$W@ z2;k)Ga*ferBB~yAKD3V@-a}6xX<(sBz$LCtuG#etscKZHL|uLKJ=)1dKd4jb#bjtj z`)wu>KN!o@KtT#dbD!fOfVq6RLBbm5eRaFwLRdpbS(u!=;iKYYU!B*gR5t1Jh$LG}6j<&fTK}&WEf^^0qyc?AZj_1E2VXK$>iC2w8roDnqfD=GmzfKlhx0zMIF?n3fN z9Gvo)o7Wp=!cED+rBOC?8;(#DkEhNDwGXw#)tCW5!eh4?N%l|bI3T4&FdVRTI;1H7cQ z+mMc$MMjjX#_OT5&%JrQj1=_daws5_jDi|EoKbLlKsI%yf{kZimDOgf-P7eo#gg&1 zm`9+(#4ssy??1tU!DLV-GXNvdvPIO3*l0jg2@SRQdw8u3h?UJHc^(<=q{Vr6R@Uhn zl*!9K%ue2T0(~j6EVPp>-$i8%ArPHPrkfC&h%Q1qcIq*ByE)w(E*IB4Of&2;MsZSu z(oRN$s}~1A8B@cOX9Q55Ad1hxsEn^OLY`M&2gTZJ(Mi`GKj>pS?dj<3 zs$;U@C3)ku7yDQ`0;SAFV1v~R!)%ZiHSdw+C!VP*Le`ckB78V9Qy8ZO_uYCj>8m)+ z!T!jP5g}PhE-Gzaj>A$#{5{pE(({fdWM7}rlrG8Z?eR)0N=3 zrzBGA45y-`r1qch``0CQcQL_AvlJ=(5lUP(#{gbQLPJc1e1N;tY0 z^_5JsNjTc)$7HLT{jX3t*XEayWV*h4$5Gy;yBl^!RHP5GBX;J9FC0jm7nxM0V$_W! z7>?3~WpYx7oC>8{{P4uKxB?kWw?@Ba_)r>~j(Mh}(#!pcD5VzLFGRmfLozX2b_9y; zTgv{H2o-M`=OH!XUDPQ-Mix4y<50S9rs25uDE&HZCgWSnmVcZR+->opQ<&BV+Yxt^ ziU!kdT1GI7bGQ`H5~mA}N7y-h5Xn(o^&B1%RY8NYB8OYLn0nA!fI|=0p7-7v!4e_K_v6r2_5B-pL+PqjU_ng-TwQc9%Cx68 zYnc*$9OE615fc7dDL8QoL{#)x2?`8m7e)D3!2mE3@$m(~(yC_d{O_=kZ z0M`c2c48h4_Ef%n=a1vNE+r3>uPM(u~r3p2Y0qV6S9yQkF!K13S$B$Fa5er z2p#K)d1OSWDbtFsAt_nX4erFnXgP^E^O*r?C@pqh z7*7{9vBDMJCDga}pl4&mD)j1*^0b{u^er1UGSEUzRnR*s<&b4`U8@7^!T!sUNxrf! z(1TPX3mL1teoU>c4(k%sjG_^`Afg!_h=~V{)pVZuB|8n$Sy76BOv(J&ebG2>ZgQY} z4)#zm@i3T2gC4T6E{-99%8YNC%-Eo2duWOI(>(gizhuS-^Sy`QO3XZ2lGbGe7In2a zw@%j&v1B;z8PHM$e6Fi8f-YFt!CbAJyE^*<^ziw%)op1M)rBQxVj3zGHD6`^i_}W* zRE(XK2}hdRt3I`q@@S85=cUk@r!DN-NR!@5(>mzRr3pxm_|K$qH#84~oZMQ&>m67x zEFH+CaM}NIT$hm{9!e{b_HB4>r)gExgu|3%#zCh*EOGxLdXNkreP#YiM%I`EepB5^0@^tfsB2v zg>dab5hdb0Ws&18m@?dEeYpr%0Qp=*U*2k%N<4dq_U^edC&T^=_+iJ7lArb z(Ar3p#3Sx{8G=IHg0M`4N#%-!f}EJbR{iRwgM=vxmaar%C~O|y%g2cG_*{H1w^sWs z2%Qz&+P)fiL}MT${&;%YpN`XLSx~m(;Bivy(LP}W`?f2ytl1GG>l*QC71d6tp^j6L z#}fF=g7kP%Y2$xY@8%8NsS+@}A*5kRU7SV-${L5R1;;-?jz6bt?M=d89TQ$}^6#EW z)+Z&nhchge4#Y|o8*B_dXdE_*Nfl1z_K@Cm(Wz3ZNSy(@TlBcW7AbL7V4S4M>iTCs zi=3vz#IJWrRk+ZzM3xBuh^)tFPM$yaL$zNbF*aaICv~;syz8WL35xofb1#bl`yAX1 zB;rdguEzOoawG+fomE^$z?A5dER;q7o>*MexNnGmBBig5va)jEq(DE^Bnv91K2vsP z$hPlj5Qb>A@bwrUJPBa{)P8qZ)wQ{LGfU}8FAFPfd`yJsx-AjcxwL8=D&GF|yQO>r za{H>)Hp!qta(rAVl4laLofktD?>M{odSsf^sZwXLQ92Q-r*?2fs*h(4vlY z@j$QZ>Tffv!L#w*jO_9Tg44eRQo)+i^9vtTcMHO|hgOLQp6t=`Z!?eMia=~XfFc^G^))cM7KWE8$P zOwxHnr<=tFO$k849+UraqN86qS*)@T;h)Wracr)Jg=>Mu?rf`_DTHhNvK%54t-)Pt zF|4&Tl^yD5VNxRkBkI34C|(~6b4@BmI-PNx>fpNgx3%HPe23u%{J8ZJ3Xe}K4br6o zpL=Z(a!pX@G!>L2nqO;B3A2XNs&1xQB(C%LvIX?UTpI-nJ#g-OV0X75(kc8K%aYor zgsB{35V92FCW>lT_qxOt43#;-wX1TT@N)~Xj_|l7+xzG2m+iprR(D6|EE!d)o+#mYlDpw;-2Dzna(>t%nEO-go^j+>Qr zz3Id{&`vBF=2}dzRA@~TZ>OO6^Lz#53_m%aMvy)wf#L?KTHSVxEz_tQOfTTFCh`KG zv?-(fF3B1D#^K2HV-IfR0-FU0B?$E*h7%w!LIw>6++-hl`vyReSqcR*=5#`D5$Bty z7)8Jxdjv%>NDc_F_}&0;kH@SXGRaR!`HfIfONEL>D~W;U}S+|1`P5MD~~xG{{qN z_b#fXT_8vM9{jMAs2dM zk~gnGm@@@@8$Cx6!t{NWx?;POvoS)`sOKI5u+7t)bTy53I}mfH8o{41sC1w&rNd#j zN90o~(MYr&_SOQ0e}zjauzhl-p}F;JB(PMx?x zxZd_9n>>$Z07N$_*WxvH5@n2G`5z7tAp{lyyfQh@hRNTI6j4DyUF2DYyU-&QE{Zvq zku$WTI>=ObsV$%FVr$J&c%pxMg19pwUg4XT4225?gs((z9rUIyXe$DKvDsn;v}ld8NNLpT(fIkXc5oGNb$D8b1F42ylkxz6`1;IX)!wJ%v>^sCma$qnG9@i63 z&eA5u0)D8RoQv!diN=3Cf*s-h3KKI%Xrd`%o=)9VtnYe1AI> zDPb!+>gmQ4yTe3-n~xIKw?{E~0b87L$?H7{TF@d-2Xu;REfk9F6;#z;O;hRh zc+gSB&j=*zEa??QJK6H(ySlVW-)jJ)%Zz+`SXR^g!STP$(~|`Y!E};4!x_WJPdTa? z0Z`a=PBRnu{WStHiM2ZI2w&`3R}#}4mnu&A0$BFU_SJaP6CENXv%>eEE(gxdS(`lG z0@vd}WBTPG!pXsZH7W-Sc`AYAtY6~2OeyOk&zGk5Yen-j4E1K$X>)STU*HiocNbpl z8|U?Lc_WLb+R|rkU<@zC&Xve%66^R#Kd7{deq_&cKeeXDPD9~^>}jQ&SUe|zYudBP$DIJ zUDGvL1z$Yp+3K0P8gZ|^_Nv_`Nv9%9qRXn*mb5}ftkJ(4e!^!v&|y_A=4A||Ixb#DQMUbEfQ`N@-Ns{G`!PZ%Zk z2WmE^ZY~wsG-iTjqqjFXm%}@XI`EhzzL#dYkfQxn;r`8hKiNltQiryD^O^b6tAK(C ze-T1KPUV>r3=@``*#r;q0N0Uhf9^Tm%r437GJTClB7N&ZA%xWDQ_P!GkYRc{mgjK9 z?lOdOc#Cu|1os*7(x9Iea)?9D1+B?GU%Q*2>i3Z$OK1!OdPJE-`G!p3(WLI##ZT#9 zX{2lD!ACWo?dJ3Iy4XY@Q1twsY~LlKWX@&#sqtw~aMqj_=>sds767+F5~?yYpj$9% z_m(F&{ukE}qDZkxYp4g02w!BkE^EpPm3R#PPN&Z3Kw7 zCWX4#Chj!ReIrWruEWXQBEk>I&BGud3B?)Kg;b+xNbuMuUO2*)eEJ+N;|NfX<4JBB z4YGffu@gJZEd*a0Sk*?zJM98ta=zO00yd?*PI>Ka_EU4)cA-D9jl^ zM-<)mwC~M^!;G)(d)I-J7D-6X(mc&0BJ^#7S9LG{JlSx4r9^IBwDa~^ePtS$DJeE) z((5__gukl?Ra=|C9j06AlPRa-1gE#*5*3=SwS7HSFqDz}RCjcFPtaEu6#{eFzHgr( z|0067;Mwwbv`I?qXD)IDrN0~e`H8hhi6Ca{SVRDTPARe+nOO;k994lHi&}Rfv-V>* zB_-hWf~z*bC*TD-Cy)Sjz%j5Gr~oa1KGe&S__{0G3SPh|i9+1E#FxFBNoET5x_o8e z9NjgLR`BOvmZavVb-GqtDsV!VVx3F@M~X9{o1Z777o7X zV1U8Z)m4Zg8P}AR5SMcHImwb>Pm@1$LcC30O4=(wz1d&gJESPyOy!s8`#k+;*WpRF zEN`U=npiJ2-gVz}bCiErGXuGm_(s}d2MyU%?R)S)FwYWxYf@x)fl z2aD45OKZuiTnHNO0^=Y>r~mj_7$SvE@?z{T>4NLN?N;rD?$+=g<(9+1a){3Y!F=vB z;j4cx3nm;zX$>VHR&gv$jiFikoAb3_Gdr|>La(e2S?$nlxf(|-?*l_5XlBopbvJ3y za#Fuvgw61}u);Rl;ekq+nozBl>?54YD~f8WcPrUQO6vX(*C&O4p(aTF+gnqjvD@4x zyvbsp(2}ZzAOA|NtCSf`zFvzZ6#zHB)tC+dBguQP(a(LjxrsX)oKf}|HxDewRVrw10`b)9T&~<|YCrrt{m^b#c zMd1>L8{-rfoK|Zu`h``S(T>QVxu;P$!cLoWZ!}Kql2EG7aD<;JZS>(@A=O4wo?C^S zu^j=j2|b?@(AQ+-@MWGCn6^44=WgG*<8 z2~Oy796jOPymW*IjZa%~*+OYZY+2ENwAaVCEQI8< z!IAU{HCKRj!jwfRuk@cmZHGYp8D2vX>>zsr``gE!(k-A1%}17^28W0|6EqHIMG!6s zCXDNFm&WHriFl^1TA|C7@B&gznEb&WLsX=}P*4v>`i5si9#Naf6#9cKi ze`9!>K_^Enbpa%te}*l#zscv4_y|ZOtlmqyGvTzee6&d(RPH3Nk|GzUnP`5W$}MYj z>10G+#&Gx~rEWw*GT((2a~T$I?kJ=s?Q80?7Ff3XgUk+&8sQ5^$6+}Dk+8=(Wu&ES zUQuX0AFyuiCF0PUoc7h=$m~SXhC!{|3w);1Zmhq&RE7{(QUS5Uv{hX2L(`CtnAJo0 ztBGcatvHFsiOh9W^mG{cw&^0$oI#2dKpo|rHa+J|dLP^;mHgeF^#ZlY9oVtUC-0ci zQutWf1*sL&D|$Usb7q?nue{-UVrk6+Q@sgB`=Rk@gD=^UHAB-_9fKxn1UstC%oQa1 z*tGtOp;yedM-F@j;4l{wd6>c#BP44uB*H1)(c&1AuzEjR$8Q3*7&%;tYP_P$`>Jm) ztroP&`SG;wVC3h>GtGYp4-*>|I?qv8Bbd0V<~DOjii3FWv!u^AeN3J(R2SJ(pX_$k zIJs{kcWD9H7)i^Mr=)f^G`*j6EPn=9+|F9BGLF~nq!|NUezx@7+r8wa?`~N~al2a( zImlNVM=ZUs9-*a{jO$Y;WLU=by~^^*qp}gp4AWCJSYb0J+Jdv&wGK8HjJT_{Eq=-- z2|(6Fm3KHEWXL5oKRTlc2%l4EUxh?O=$?~+cka_D^UeT@2~DfJ?=!@^S)QkD#EmLGXEjZDhq=i{ z;>olb#{$AJ`o$`kqMQW4%g;6cn9Y208|uKWL)F)G<7MuW{qf`;4N zu~8=VS6fPGCI$E?eM5{qs$ATQsfokVp|K`BPy$dyODar7KT?%%+*M+MZqv6rvm}L& z?5xjB#=MJv!Vac?8n}{R`QZs9KX8$#El)uTDQ`^z)?%yB$3#xtPAjNb@Qq(t=xh~R-C1n!F%*;17agBIm~jq)xh^0vv^m{0R8Ax1WI zT&e`;GpkFumuLEzW0+ovngB{bwZFbi3;7i*n<)x|pIwNOjMO^KOct<^(BR$jvG#xz zELD-<(yv7+rO3V>>ajRlYV?8cBtamiI`s5J)|agd>kqy|2!<-ZICazZNtu7tf`K%a z=P2;qGFej6U zju7WTQKwSmob{M_U0aJWL+P3XX7HSAcEn=qVQ)XGUN2AVm*MJAkST0f=N2EBN*7n9 zm`fHIQPen6XguX$?O;^@;`@O_lyZcL%ZH4t@(zf3uGnB75_rX zTWMU`7|=!No*2tCdY&3qxfQC^peJ3Bh}KHpQjC*EM5w?>N0i)y@O6c{Jg(v43c%C` zn1?@G@$<=o_NYh$!htkC9T)_elz}!} zO@g^JL4qYPCl^uVazM-w(Y>;a+3D} zMC67b*vc{bU7IAfbuKWb?4CUVy|F`?&Yeuu4hYm;C;dlARjb8P3zX@Vi1@`LNg+$M zLg#_M5`v_Kl#)*};X()^IUOj+a@mSYx<-u2!c9C}w}xUkE4E7(#G1K!Q{xWgVl?#& zS$O`mJ7Y@49M`HC;}uj(!lg%Gzj%ZQXNR#8D@z!ILFAaxO-g%k0Z%XH-=14J`n^A!px=5w+@$nS(HS}h#09;_j@V%==wIMO;iNF9^ZD9&;V zxVY{lR3Xca%7T)CTSxsii=;7}R&gnBf1W}fS^HF((!ph+!5`uj{%z!~mK;j%7RtI!)Ab(U~Of8c}>#Oqqc^h=0D&7)}Bdn#)i{UrNHS zg|ejj$yui##sqR%jNa*o%6kfDSo%QCIvum33=_m&kq+1;iyw6?rW4f;^ASezIcJrG zP|dH)J$2bB;eOgHF@3Rwg^?O33B8qRQA;HzpeE#-7fru%=-O>z8-AA zk{+cQap*4CR*G5`qJgUWwO*7dKGcVe(R=ndBxX`oy`+tZk-*u%QN-jFvY}a8ol3J)Y&7V6$ z1j6Pih$6v_4of?>zl4K-$1=DODO+Y*qB_}ig5FiQSLmU%k>LN#UcHw)@68JUuW|FHfXZ{GFb|Vp5G-zO!kICpbBseO z1>%38$DU!~q>mnCwP@NF5X(0X;{w^to$n66EnaobF94QKG}8PqwDsO*7hQa-S$rYMU%wDdvEHFEF4fr`v>i zIMDcp(4(MRrg_skeXD8$Jmu2tlYFqhj$xWN`plKJ0x=3MVm!$0CNkqnpMd%CSt7S| zOc=?Y(!$m$I*F2X-L6?PC{wDi9fQRU%QZ;YV8s}21$VQh8*SVEhwccXvmWN*} zGR(6eOB*~V!lnh%ktYABk-dn2U6MUcZ(5`lb%hV=28&%B=Bd|yelV<13?aAdX5#%6 zURcF>F$}luH}h0N7o)yKj~i`?T{O50mzt{lDUkaj5UM5!D?wRD?HEOqTcUin8*Q;* zK|x2$6^tYtVfJh_Uo7qfLA>NH*1&_!!g#&s^I3SiHU&yJ$ebZR&}H0K)VD(%{6MW5 z8vRr?X~kS==?6XYenIjP9+fd$&q;!c^kxJ&#K9{Hqa%{Xd9Eo=yoh2jY%Z8>Gu$qs z8;UTG@@LHI?yCxTTha`(iNI7|&e4_@opmyo4Z18vDHD=B+iMV*?ez64 z_IFljM(eTRrc#PhUJLj{Vv*+01!zbJg<8n$Z_QVs+;VE)bZpsWUX3I#%KysZ_rX3uB9t>MUxWZtXMc2q#-8E%j(mbN%_|Hkx>L6ar^%#cSsT0w7nZ^ zHU?GFe5He2>-=eQw;~)J?o8BWPZW)8(~&2W+9Y3!uJ&@ZTHDoHl0~qKM;xjYfp#Q6 zg$mHKD#)*M8rkwz8L+L)0wA{O3k zipj0jBq~ypf-}rXCWwJi10Xfp?Vp<=pdzS5GM2jb)vVGKaxkVjJoS*}V5O*9tW_rYPnU^U^Du2;D36-{}Sr<~X5C3v3NUK{t`Z#`F?t zTfr(x5{(ApVHTn@&2=)@x{*6zQlPLU*Z1;^T=^-*Za#E&Sc-BXRoP>p7;HLrOX8K7@&|Lba$F2GYNrsh~6O$ zXGpJ%d5jpOJyvLpMzbYvlJowwdtxtQjHCRS6@0_ahMZ%8mI+CmTqPlfyoA36S~YiXx+K$nfRJ( z$1~%}bq@A26_t-$8e_&vP{yWpM^w;W63#_aV@_r##D+P>_0rHoM5|Q@50BF*M7b?I ziL6LiT7?dRxc_@~h_rx2(ol=?7)Vi%>ki|yX35Cyud5X40~2U=Q=^PzpC9Uu6RNOx z4TGW4QzCc1iCITl-+ASVDuiRSDH8n7&m}neXo_~g^~qr&MxfMBiiU}j&^zo~1}x%O z`4LyvdPgs8qrK)xU1L4RbTN#eKot+9p#?K7%(J%sU5n_g`*S`IzjTe6&vn5)TK#_c z$%3NN2<5cptKC_iG%2_O(RV;l~Z+l@Gmqk|H zZJ#Dz`Qq!Z6(!5mzxEN#YUVaeW+Kni9Wy*-)fCoj@3ZDG;eW=t8hcwP5=&kS&{mOG zWji_IiY22E$AWZAKi=1b5}vap|11kMJFH)q`d98qcFgAcZAE(9&RD%q&DWFd4B26u zq6L)y^pBFBKNqX$*7=z~CajI1J)ZQ~gerurfAMt+(oyp7MG287o)<9EQGbrZeaK;| zuWLIj*kL*3Hx93JvY~4R^I(?+IG#{d6WT`0IS$UGtRT!ybE_PRTL`&26b?-~2e@A9 zB3pmHsBtKoeio7{iMBeDe_hwYHL&nrIH?rGlP!cl>)^2`!OaRYmW-UGd!&ve@HilZ zmcfwVWnelY7l!iGS4)aiP@5wE^jOWU)BB}A^rl;_i1L9`6qv~5RTSa?%S8*D!hT(= zt|ALSqM&R@dGBrK;p(e2iD9sjPi(T{+$npGjG-ZU%}`Iq_0U-Aa1P49f96(XWt!LnaX zU_~0}Ni3B!jL{G)pV{bN%Th*y{@?vVo9{1D7iJXJ2XkcxSfFw9wpxUtsI0v`sM3#x zQNC>zvs?xn3cjbk>9vfD|4#I!8?CiSlSkn`iOoFo_&L@8$#}?7HeoF z_O0!A{97-QO#(FZVxo*EZH-wrBfRjF#jK`s_bYBM*4VXn6lIQ2;zUXw2xyff-c^V~ zqMYqIcj(d;Z;9w;KJh(k_Iw=@dG0vh!U^TANQ z{pmVMM8;(gYquhi%1HtH~UUi^Fo^7wD>D<4nYL+xuDQO`E?!+c~6wZ>JCO+#cIWnFC ztXq4@DM*&0Rs-Yc`no0;YT_kbd|0&v44_XXOu{KndpTc5DlI$2GsAnb8>K_DpR50= zL(spLVG7X_$tsQL%Jk|9!TYEsD`>xhM)^&F3e)&q*T_jC#+P9t^eG>Nhg$_Gd361hd<|#GPU-ydgSh&Dq?d&BxAqlBBz#sBK11T1tTOo# zB#xuTBASy%^qGeEhA@`kwl1O=GRLg#kWIvFNivw4V1&oLRP*aFL zB8f6pE3ewM7^UdZ%nWsXR)VJj{#O4S#Ok+WVE1Ol1hF*+pxCGa`O%p?8_ z5PUMonS?mALzcz-HT0xt!A1E9P_7y`y9E+^JQ&ZnkGW5Ve{jXbDw@>So8!8)?^9)I zNd)Vrd38t(DsJ9&M~j2g-3|Hmb)r_F4{5@`K&<&Jf={JLgitXK80G^9^xEd(|B5(| zB{2ml^{<4ad_w5wQ%@HgIZ(ENeoE_UFUXqH z+zAJ9ONSSb!gzQ3WcN!=dX4W_CHmK5LTeR{Sq~l;0Ejq1s;t^wO$fz@mY2Zqg!&E2=U0sdD|A(6%V^)4iT3Pp18HO0A7&~eu*>E z`2V7|Xf)Qxo6!lL$hShj-XxtipYTJa+$DB-9z8T31fWu3`3z>!{Q8 zdK>lDrlqKhm946(Jj}-LWsdrQsM|}A^;c4tcfvxoV1WgSn~8MGC1ppDs708GEE)*Y zFmRpX4`Qhz_Ou}AYl%!DKZIhI;(JqTwjBK5N>evq3gz%3(z|53wRRh9fYEwnsw}g8 zT04UZIHKpG?lcG#B6Cp|hr!->t>U&&dEK(eV{pjU@`AF6Z4?$;R}boIw7(Sg=;;MM ziQEJb1>W!JZdlvP9oqSlK{(YGZ?-_a8?#uI+6oZ#JJ`Hy(07))fPhQR*6jq@>plTuEC0Ew2DsD$XZo z4CyQKeQ^|ueq67zsrSW4gk1`I8Mhnd>sg|u-fhYDG8-cjcnPg9E#<=30Ny+2S)528ZE7xEFMc0=Rif5t%Z;W3S}q@m=&>eIdjp_Q`hj& z-Mc78=q-3nwcVKr_X*IZY=gpz3oRzdhziGub4Ir!_7Kpah4dY%iJ^?ZLRARbM>JxB z|0U#DB-~Nr{Qwh#UjZDPz{C&iw_IUTPv&2NZA<6m>X(VJNhX?O#8_PV7jTy{gZYmF zJaDkwmyM0?(ul;d7yvjYw?M>0hqP=|7vclt?V$0g!#22j}nUjqML1g!rp^ zJV+9mCBX2lwxBmMl~n~GOsG%Pk93CdSVJ2WDo)ocJ;gZ2?x(YCjHoi^bI%byi{z3Bl!YnmrB}hzzU0cs?D`g7;Mr`3vh$yZ;`7P^I1tKXIh?|{Q zhco~)F<+lkk)kd_Dh9AQNs>9Kp8XrfqL<9E4-*|n;xfP5wvDmxiZ!%&~K{xB3M5{$&D2ob-tf0-`X@Rnp!{}H=M%;dhO3#>gMQy&no2m6D zZW7dW%0ip>(DDR^+R0k^==uV#Wwoc8%aQbFdsq?TijtsC#=h#TmY$8PBC%;OW1nv( z3gIfV&3DCy_-c!J#bBPKi6Cf`sks@1W6Mts%q73#c~~xOpO?I7XEgmSpsaaH`FbQx z!au7IW-tek>To$v9yG@%7wtDDkXX-I2e|B(|JaE}*GJwk4DPB9oC zlGI9*e~Ts<5ZafxgRfy1--z$l9c|#o6SktYl;^kQw@#l z@WOv9=KVN=KF5J4W`EJ2j=}$50T%Q*`UP#qGgNnm;#I{WPXLBm$CX|fh;}b0 z9mk2?=w6w}KPuF$*n^^~^{2e!xqayli6snRf)#mtjT-nw>x!{Iv4~`P4itv`s_he4 z;m91a3r%sz5Jeqyis|0IjGeRmMgW4BSzk(Ds;BTFU! zDXQimS%w`R(VVhp61?4Q*tRlH3%%A{^a$HVQkQOQYZ2r(O3+od_Vj^bUXjER9txMH zvFtXNMZ?!tF67-0WE~xH&AN^5D|mJh9`mC;Lwpo68+vpQG)mRa5|TC{#R>POs|J@C z6^PSW$kIa`Ps;UUQQ8E%&O}Z~nWLNU(MDO=Syuw`RjbYKp4%Ty^hQ5wTr27{tWp;> zURUZVY*G-;rtx%vtk!>_3SEKvu}pM#k1K-+z#di9A%w8}#-obgk~?PcYfFm0Lhz2% zY7*xcx#MqHNUmo4m`UXjVE68IUpQBX4j=5HD_F zVQucPpR#8{^i=;i<_`>!BamW7yXI{YN_d1CtiOMs*IgNnUQD>>P)FTyL~Zs7wwRD6 zRKq-qB9i}(N3i@_8e-tNN_vjWCEG7MToEy2mn8eC2%D7)G7W!KQymUL9OzFnHbQu= zdMc6hZKYY$NE7}1NEbwNr%vO=KMXQ{=7N&IH2St64KZI@3ymTt>6cpFin@N5#{ARRTfC{*{Ke0^~uBHcHh^ zM0bQ}ra`zPOyZzTe{dbdya&Z9OeIG!>}S!HUij)H}& zpcsTkIt2YvpbmNQ;zB~9OCj{!Nbi*5oNJt+HW76U(L7naNYdDJgx9OMQt>Vd&`Zg; z*B|S$sWfd4Ep==0V>ZWQvb{`DghMf~)pUuM|9KwxWFF!uV8wDCqQpFbioid}5R(eF z_zmNSpS*+gdyd1tUW7qLQK8a@;gQg0_7})ty?QCdL3A`P=FIbr0D-r(BE?R-tRWr*qfQq@ z%AnL-ib@on&QW{~qG<^?Sfxs?gAk`$k!Gklf5)`I^Ksv+R7o$!z(I<^K>5vLDgxlP zGz&7^O6im2;tCn^5x`{>gJ6Wj)M9Xy#JHzv$Cq&hJ1d`t1 zVVpT;-7H*bl#G9c5v>+7v^zOM6d_2E$%{pl0%5MLStW!}^H>lnkvBj3cnbtA=#1e-GHaa))*87+fD&MDk6?VbY5IJju2m z_LF9jDb|Dx;#LZjg1aPm0caCm8O7o@Q$Sho=8g9#tq7Ma`1b~|uaiiUsUlF(G!nF9 zV97}t$NF;R77)d9BMoY)BD~BX$P@>1C|D^PCpcgee3GaLjPrC9y&l@vd(N zK|m=IG-K$ElF*x22msOyYQ-QEmm@K`^Bk|oa!0Y-V2}8KaxJ&6RrP0fv@1E1R}==Q ziYP@6_{$+nz=yiHWI8Fc4JDyu4~}vGbiZq^R;pt~hQBR#n?-F}Wj;iqjF)7~A~_Zk zGV(i210jo8zQagV4XBDkM*&(U4h`i>Xwgr^uBXTO@0p@8acs!-FI2mAVsAf}iIbL4 z+kNB~VBtkOY!^m?K(c4ZH1_)rB-rC8%M(wXKd#Fh=dNI}S?Ucvgxj#twM;IAMrXl7 zVCCN$>`k3s7$3Hzi2!U+yd4KYxG20@0pltN5X%7qsR-1E;UtTjNT7Xmow`gHyspW! zQhUMULXi8=Mzm7Eq$YZaoTp(KKtK+$CPS}v66}<&j_N-}v$P|Sj25|0Ti_Y$XfA#? zMTyjY#4AK@a_)r6QwYFBSrJB3gyKnH7=@ZSPS4qZ+xjWU29<{LP)gDQJ*7rYw@xG6 zkZKwVC%P>yG!{Tn5yjM(5naRR`a`Q{$+I_S7yiN>3QU)7GrC0fPb00#CeS>CSk^LD zAu|J_VRD8NX~MdhYds?faGIxO2SYhNehir#adT>(?JuK+{lN>V)f?=Fe4Lh)vSX#9 z?kHEpHmJ0cTLk5p&@-O&ZBRjxOj1Oi3iN;AdBi&>4X)Al`f``UnT&crOqaaysWrB| zlz~?D4^|s}vM7D2pmFX~mIf6$n&GDrWrAdoA{GKzDwbeuW?0n= zII^%p9YLV3NjxruRe$i0yiw>GDzX=&Dhwb zfH8yM!Uq!wj0nVuG!PM$*keWLfk1?#wRVm?ZnYp*h!$-3eH-Dh?)Wr*u0%rkVh`q# zU|M5_VsmhUQ$vJTw-Edme5_DER`R7dD-K6nxxUU(a6!DWhy>_qZiIn)=`!x(irju5 z*au=9k~=9{8$-P*-=q)|qP3J~_UWj0cm=wCC|329S>n-(ai-aA+Q%FpDJqC?Ad2ay zaaoagEfdTXaN`b~vA=)opPrl*=ytgAXsvg4;Zao@o~wdIzGc^hPu!&2%~ft%7}F5& zWl2j&O^qbW;H@X!=uolDG)a9CA|TLXmaUq%jcBe!M?o;YW%A(~Xobxw!M0m;JPG1^ z2#l3y;J$d`5~@BjYnLLx}Kt#d~tookIQ;t<$=9)wAhARlWqH-7v z;kbPo8%ePsL$L12@+Be}e#m`>=1NiZ$GwzwtDLX&GIRj+{7*v(dRbAuD3Rt ziv+l~xHWTuX1REcd!>mVG4U#C5oM|{Pva*BJjs%W=4C+*>mt*4@498ZCb!MM!xz*H zK_rys%@S#oEl69{JKc6N*N(FxU`(Jk7pJB{S{lHY$XP*>!?>diNeR=~xLpb=;@Bpx z8$u@injq<4`~JdIh)K%x%I1{Je} zLs+G35v2=ABKjhT6LoDV1<~X-269XY$sA$| zq>m+vx9Hpr+bZD__Bx`^$nL1(9Emx|HX{s@-B{{9$}}*k&M6lov3!FLXaAF_>P{F= z@x6dDN5I{P5RP*eEE?*qB>zD&L!fPZ*QmLZ%^1}!+tql(ljf;tCq>~&=13=)j|JuO z`k##(rg6A=d{?(%eBB|-zNCGiJCfjxR~5Ojp$bX_op;hUBTQ40*C?VOY4T2!e+wej z{9K-LfQ2-yja}}s=3@n_AtmCGS_a?o+n&y?*F~rMTIO~U)HKKc_*obuf=>SD{uBL1 z{G0r%{6YF{_sHfei;&jdichlv%RnW(Jf;f&Dw`oW+>=|%qN_X8YVgf;`9N`XvT0i` zo-1P-%_kbk>pCfwFM%>AYnNZ z5j?9>cgut&o}LW?_SV!~vj3PWcT{#=FV}VBA;ckF%binUI;L5nd`W)-Hh;8Yze*Qy zt0T*r4)j1lPkpleI@b_)LTt^)gywN@imQT~#ucblgIB&}-kP*;UbI}qhx;J55oOZI z++-zM%S5^D3WY*)q~I~ClOX~^JypwUnt?~bxcbXV9&Gy^^}?bOo}znDSJ?HcHyuNO zTOzDkQi(CRj7p(mRLX56QQOERah}o$N(C*!YYv4E`M$V8Ii3EyjGJp&wmau>NCNWV zxJiEP36ItLV*o~@2hm+ZIWAH4Bk7SLJu;1R0YH8!%Gfi-WFS;e&+;YJPWN7uCO+Bh zGbSR~{%f*>5SeG(zr+%O*iB*JsGi0x?1C+?Ko*qfwA1ZeY#K?bD>#ZS zf@I>NyO5ysEW?DeEbGoAB21x($w0dx#z=|fS;;&H0S7Xc^c*wP-WMok5ulcQCn)pG zW61CFi56}EtVpAwiXu$3SI-IPl!!RqrcuTDc=1rcu7+U548`S{ zk%C_K;c?|`Unmb{5+%6jF0lP4$$Ns5?{bcsHcYN9>m&1M_Y#w2sZ#|6!VsI#!k$}x zXIrd^By(Vo0dQx2E~5H|OlH(71cVvg<~8qsEC8<6@CAynKQyzF{KMM;#Qk$2fRwCM0lj38%0%#sZQlD;_a_G1Hq}J;!!Ze?z%Y)9jdR} zAef*3+k8A-QB%aBlK}Pmy9!Yn({$@7k^hc#%@z0b_00u+%8)}duRkA3E>-R7^=Z;T z8I3NvC$A<99af0Y@3p{;dGJ7w)_VSA zKom>Yx~}wZ;~>VE&r6BEV$p>Q+V0n6m8FF2$C8 zKy{c)TiW8id% zNG25S0(eWx{y`_u_HzmR2M>1K*SEyVY%g_4o`INGWYB-3=W?W)WXfb(u!NAZER&bd zR-=BrajkdfiwUYHbo)G37}w0gYQDI0JHIr?QWsJUYa5@-CE$e!@WuOQ(3{1<+xSNG zeC#00ar5FZ&IZs(5O0qozT_d*61|*<^`fgY$e*(pm97^ATJ?2d0-?n1k>#7Qs@L~r z;f>LX3RjLQgGmvVk;AG|EGgCkS8g5fL{n|zUtYlb z7X%>}4$Oa)%B;{L$*9A>k}3c(K~`h5=>y{mtmnad%F!aoJyJAJsfj`{n zjuld9E*8FzqE(H=#%QXMq8v<$o3}xPC6l?UULLZEH{li`)<&RM3d2~cy+M!xD%BT8 zpR>@Yr9QWh(m?+9mM|@y;6f}Bf>W7z=3h_pAS-3(&f)U^9%j0P))kSQeKzIUfiuF* zc#d`gfE2+bm@hh@-D&X%X+x-}3P$DlegR?|7gsf8~|7OZ{+pnBSOt|gACZ^>SFz)p? z(1SM}{h#z+1V_t+Zxg0GfNqCLi?j9n~VeM6bs6Z;<135u`}5 z?`cXZ5Pm-<3X<#o5R+HBiD1MvJER~MH))YkBdpgjqDGcI4I(9Ws`DGXiw6x*gx+ct zBMKhPwWh$Sf=~h^Qpt!^VaSGw6toMR`1FA;!4P{YL%=jT+lnn8-*f~h+4;8$FPu}n zU)v`N4{WP%lr~xc2~WS&j|5IT$k^&3+b+*!ld9zQD5*qn)qfvWlS$qocDIbgz+MTl zmc>xz5I<}Ku$Fw6*NRP#D2!aH=%)9}q7vw*kv|#{u7Kb%bI9_u<;23eJ@q7EcxtRO ziS)hGT;wKnu>;--C}QA~a}(@(d*Bq%{J}Vn@T##gV;Y=} zxtF#`*zF(Flpf}GSge>5VfMVfd* zpo!zt!ai-xPGJ2c9()h?-}>7mnL^gvOa)}-HIi)5gHv-wK>5~Ald*`U_4f<~lTi;oFX<}e^ry6KQ zMons^F3DmyCp3-FzphU<`iC2Y?%V>Gd1%tqn9LEpdo_Z3>ZFi%eGblJ6$`S> zeJB?qu3eN__Mc{^wdc(uEoyud>2XWY7?}aU7Ui_hur2yXONV2#(MV_8z8tm={OyQ@ zacv`%nam=k9C= zVP(79$GJTYk%9>)(4`~wys z2Kxn4MDUc*1&B-f8l(v(0){#B3JFKG<63Q5o>K`X%oy1+)x_jDARPu%M%7*30!a^wCcKk` zp=`Hox~Z=#y**Juh?)XfVK(mxK^+0@&`&tjg@`>xNrtsS6^;b$iHZ4S7Mx5UfgZBj zV+Ip2-uaeHE6c}H?I1gyp{PF%sszCB-pmpTAE3x7!Mq}?$8pXHt*a0$rQPxlCLqWCNXI^Zpis2uLUmZDw$*5d#Urvh@~3`)GA1RJJNc(KfOCmLL}n zNh&l5c@J96(BWwN9oyO9y zOpJZKiG?v96yrnW*CK=ozi>!dtsVzp`4`qknvv4kMTzn}4>7h7;e%o@zsQzeGfq)d z`x>s$e&BB<3aeyxh@X9zC#PE-c+#;V1LM50yhT|oRmohWMp+>K-a(tK0|%C79rX*K+`cC9twgc zQ&H+Q3$^LWC|JZrfXcNVmUJ{Yb!TUO5#2A)3ajT#B)c_KHicreWjaGCY*=pvh%l2G zs021ZiM3RML_bEUzN8`*2EO@gqM6!dz?S8^5KA?U$)NTy2FVG>Z490+3pDtqHIT7! zGRfnVyrOU;kl@bt<~n|zlTmE;LE?1r1xOGt@iU-10;^U!)^gR2@HkF$9xb$D55@G$ z!9-fo+y!?^G!Tw*R5l`*X!Bcy%}_B0*w%z50K#^36QYB~u!7^gMwuqKd%3y_QNt$I zRcNTvvizP}rWi(y7NiL3DZ0w6EHa1XeLt`^iO2_GfpE!7AgX^?+WrReyhj;~W5zg7 zLE&8g2!HK@(u%vpOMbTx#R2vws zv~YqFB;gU-ZElhe<(F{RB*Do$2fYNP&0mw}*dp@h!a%6m^U!3OTgpTHVVy31;j}A0 znM1I<)O$9D<}p2#RXveM^*vkBdyiUG2yg3SP>!@LglNjW7Km6Anf}W^-eIOVVpYlE z!JtCI%!5Vjna6RMMYy>e>R6PZz*1t62~uQ@u7qktX9W`6vi!MO+#Z59FzzExB|AC& zv6wUHAXM@sS{eH7JjMB%7h(jJl_Zkt)qGE*m1pr)2IRh;_^j)@F>`G}{$4 z8Y8g&C7MYaL7t@}E^RYIo7&Wtolb~lLn${_$nq5yLvjqh13WV)Vg<0}W(?ZrxGBK@ zU5s={s5>UrH}cCga0pjfB$4HKO z1(FeEmRPJY6Q&_s4o&=oI4{Q-aXA9 zM}a03YdKZJu(s`j7kQf>)IRY=ElNxfgw@zya2%z1n&K1+wm_^X{hP?yvcw+;ZREli z*rJCYmE8ubTxA$7CAxU;=b9U!MTwF2-$Q$4?db5Zr{$HdGwpJ5B8vdL6c4QfXe(|? zMN(Q|CN+vMw0XWla)v}#FU=yk%wAKRUO2*y>At11hfg8bzt$7x@3{9hy5ZY5rk zy_#0S1<4SKFo6|n90y`9#8kJP+8WLcteik!8m2SEjF?q}j_3GaSQWph_H3 z;)gzIfr6fLFUz6%yAXGNv{W+h$iyqia<2dI_7u~poT9Cj^g6PvBwajxoLUA>zN zcpUK|gRCi~prp#xv2TT!F*ffmM<{NLk#;d<1*MHIspHp%M{EsKT$4!?htXW&g`0_< z5T{ujxN1(D4rU0P&6&n{CR8(Nre^Yx(uh*1v*#p`-?Hra*C;NfP`no`w1jkh4(+cQ`@LnBt-Y4nix?GPQXQQBpCjm||d%SrW)2`94e( zP27pb$HQuN1nC)qXz*Aba!5jYSepr1Wna^BkMnienr0cGPIDcv>QlKsAY)?NKxC_YsFaQw2XIL;7A;0!X) zx{yfk+8~~!M&TLNdr+2hdn3-Q6Q?S!7_9znwC_-6AVS+NT5PrZCMDwUoKCd}jdh96 zk{!cX;GYB>u3ho~K&{VFZ?kv0HM!}LCyH$4H|(zPsgQD1(#XXogW-OKoSP=N5#a_& z>ZTC`5cn5?&D!H7#&2ZNGM^dkK1qKl*9-b@RYG5qst$nGRjJW0k_1|7IhD~)tmdHh zRx1h(3y4yL{V7*C4YmUP8Y5)aM)mhfer6lHU3Ouucts$(6@+t=_gRkDASy&qLk56( z789vKC9)%^rQnn44n-0Qj%eYMS-6G}L8E<9OphZoAJnmGz%rY%de-J|2N(K6>Cy3@m zxJ8Teci!R)&%Xh9CAC$;f&6L{OUJhERbl$WaG;9C;cSD~C7njo!#4TtJb-_qVYgx@ z|JAh`8r}(Zk6GpCJl{Xg({_wX41pLP$npauzH6 zLhZjRS>y=A-BrOUC54e$SY)qTBvIJNj`|FtQK)r zdVVFlpeK^#Z`Rj_uO~AWG8K3JJ94rj3e*N>|vK=6J8L9GB&{G1yOGikY>!NDtbs0wB*fj)Gu%XL*iMT`^f{_PDrlm$o{NE^TR$}D$ zNwHsugvYY^N6cBdnyMQcqG;koA=u*;C)wB$iOJOat|#TL*<83*%?-t=&l}=_iIIBy zcv%&TO7OcLWQi1}64oEh;T$BcD%Hr3Il6XHSa&kZm8sYAC10YS=NjMKv2pzJF1E0* zEtEqT;9I6ybu=hpHdo5$Fe6R{wx>AlI#ixZ>(SSfA*lX&m!h-~rdwq`Uw`c^4$(@5 z2(`r=P2qc5zC;F~u0)}{wZMiE09FQMFToa8lLT7F=oBg0A-7dlqk=V8N`;B-y~-lJ z$`->W)v7Se%wv#bS709nJnNTVU09tz1Qmbu^d;f%A} zfjm>*BngeERQrv_2NOKavfe8BV8^8hB9|w4DNR=fuOin6u&mk!`#m(nx<1%9k{3K%(jQviB@9YzWnlEs-VR> z+Zc2g2!?gMTgk-+mbTIJvVSH)P{lxfa;2>=q_fU*QGc2c+t#%NmDKQx?h6ZdX5=ml zdWq0bE;fnyk=tZX+H<(`sY<64Af#1{Hc=Wwy0=^E%jjZitBXR;>`LtEwb-eO4syKQ z`&5WK@e97_C3mDddpqlw8=@wR_@q%LLOs;o=j;4c=UwsoXSzIE+_a8q(?02qYv1!P zGEgOl2^a6}QP`D#2N{P!ilrvm?vC~{T-A{RNs7k;R>PBjJ{z89xxBV@chaROoWK5r z-ljN}Bbx@Q*QC~>YmEv1-<2Ak*ID;rRF}Nj9sze6rrohJWYdB{}}fFQ{qr@w+0~ z;QRcs^nQ{T>Ru?Aga>CDb7vRQW=^bB@di(6I^{Mq0fenwx(d4d&1lHZ8pWcpfEY@sN&!?qx9FW|*SGqvZX@=K(37GxfpRq9;dDVKE%zig_H4 z*i;Cmd+dB$xldyIPp(`Z+ev3G?W{EYclalRw<>iW75m*LV6xF7Ebixt?Igu3Gl$Z8 zNQ_)n{4Di`(xm!9`?jGQVK*d=x|LB{#uaL;7y1|ZBV-!9u2of)VoC;H^dO3zT)ZR< zVn3oQ)2`#CLo}3n-TAqje^V7o0=T85Z<9ZaGg+nD&3am?smoPCEm~I0tVycKgF{c} zqAvzwwC6_j4`Lx`?i@T`gOA@&?rdVYo1WR}X(zV?64cBR!>H}ytLb%QVSQ%WMIA7K zimkS6FwZiYh9~rkVw0pxlU$e0Hd+!dJocifbe0_CCnbF7QndJzF^0IN0}#Q_nQ1|L zNYXWW*+ECG&Y}@)Qle1-q4MIs!DV#LJtluFhr*lj~(IkxnUC7MNfPvpk3$Bs%*vN9*6r$U`mtP!kiK5yK zgf9;}k1=%hA8QSFqLVmxA4;#J7*$qTuBOwaJR7N}ty7%X1ZM9yk#m2noqO3}w9c;V z3w<=1uG#5axUQWd4OS`>9r42Lc$>kOSA;B{`;yiU{7=)Ytc-~T{KcA0fzFqmc+%SY zm!mnyUUdP&kD{WWyf$X;o2mARa5Td{Gowg!5Jjkt{K$zHX(r)u7G&^wb_X#Gz9r1l z=I^*t4*!@SUGTAr5YBzj7}LSE`J@a)>NExMR7L_CtIJvOXa(wLbaSLVR^=7FJ{a3Z zfe1r4MrdEVLz^9puv-A4LLas*M(ZfIDvVJU-ur5wx=B;z;zuJ&=P*KsD8n*`loz9P zXN;h2CI0%HE?+tnny(o^RfPQokmeK2seXg-L`Yo%srY6fyrsnaNV{-?wW>tLl0jWw zQGy&XL%n?*b}*a_Ozrq<^RVJ%=@gn87s+^^43|VNiUYKA%r@f-ut1{$LyELF?%0P~ z`nNRx;m5lkYKav1*AZl$AcOK1Z?dpq0bDJSJFBAd9Mq*RRcvprj=iMvMwBeUMltG2 zLMo+wkd3ANd*z|$0~ zzeMiJVb)(6K`{``X9=_2)R#K&n2 zJiCabkp}$<(iRLQTuecn=(shY(lI8c0OG5MnP$O28gke#unaxW!Sp!z?KlM0i^j zVs1>=B9_N%I5g|YiW$k5m?$e6jiRl7&hr>2W5IUva}~tAHGrRAB}SzCo1zryBSrlT6-|8)m!2 zQoKt4gsm^1%cp*~^RF4IaE;Xri@rZ2Wn!SIu*%jH4z2D-CJkC5aCz#I4Q)0!Aj)u1 zqjwa%rI8Kr&Z=<)X$l}&RIFAx^w=vqiF}tS9q|3NP*%=Jo&>6DE-VcrX(}@ zqx``PZr8AMMm1b{pi3BUUNiJ$^XvUZE*2HP3_j{%TPH?+% zIG#=b)T>~gd4_Ewmy(`UFN zi$OYAW&SEF89SmBp&ep0qKCd67khESefW(+*(yrmO^y#)028vKeJb3USsis&mcLuOpv@5{TqF^?qv%cqFThER( zi=7g`Y}~IRA4Bs!%6R`3#bv&=AW{g#0E;C`|Jv~~bO>V+#nNc+!3~#KW{?(G_4zD3 zL^Ir@g4}{}KlK)>wiY1}Adsr+V3nPVijMIy2a%qYpl9U^rh=+cB(gefO7VgyO_bLC zM?7ghTCUk*cTyi(Nu=2Ng-en~Y;(d>_xU1{tCmb7?uxb%e-*v+ZrQ9gJRqYMyo42p?y?lvck;Q6jv*SGU6RW;JR5%5H->?ikU>!siajdcoD@4pgvkVVnnVgyum$z zM~Hvt9igjJUbS6Gt>qzzi(YCLVTk(bAzeCbTmb-TA5)ExkEEzOy{Wxh!w8zLY$`%rj}3djs)4Dvy{5NCVi&OJP8Bo&N1#f*;y}bPiG)}5nFvUI6cVTwHaEttRSqni4 zx>zF)MY1MjpDP0EnRRN0DU}c?Fvpf8k!XX*C!j!_NFR50aPd{{`m1%AC$ss%w;$7op__p{9DMD3Kro-%3>l#x?r8)$ckNjr;PRa6oMLz|oXQOL|QB3*ABHO_kZYT#c)TqV@RHp&P66U!6eoEXP5@hd^Xax&;T z&wX4*tJ~F7K!4bC5$J3}OiW|RCnZ`zfW-1^{Zej2Ir+(W%V8^ui()^_g@#g=e(bwr zh$^6@9KKCE$`32u964Bv zuAH%GKCk8)MR6OU1ng9!kQL=>Vm0wAwXFBiA=IQjC~WG8X@G!VJRFfk7^NM(@QbRB zSC5~Zu5PlE(fuhbTTkMuviOH9*ZIsErurV@NYoIK_O#7kN@_^MxxD_+ zI7u!eM}4}#%pvfW3Dq+o$M`hQJJ9J~SsN>aP`xy;&4YnZ8$g!9D+#oUpz$fD%Myah zU-3?olydOs(wET*ra=+?vXc5utzIZHCqID>_&1btq*pxxz>3{DLxhRX@!XT3+- z4VOH_c3Q3o_xaZ|L85fxn|f1`?VdIjZ<0QN42E9{1}*f6)8LoSX-Iv$Fqn}BN-le6 ze-rRX7MKUyG&RB$PJ-WOmS})!&GB`iBWNZnQnQAh4ixGDp!O4&P|FF=IrEK<)!k8% ztJ~e^u*)C+_*obvmrmg0;Bw!b-MZXr+xXm6-a+Ogk)%A*8hB!FoWEm1{w<3Kc=-xp zI;$VhsfA2p$BpHu+@1wsp++n6<^@gs|KapFAv|ythhZ6>sdaWlfu}0DhZnHdgJu-a z{=aZ2Dh*A(z@0Q@%ME){S9&bL7!06d1Mo1GA_~cv@1w1Jpv@gK1jmh9BQIV6a<}!$hnUB z39gxi`1>u@CQ50diX^u=%mla#0Okky6NA9xHnhImTc)HHp#};7EW-3ALx`_9$pT2D zKg;m53&FY}j$~7yRkQCiQF?MbruSH0p*syosZ8z#p z5h4M6Uh3%%C8JyB_qD{ggv>eN+YSk1Ol~&xm-i6I+sH|iD);M2XN?=&fDXj9q3aB|SWYPc)OLMr z&Sev&xu%>!TlXfym=(h0eU3DRmnR_+gFaYPm3jbJin9b+6J$%}y|2R+SEAxCPje8+ zPf!GRLbCk)x%ZrZ$6O*~M)j(6>%}%Ja8817Cx@za5n9Qq`DOX&Q$%e8#7zg_Z!)o1K=w`C^Cr`RXaPT&HYS@=Gcq-`ah>V{lD&KcKvr+eIxj>Wu)qh zX|K4ZpXQ;|yif>xu3*M|va)siV!USyFt-tc(P^6R*R+n$RxODkK(j+3kBKuRrqotS z7<A?DdCeYi(-yuwOA2vH=N9WvkJfX}=*fr+pIbl-ff71K zX=t4zu4-yiS(yAeSV6N(b=e%>v?+@UCFK-z#8ktUw}7n!`H*a8o}TSfLxoS9QhFGbkj>X_C3vkB2Ak_BPFE8uIyhY$DWVP^l?eo z;D8rHtV$0BOBq=4=;qrYvKruw1wgkDVpY44(_R?!d*nEW$RWY-IKoKdEenMyE<(75 zxRes2u#Ghd#CFJ(y5xkXuxl!skd#&aV|kU%qCGB&W9`cAWqCm4YSBg}g81AL>BL)u z%hc3n{Ud~S1_-q{mI+nDp0?4oDKj9?9HtTGbC;|I3Gp4f#ajczTm8w+a%Fnj}!oZ^fx~X3`Mcx&Kw^(hgjshKKQY2Q3H45p!6VVSJa7jkI&8hcXFEwvdX}8~cj!aCO62$EB z7LTUNNU=tg)!c}gd3ht4@Fz}US#;)4TA4`&U(ojEPfD2iB{BXPBVkvybvrdBF}9eIpGm!cW0=48l8_ulYV4;U<61i4bn)fd-yjL zzHiRQVy?U-Wk1iy(;CYvTg#jToJq*ZDZ;lp{@DYV{rWS~PQlpM-t%!LBglu?wL`O9 zQ)=k* z7J#$tOB!tM^Xv;b$(hH}wH;YHe-{srj-Y=8@tO%BkrRT!Uc$-UT)o;tNV}b)g;Ih| z+Ww7|#ps{cHN7{nnpBsilf!%x2XSPb#@ikJ3MIEkyECj+vL*f2O&4?Vx_c+tz9~i% zZJduWG(unZp}6ylCh3YzY>uWDEt!9p4&>}{` zcqR<8bdXo!JSlEywlfBxy&J(+XTMA3p527qqFU*hg6}1dmAlcPsokI-ToYE3?A3cW zLK4a^ngc~H+)p?5ofaM3<0lB@GeJU##5JirZhW{Df-E`%NG!uB|2PZciTd9y1*v8? zj!_J8+@4iSEbf>oJjdIWioK7>aQ-E0*PYS|6I$Ta@mBOM3pl>Mbhlnj+V1*m* z5MuK*<;vuKA}f|ne7E_@3%B@Z)#EZzr2|h!bk{gWm^RKANR>n<3S+oiJrvOIV^p7+ z2ytU-!JHDpNf`cF)``-@VvMnevU8Cw(2d=8j@MY`5T@Wp zETn36@b);p4ulFyx2=YDy6-glS$%jrU*#EIDn{60i!j+O#K|&wo1(_(+f%}Kp=i&N zye7tZLw+Vu<_>8JkwdJ{a=dq{&zlRTp;!zC;FNGKodmpc|5ziPi2@r-;DyC*lj8ip z4bwDWlO^q$=0t>u`DTl9Htge79I5)f`+J)v%Zqk7b-&}5@i7Zbz`_ZG*e;$)JmCr% zz-?JK|j;P&MmTh?Y)NoFCIgZB-vza?* zx;5k&r0e>j%o+(Gf)d*XWx=DaGWB(!6$cTp#BllOvd4KU5@L^q!l3n&M?(t8{nfYM zR=dw9QEN6^439xjPg42P)Nb>AU(YsYIj~SMN{2()j+J0}WKKJW^twpr3Cik0t%P=) z+ao9qCFR{`ZF*k4QoH}|l+rdp*_&QYM#E4MB%)d9UOA>J^qw;o$2{U~Nnv*5y$+Qv z5@OQ%OE*bn5Wy-$k|ZjZ21DEw6iVDOEtVBW&gnUUr}kpYYd;@M4GR2^$F_?$ni4Z1eE zSE}8RA*U6@h;h);?kP&MYQRmgTTDuE;)06iV!lp1Ew!VD<|)LWR+mGdmPjsGHdaMG zEKFl;XBS3$u}{sLw#Dr_clV7}e~?uY;zCq*hFL-%{Ld4s$eghz0WH_uWThkBS9_70 zk5V75%JPU%?-~MJU?RTSI)dGHq0HhP?0C9cE5|i6gzRD66HCK^L+3O!Cd(gL>3dXi zK?~3A7!7?YS))%UdhU`(c0~U44zGG$_Hl_orVHZShDN3C`pGDD$ibrT7fVcaF&I#*54DYsr_$47KWFdtxzO9N#g>MZkp7Z+Y=J^ z-@`k&)+N_yjxvyit7l(V#SE41^wjt?03{!Qc9H96~{X9auYHYr-ruHu%-ns!B z;x(_$S2Jw0n5cgZ)2{nOzt>w8c1}c+qNoxh+Sgq3^cw$9n;1fz z!nfCkc`YSAn+?T7Q_d_f`aMpI?zcoM-$E}|zDeo7MoxjH1`IY*G5kIYGGkfz8@OdS z{NaFyFHXkHVFQyKG1Z+3?*RJuFbx)zVZ{W+aFaz5es#X_f6!j%Ixp8$(HdzoSpRi& zQZJ#Mztj-FX{X2&kYLg;(u~kK3On^CR0-ggF>~8Z(i%yMI&=x4ojV#e@QqaCIp|4C zmes)rkv<$2XsyWX;fGiz7NA%{_g$0M{{#{md}Jpks3M@|y%O*lVLj0%5V-*4 zPI5JN&r~;*O}1g)KiGSCQh$an@)r5daki$m>cEf;aO(<0(zbg?6 zEdd z$g$nJ)I;A_*uAQk10Qv|@T#S=4Z>Ov0w zn@v9+F|8bzVfvB&4=B?pgN76J$#K_VluEfjm7CyJ&S|RPJ?$sjq$H7j%v~#i-_j1p z*I_v(SyK&cRyBT`U~cl|w%wl_Iho|a>Mpof!8?Q9uqt4OHQYaACSKd7BH)h-<(i`W zEL#*)R*QZ?Ao7x?YW+rkZFM2NZPBZd7~@WWzErf3F29oN^b?cvlHRnkwKaaZZj`5O z43nGcaSZeVH8Sr0wK=Gm#cx8GfLNbhhBR+}h^x5O1PAy<2(sG|(&JO>WmJOs2v&`r zf(>Bq^UJE_Ur*2GggM!A>$-ei1<1T{l}sNlQJXIZtF%m5h$6@WhAqKymA^V1t4V9+ z!qXV|MY*nj;LTYVfN%!kU)u{+ruR*0J!m#jp)K}KMaiUzU@|#JdQKiq*z#LW!Z&^5 z9F0{vuSKkK;36{(1P>#MSjNORrK{C#w*GFcXm^Q8j8)}VGSI4``T2b%HP$CKR^Xhf z4P(r1eqY6wNohN9(WeCRf_S`@GjDipFjaKX6ch{hwIr*pSlO$5N-!@HQvbhq2}_)0 zY#CjPus(@d>IfTc6Xc)dxcPG9-@D4%qS$*3K}yReK}Psn`YW>wT8V7C>&z!cDT9(JWjRPkQ9V3FO1^Ni>&Px|Et| z&ucyldL|4)i#4dlq{)^79NVBfY zs?Emt6}QP{dAcmZ;YC8Z@ssZ;aUFyoLM60sEEnDvg?_SA(}uh(k8wmW$jUs5dC`iz zi=ZM};n5*yrZR_oa|1y7KFMcklO#uqM|-dr2dP}8U?-HJe9K8A4^OoQVTWhK; zq^L(AVo70W4##!{Qiv$(oeRoOn z@wmikSf;vq#2y{@j5*h=m5=V5E3B;rqg*ElY(1@CghE4Xamjq(#G3oagWvBcPV-9r z5ee9kDUKTkvwoB1(cEc~!7C7wLT-2Cnlh-*#iT4*r1@%}Y&z>YCjx|XnBoZNAtD;u ztZ5tpVWh&=Gd?IZam5$)gw@_iu-zN0q6?sxZK5^=z=K5=&S_N^aZw4FvyNGbnz?zs zHfWMT^5V5lZl}z-sKgq^V0&)Hj3R22Uz6_qo&ZDsE&{R8-viz2dkqw|rg}>_RBe{~ znBpa&G*znNg1)sf9i-8URq5QHkA6fo9!=DN021>@~U7NUqP=7bNhNW;Yg+H!f5@j(MZ}CyqH7Y@yM9es;i;@1RMBH1CGaRUmQBt&H z_yav_WC42Q&-2lWYt~yPmJr1^q#K}1u6_J6TGJ#xM1wO2x?US6d+f|?;;SZFx?V170xSgO!D0;>cJRpM@R;S z0XG8&0y+sSHG|J$0<$_nK&piqo}Tf@hqwglKEaWo!s1mTdTQ)&pqBB=77nUT3{j1&1nHa{s)Cne8YfYHD6**g1yX9dd?zHk9p5b22j%a8Du88IWxb+>h^H!&InRY4n9(X%= zx_Ei`Fn65u4&&N7SdCf{5!Q%d$v)CWl5;oHcYSL2Rh{QsTW?}5+(@S$DKpbO(ye^z zg{Y-8LZj|q@3-9gJO)LjYr4i0i0!FLK*%6IEkcu)N*Nxa6FOmEi#l zXiLwzGZ4d6O_qiKx#u-CU7CLl0L6`A{5t|xW)G;Ai(F8dwQV5AMHm4X$MPyh{+0iivWKfI=XcF_-EJHvhf)+{IH3bS__e8F)9)U*| z!{TC$i)=;-iA55_)L{*2tu}NB`VNcndz#ZXF%S?v=urY+|z z+m!bGt$&@e0@^;!^3u?K^@@OX{I*d>L`*}3%+wrWXi^#%o!=+K>9lTL1{E^E8O>vU z*go!u`2MdQ^pOcgk?VDIeO9L+RJIA_6C5MXf{Klz#EH ziNTi^9Vc4rsljd>AxJKTx^RY`Ftmm&6R>Q>>?LOm@S9PiJECqYW1jn;k|NgqZuDA; zSGQQ_H(9m)H=q3Ib(ieJi`mZ}aep0AD>bTw8r-TU(GHWlT*ih(y^E*y>wS&S6A+^@32;URXfr~TUpUoWjoLJ)I)YRhfZ_z0 zON6kx5rmn%8-T?F02qKq0a6d3vj|c=m?9M~=MI5ctmEnu^;+D5S)uscCeN)i*Ma+J zNOS6#EbA8OpX>gg8Dl6X-B|Ei89(=+PeYImYG3YF=?=J3+bfe{C{lG{??j}`43tPEuCf)fiFrGAzu0d4H*G|! zh0C<|4&=xMb)|GC@3QrRuG{;SH}jPxl5Z&TYb@6*FC>=8Mc?am45u+f^Rxl@rqUrV za|bgGO zg0f8vd7~)g>Bnu|=dDp|6ZC0{VK&9p+b^X|fFJPy7qQ3~@!S>x3NvJ6ksgC8ASFP< z8RE?IGYHPn{8TT0pTclWy9dG2^wBoMusy#+?sUw1MnN-_ZD&}JWP2pa5M-e>Ss8{= z68zup4v7-um?gsWTo3cGi#!By`!~-uV^x#!m9Y;Rk*gAN4?m&WXxx@PhZ9q}XGE>9 zD{%kP$jmF*M=2~$nI>p}7mIRv5x#UNhz(!!Ea;*CT>OU5&s%f6dE`?wWx()O@>VCK zk{^)bhO{g#>n_UEc=Dcgk79_u?-+!d7EOsIWRzjVL}bQfNyN1HnDgRkMFd_1QZb?a4Lqc{KFi=8z8Bmj) zGWN;S|1sLjI-Im<{~c@7v1@w%+K?1Qk=@Asi~%%Vu8;~k640{zd*3S<%RNSG^}HN*?Ji?NNJ^ZY z3SW$&JRwcyDOPQhf|Nvw6X|lVtR$7!EvD3!y*b&YV@N@mAtox!vt-p-5@{|Pp?a-y zqP3{(YHyKR-a9iAl}vBB6lUW~f$N?*iTMdG@bp2}^1B=a5k3+b4i6U9r zz+#w-qFmE>EQx7>G2tg3aI%N=P)pgxLe(B#IzePWHTkU$9)P5-e$q>g$CVm83PIA7 z-c3lzznM^jf-)szwqNQDzfm^lbgN{~{!@CgnDnI;Z?Xk#M%uE*X2pbfM!Z2wiyDNf zyB2-LDP#@1z~AQxe32`OBDwW{bJ2uq^s>l>%Ec9*&2jh%d-UZH#lb#M3IhCUjKOvs zKK8kQXb~LBTMmL&V2RFlsm&+_y! z0Rjc^AD|MTE5Jnp^fe4bs!pN7x_FK-f;>Wy_z?tpff`W#Y`=7g?O7eHb_KFj7;cv{ zIfR*VP;~C6r`<6|NJ|DdQ-qnuRV$Q^j}If{L5R{YghWu5)$1;#>_N*rnw{=b|4&UV z=kq$pOz9ziOj-iO&EvJY3UXS?n46o@URByZ*$Ya_`?}<){@yfk#6=cF!Vd7b zVI>&QuZj7y@z3#?8-g1?u4sJvYETZBzq8@t6+MgS&=u}nL--)oU4e-1Skg^%0;qFm2Jbi2x4s9O8gk2eF zi5U?Pl7w71A*&1=9kbG;q^Mpp$%@HIE9o?!KAW{JD{k(lXwCCL=M^IO+&kE8)N7UY zZ5e|+TMj`~K@jAEU4-{<2~f`n(C7pa{$ixOc7@$9J``4$g{ks+DDUQv9Ii#H*6B1~ z8*!Co8^cI?0$>#&y#)aH7>Xhzf2yJeSWt#oB?mayE?H%IfUy{(2s(p&ZVTsWCFh*e z#vvtTo2}V*R*jN{5NQ%6b4>|JU9(0vA(sX$ETN$t)4E4(bPD8iA&A+V9np(>_&x%B zD?p47AV3Asy%EbKR>7K>D^oQJjE9?(t}>;p{I7p_*C7FUONo~ZDCUmIO>@cnw&?Ik znWZG?f6i|oy>mIx{a=NHKH@59`)N@Q5FuU}BD}UzC5j3vbW~XE#z_sV;gtpsX6}-b zE?-?*-(3~^+3Xi&s!@Z!V*p04c=Gle0YlQ&FI!#WJG zv?a-zD|UDB#7_IrQ_@NRQqVEa1wB0v+Agyyq8YND9b}R4G>K!ReUoKyhcK{(4oOe- zGj#tPUbGaKQ87ft@>u)ItI+bcwx6^m08t;0p^JOAVF&yW%G*xcEr;W}zO-X06{51+ zTf1#Z#l8i7ZpI1c){LX|F z9%-p8=rDQ|5Xcv1R1^b`r_$jp<$FmYE==JTIk$_(m@8FiD}~{q)scllg6wf1L-Hgf z=T5N76Hu*+5OfH{zF;%mrIB}5ED6be1k{#))qT4~3>FJ1A~Z1MrH-T`l$ETMwoD~L zL{^3sK&Q3K*qO=Ls&!hoSl$Al2`y0N6u%jw!P**~c^=13iF$ONO{I#tRZkqWw8UT_ z=Fxm{kj$nhy)vDVZsxS9CuBf~s6{<%T-4W<^G(eZKzc`PUMY~%yK%dZ@L63F zdm6CM5V<86^W)9Zoi@E?82aD#8&R4LnDUA~sVc_a&HV6t4fl%TRTrvnuF9|`@?y0D z=&I;Xif?3M`vy+sIUbZx;0mIGMAlnvOIZ75Sz&U$P*NkzcdKB?*<=&-)E2hLJY8j6 z%hGy?&0IWeR#I1%ePP$Wf-XLS&c*hWI!x-Au=tMpuP5icj&2hEAv4quR}A)DxW+q0 z${;#xD|+N3FthO$>ip}2hj63^!8AnuFj+^X4y8>vXZRtCUV@oNjdbZoqfVwK$y%jJ ztO!@XLTv&qiuxTEmIq84ZPJK{x}(V@Y06~?gSe4EO=AHjl+&2kt1dIg*kR-3kt@k4{B zrj(gh^GF2g7?wnqpZ&MJT|=QmMeSuCuM_VLQ_e+FA^O<$gIBeqCIqYaP7JcI!XV!8 zZf}0vlAWhY-ZI#VZyLqvhp6f@n>odQ)vPd05fWC=x8J~^>(W=ugpn<1FV2-X0)@%= zY{zui#-=;nC#_U>6?1a2UwcKZ$zV(?+q(y7783sHBA7e&jDpGQ@0UYu$6@2cN`T*u(^II2;O+vA_Pr7yX@Bd6{{c`;k|6{wj#9zA z3}4>ox2s|Lif2@ zCUkvLmb&E<b_iKbtX<-%r{Z-1?|!;+QZ$*fIk){mBdLzo$I ztnPQIg+@grOWpSE*XJtjX!fUr%^D)gP4@N9+>2WLiXgE2EH^k!^FR`E`C?tF2t+vr zjWjjKrslLknHvii^d}-n1Y?8M0%@l(S3NWsYX#~REh3J_=$w}yuc@Mkn(c~>o+NY? zT{Le_R&Dww@%gF!bv#9%H{SZ{p>3WS$7vK+^BiJ+Kv24JK58;EQAiAReO)2a34@B&ixe zsJuE})Zj~tKgX6VK(bW3P9~j%n^075*#;=82_lJzk*dGZC%;tMJ2Bxo-OOPr(Kx4X zU^&M8u`7bOE&x=eL7_|Z(8Gfz)doxHky&qQW916*MfV1Iudo3(d4{s+0Y?OwUB~?A z7y?SVyw5(EM>R$wQlyzp8B29hkpSA;86I+Ra z1#4z`(2$Ef((>=&P($2qP@X;l`{y;zDoVnsb~UHu?IXV4IGHM0;l5cWTZpfn-U_-W zxujp$9+mG<)Ft2e4`_%u{WMAEr)mcl`*Z}Zjae0P69ktB*Zrm%sR$`3(@isowU1r> zs`xB7>!|k6HqWkGwWW(0p?E0eM(Qqsfr-pruemCt(gnnv#SP?L?A+dW9pRjO$CG_Btu1wEr*kV3~`HTG{HHEpqOkffw<2-~Ph{sA2$$;x7O_k+!E3(;?@Kd6 zt~`UXb&ck22(}A}o2E98NJch_zCjb4(*_j|LD&y6LWJg#P}4HFMpz@g&L82st}Ar zoQpX4#Q<;DQKr6{s#rRghI9jIF(Loi4Y6q@ErQZ#Wc;;e=B68 zZw>mtG`nRBvNYD8W@U}zdZm#_QYwGVR^%J&_Q^u!8>WdWq2>Q>xsu&;2_qoFBvOuK zT5m%OQS&sWlIvBAY4!d*KC8RR=}skjNlfi>AQG;(U(ZLpCaB3dpfBh6C?Pc)Lh32o z(Ubl5dHvdt_}|I1$>0}*BqwttQVYX2WN@Ld z*oP#1zghthIQhq_CDGc2-Xz@4P_dH>BieyHt4DlsM^Fj4J3-C_;p|`+Io7It$NiKl z`hymVpHoVEr zX4i6#k=?$}A-4dAfj$Q$#f>0G)zm7PBA%fapG$FGv9~cZo*=QgYf&%w@jA=D_CH8V zoieHlU{XWe8sjDuV8@2MKZ*`XQ4PG}&zx5~jF12P7ovJe43tBm9E%-vixsxGrsPl1 zq7mRP-Jaug^4~FE%ce5oVEDYHMGCOZx-u(843H1``zdIh51CWqc!$JY0u*4=LAn^h zt`ej76MJ=4aGmDD(~{PNcB_XqxIfyKEk7|cgcc4ABk{DlH)3(WnShSZYoC`Pr!az! zddOnRKK4s!tvEJ%xc#?xgrbZ%tSk#RbitU@GU{N&$P{D-f1Ku^iY@A@76+EB5;_{^-X$L+g!E)3!@G8Gz;v5@{sz>0-5Z z(X%?{(WXj=Gjjz@|Dk^~W&~Qoniv!Q;Uz?kp;~|WjfA=(*ViEDrv`Ikw-ai+EwcqC zlZ_S$9*dk`CBvws2W3!0e`Z|BrH}61>7GE6kwm>E_xfWhPfOzoqGXKWrEU`>L!H~N zt>dBcRkR1b#u~vT;8;d1g0P zSV7F%M38n~NYJ$l-EU%%Mt|{n4da<_Hb4BmQ+2mSppL6RI!(4NUMue`&jKhP z_JiKJgg^3sC{l80Vhuq=j)fTGUa&n8N?AONbhQfkrCL!wFxvNel1dgjVQ;-NF&-VA zd4gya0vEP6VfWLORH#REmr{Zd)7(CO5m^aNSvpKi;@E>7D90x)CO}cgmQ(WY{+D-;MPQ_OF&Lze;vnv&$k%;h8X3SU2MUW_4 zCwo0aUpSPj_|h{dM7Dri4QPM? zg(39sf|^Hs5nOa?_KeqD8Z!ZzkTZOmr0iCl_6?>?*vk??%$J3s86dDFI~FP{16~{~ zq~PSI<>`&4my+C$D2n@j#MV;PIvn6@WbEFBlBPPw-IZ3Vb%-t1*1j==!k`zIajVLy z++ncbKqtOcaJeQ49$=u8fcPbjrI!cgz_&@0D>_9liKeF63{z>;JcDO4%)?uI@_|pq zH1pcZV#CD~bKzD|CQObZkesmz1omLx>zZi6bcsGTOUi;`HmCy2Ro7ppF>()#c{xSF zIF>lHY~o{vw3c^gtwoHoopD8!gj=9TWXfHYR79r)jI+}n*Hv!vbmoapGmMWX;sRy^ z=~!~SC4D%gEzyRX(S@uj)E>`iEw`>6!95lDdLW+Td+z`F1{CuuMm?C-)=p+v133Ip z)l#?<@ii`whRqFY-9=eabbyrm!SEvwa8tvKZr=!XQBs5Ud<89bBPVctK_Uvx3Tiq+ z2RA5WKnXZJ88DOwYzIskB4QK3>D%?%RpFCX+m=YN3h*d(JMk72k)jSs^a;A4w_Do2 zy9`^N0bwd;K`$6?AeP~b+$^X-jx`_F-Fty zQ!82oqf^lL8y1iC_Wh=kmeUkAZ|uWDrmG@6hLosOyl1H&-o&{C5DCh-wQ68<8M{L~@hN`#0Zp#CwjiKSW)%T#KW3=EQ7%76XCb>qA?#rN1JPU(AmB~2|qx#BFDh;O|B zF&F#pp}~_|u_=1fR^{!J*w!jQ)|R+>5~4?kZY{av!Yo@BjR`P5+&7z1j#1|1vCNg1 z`K1CV#43X)7-LXe1HgeQk=MduNkfrlXVVxsytYHTaM)z(ALBZwZ7YVRktVlXf&b*! zdkyBpol#>t=Qm1|U`QVM@}?}Rn>6NQHj%MQAu7?LqD+dFbrEGEd}3&q?^A>{m^{;d zj@O)AD{%i?PIef&2eE3TqK)c+#9gF1&R0xM@uW37*S)XS;acaKJ5C?TR6!@EQg>)`*h(x6{nPJu&_6ZR9kI zy=KnTFjw8n7K1E|gb!J_oy_2pUKtYP-l!sxJ;JDNqLpNYw0ze8iiC2!Rj7ngsZeg61X#GBSdfHie`^qVxK(119 zEYK+E&4NbWJOK-oQZbqA@D4Y1;VDLnk8@`isDX$E@F;z zqBJt=NrW1&#B$ge_g^TSlD#dSe3|*CRWa%#JZy*x) z%IY`xPZnCzy>thNjNi|;MYa6AU zLMoLS?ZmD?#1UIFW|15RGoa5+NOJTZM>y+_GrCaQLd~P(dkZEZ`XK-RSqKSxC$Ovq z5WXTD46OQsIa&GKn|db;AVLYGVt^um5C@Am4`KXYb+5&^>m~-#GRkWgLRt~E{#KpXqU21TVr|O%CBi+z z3B&nEZ)Sj64ua9s{yP!Pf&+}>G6G`t9%n=dG?NJqyK`w>J-*zelE zLFi)-NtD@*;fxnaDssiDelEcdpR$R>Gv(95?kQqOo{Cd|%=Sx%8BWFmEhhj%t5`6P zh6`9`dzzCUgy1v8oY}Jrpd?5!f`JJJv4BI4c>;|Zt`T$eb~lnM6F9#_i^0QQRE8d~ zT?j~%-=IRONdOtDau{>O7X;f;IO9A8e2Rc#z^uUQL~FlE!8%fiULeHlD8l%@PmhT8 zyO%N&d+1hRJl_1)lP7Ual|DgxG#pvsPU+(q?DrpUbnr@bIqNzQk9BLt2U%aYbnm_0 zRmUs{W@w)y0XSK6F7vviNxbRu6Loq;kMHjJf{xs4#^k zOwdF8y_*z($qEzFez6Q&j8YzSssvah#CPF7fF%~>sS!|@au0?8&?ztRl(+7JkfcMG zGKJC#y>fWO+z5lvq%|k?9#*A@t0)!+0ta5hiCy_hB}k)lqx6^3f3{#5v`oiX$jS?K zsmU;Cu@O_o;A1kk_MF;t14`sTr`62C{hTEzJ-jid}1j7iv|3E_EMItqWG6`+$taev(1uHc68{HRJ$~f5k+!0$8T*#(f$|TI_#%CwFp` zt@rmMQK+?%_|T~SziGCPtxrY4eySvm!~q8@-i&QdMzfP6A-&09CQZ4cg$RaEwGKnL z)>Nc&9S0)u7UIidtW-pm!yvtbGlhd9Bk+I-HcZPjt3}#`OZw0|k z){se7nPXU1El7Yy2dIHNd|zruKe)Xl3}gtfF_kTo&pv5-Hbk5mLPP0lUY^o`7gD_@H`%!qA&9>?d{jX_zj^ZY{W zZlLJdzGqlQ?YNf`(~95KifAZDIReiz#)dR07x7_rMjV0o`3%AN23GW-B7^SfwjSpI zg4-SfVGfWj!@zk!)TLiT=h_74*R*z_c)j0xEe2(ft zuM2b%kz3`NoHQZCJo;0%LqR}{>IJZ7-HE=zSX?8tPhUlV;U!6A=Bwqtk46G`Q76a| zYoJ4;qzj}iPku3x30S2sgOQXvMXi~5*$U&VG(;ppnq)1hd6&rNyPl;dmLHy>PdbgJ z@DgerTrH}Lp&&>J>|t8h2>lcBs59g=zC5nl>taMe)a-=ju|taD z*(o^1C`Aq7z-u>H?W?Ecpz$H@Zm6)u;W$-(QK0GcMcXX;NxjYE9)xxu@3i2658_#A9gh4yUTQ|3Dr-th|n#A1-L>B^gq&$ zkW4x}OT#f0{j$kl4OJ4NJi8dAS4fi}ree#eRk1LA!uB z@JxfNSggwXFKteeMva<9h|4rZ>n+GQYYVNBW!PAwnP-@U3HQ5S4|$Ap&JLJXHi1a! zQ5TGqH{=i5wi+bjXjSK!45o#QIjTg~CQ#y2S^Aw+kQ>**30Co=coHN*UPEKhqgi18 z9Iw12B-(ILj@B!%cmi9JS!Rc+LlgLN%CSB-Mso;45d-n)H0Yzfu?*rhcA+h5q34u@VJ1Eb1`(a zlIH`y74WMbo{Mn|D-6-RmS3(Dgw_E*mtC{PIPtjKqXP0YGS*InZtEa777?JTFOQKy z>D4wQ)8Z6k$CCkuEki^s`dI5Y(k4w%+>d;&$qb>SLm^MBA%iMOYg$ESk#YuBn7B-t zDQ*UeYw9ieiiheK9t_`u^NSrZzUu{$L`+dH_k6@@BT(gf8!0!!L?P}?mU$J9o!yMI zFKsWKDmL=8$^lrZS_E@zOyPV3c+Ke-K$|^J#(Hl+=qv{6%I8EhoKAJw{<&W~%EGnA zz#=o?n5p;CEhoQz_Y?|1N2X2^-1#|dl>yR`rdrBlcOOKsPgn&=qV`elPlTQcKvZLr z=inAe1llCqzrx`-42DWnkFob@cL-J?*uAMOOA%>&H{YeGSeG>B!qY#50jb!;+3C|TuXbG|SS`KmK z=${dVtIU-z!W;d@b`5{xOv!qG=#`BU3KT-d{+ma^PiGx8Z!I`X(e9KIxID0gbB!8P z82xt~C7m2|QNuQ7kF#J+6Sfb+ZgJ>h%zm=}0;E%jjM%c0=(DL~91N4N{CNCNh~B72 z!1X%N0b@3TW#BQ^Ym%?!1@c!7|M1)|Z_(IbFJFz1(xQt}v}T@CUO z;{O<3NY`=uSe#?aILc8SGTv`0N(2%NKAix^rHhU6=|RiAe9&Y{JnBD&tL&AO<_M%f z(PgzE4+D_9BaC84hO9>u2M{P6&VJvug{p1EqI#ydr(e2bDP=x0O7To^Jw*_i7Ncln zt$PI7sJ1r=fL5i$Q6N0NGwd5??#ZvtyAbFzl$W_$+mJ&VgtsOc-&IMAyA+?I@g|_y z>_amAS&L*cuPGy?3otX?d`UtxmLR*rPhbf{kyj1D#pXw_7vn_@P?qY3U1|$e7L30G zANu<8R3OcNQDg9XYDm7!L6zP#pw=i1=TOl-)B~qfZ4LBDfT(6hi>0&OJve`g&jLh3 zs%zG#Qz-Fk2^I$w<36ig*s*6R;p%YHREmnhySbPyi_z>^TA6RCyWaM=eaiJ?;Km1MA+6mI)F*^W-R zh`k$88Zibi?L%t$of2xs5H7%!B|>yv2p_s(W-TViYa8m=QWfunh?hBr`9-)a&PhYG zm>=pIk$)xn*CzrLt6=!sI8ovd>swXG;sjp|1OT)=A6k=TWvzkKQal}^++1y`2u(jK z)c8gT9rcvpMHp~FSYPzMY8lf{#K`eGmoX|C_ zM6bRzn&$-GRtf{NlM5e+B)kxl1|e9>UOxnHeP2P%01>F_#{uSJJPzCgay?7@l7z;KGT~w6?mrz@W88+@5ZN;WuKh)GkG>`uMAFo`yovSH`C- zcppgef-J$iUrIWtopO3C?{xUq7Tk7Eeymy%B~l}SC|~lELj684H%QXIw%bjtmfs1V zcH)87J!J@!h`b2XyoC=`jK^2_W5_a#^u^BUY^+3KXTUuSmj*IyWIG+$4FY(JD9ocG z#p+i3ilWsKRGlao!+yq}2{1J%t8vK3e7qo!ms85Dm?0)bBRYRPWsqt(RWsGo?P70) zYnZY$gka)eb7K+4Lh>?5n~HN+_-c`!=`yr>oGvWzdoKs?2vG?0UG(E>+!aA%kA_Bx z6d+v|!Dh<9z$;OTb2NntSBel^L?>A~C@BS?vQQOft7`jX&e(gwET}zpNj4B)ZcM5( zrWpk$fQww_nk(Oj7RhI#WJ6KN6Vu3ULWSDhbfFs&F_;?rX*L?sjL{_D|N6m9nA{;o zjPfyK=fs!u3PJ1;q>loSkg-*Y(+0VT*uiYN#?ux_)6acUQ2~00Au%sYMQVA{T;9#;?UQ9AF4D3K> z=~p_f#G=d6G_HgRk6~6`cjO}*@UfOyzx_33-&kx^j8KQwQYB>y>+MVbPD{`xFD$Mo zWq`ekVX@H(u3+jGZrDc)Hl=%VeTb|=XgnvvD;cBmLR=bw$6{_ zLwj=SCS&N2oV|BuZ4@T`S}J&wp8jb(fgT_eHq#riZ!{GrLwo*Un?kds_TAM7d>Cc=1>> z45=@uzZ|!DoBEUd_W2qLRCT`*&UQ5|XppZ5J2=w{FF!AtQEpM8#~mWZ4@=6xORmM=Gqu@4p*p)77dgQt;Q6vahw! zR|)p*;{-BLZZo_s)z<@^8j(ND$j@5226@OIim$z!<)0}@?>CP#x?d3BC08>qqLIYd zgyo_sY3B{%O<4}h!*+>cLD@~u{&RlK)$cSpZP3BIMpR8VJH>qLQQVg z#S)JS=qjiI>O9O2fzc3}1M?cwXuEL7$whJx%I0FSeS-B`n^)4&!NUp>VPD2Vyn9AH z);mvGJjS)7RXSh8WM({UN@c4qTfl16DfYKqO`R15(K(an9Ex`eG_3V9!hes`RJiH_ zAYe*fk;J|GLBkL_2~87%C}7*Uz00Ht-g18LVS1}}nX4|6Lv0T7`ij4ix4AM(rCuzQ zs@6JgVh~2dSM<(7)Je=9psANUpiWO>gw3wx%9LJW7$^F4xe^8U;Akn!h9qeD7U%XF z(UytAF063kVdH48ao2aR7x11SxJkK_j6Vz|1H`BZ4Ia?gC;ezBN4U4%?G*Sd4+dUk zR@ONLq_TBL=mC^3rGZPl7QkYfQsVqy9orgKRX;}^;&Ze`y!~o=*Tq>jG>7KG3n6={ z>qs3;Dpe8MZ&=VJ*yM_Tj4Z|hr7tCQ*j5-uuw%h#a&d$+VmbSCsXzYJZMWYrU|;{x9Vc*fWV4ugnEwvSEQy)ZD-@0 z9AWg50yf|0it|Dzy%L4KYiaaVkR!rSpM07dsX`Kwg?sd=PIBf&cXJd|4@Z=%^we=X zAR%RLN(Ro5gM=)nqr=H|G%B2En^8O!NObp4QxfV>z|RbLqPYSEDx5j*s3}0&6a=Y} zl3I~bjRm|o<4hK1XhcQ5D6IN#GV(|x0y=HfA;as`9bCZ}@{k%DB|&lV=$#7OO{_idw<8SoGz%n4Ax2z)GIgE~jfQItXbEUHHL|6=6!JSvP* zmQvRhG1~G;obERrFrRk^sgDG ztt#`vC{uY{DuD?4;`j`jxOOn?fV5>t9=wucS0+p-BC!NTWKFaA=q3@-H9KUX-y)Uk zV=goJutgbvia2;o;Q*6FL}&M$cVu0^OL%I>C@K%Cj$W~9**j?}j8LI50Jn)~^oUAA z=n<}!MNX{>0t(lkz>f`ZvJVJIPb(L|-mw~1K8+kZ2OO220d$-XK(>RLMvt?%6`WR` zH>g=D$m*03;qJ$qb4^XYl?@g&K_4+uau{hH8#BbFZ zfOc$gm2DmfK&WRBTq0)u(ZtX=+5^^rrio^ErQTx115^+H)lm}jadf(~A9fOW&ytka zKBWi6Dk9;t&sV)=j4!aylByzwlncup6%z3~C$ZX-5X5NBrk#u7!ioV3@0}u)G>uYk zB?)=;ny$QJ>_l@rl>`d#(qDA}g3Fp30xQ~M{b;|*ii171i2d>LH1OebZg9OdDH zUVDV_7W6FePI4WBjXh6TrgTojczm4=5K%=h3SwDuEKZl3o-HW(5eG?JX^Y50N?iP= zn9-x>Gq3!G6en>rK;k|Lv^cqhuWXk_U}EdAcp5sQF*6=SYcl0nI*63E7v;C7IU=fg zk>{JEE?hwlXPyS&$O)sumWcDVEo6P4#|MNARKUCEd!E`pqHoCm!JPMYG56d2^-kj|0b zujW(|tL6V39y7u*+2iR5m<36bT1+tiuYvL-hcJq8%#s!%KsgO z%~fJnZU@SBuMf>@s3LrdX`2BqXe|Q#2|e)PH07e+t)n77MNmLIJ{i>sVRmho+7-EmyUtE@9Ay=X%%(6yMxtn6b?J!7y-o0|x(s8D2{z*+u_C<# zp&OsGlu>#0f(KHob``8i;a#ERTI zr#F~7MiHR!kd7H;qxL2CGXBlBH!(vJ-%`CPfX?XVb<>~{>Rj8m9Ub3>z8QQ8BDTf?h2XX-8XUB2hL z3l~H*Cd^cNXmNn2h9osV4^yGL65%RBuM9KrhzQaa6PGsNG3tAI_s7H;Ju1UsL;OS8 z8EV?GVQ@rm6&MP*Dg5tm{b*1b5S@qP>=v>R(H`7^N@GUk^oLR)Y;DDmr@qk}1M}A>XSlI+6(J>56C2JOYIW_Z- zb&G0Y&q^ctyNOdtb%PePGiwnE5k6De<>ZvDW?mtYMeGsdh;fR#o-=~rAPrqWazisi zBSLcb(}+1eV_b*WW@jWt2`aj!hqhwI?%92`)w6ga{3d)xl7(wNAh*QSdL zLMqFsUrR0PY6H8)=G2IR)t*5H*1=(WVpCp$BSbpn^4;fxDVFNE! zFqHz?;D8f#@zx2rL4t@^`S63s6y4pp2nY*+g$QYwRiDs!BWEp#h?YZ^3HXv{lk&+Q z>N}56EW!}T7c1dE^Cyc(=2(?xVLo)#D&lhligueTV|GJ`lg@x>>OUzucgnwxFv4@D zN)f7Vpskt1a#6-5Zr}|JHKP&!RWXY~bUBryP(|PQ{l!V?ddFs3S`|Xt^###0q#Gs- zUv!~}9!QlgigDPH4#YGf3U#yYxM2t)khzz{{My)u5s%tdq^N$$y(1l7NM#1Omo)qJ z{d-u&NsSabW2i9YZ0=Dwkb#gj!mpPC8$Mz-r_e~4o@D9q~a?@{Au~^ z!-iejy(-p21bE4ROPom{VuC2!9QU-QnGr*=L8|B7a=BRx&U0c-lS395-D19joN~$B z@7)ad4MzxajHIN=5aviFEIHXc>sb^+LwjD{wqb-3sCf+6XoQk0>c4d>FcVH4(Su`& z35gejm}{2$aJ)0)Z*0{$>DQnbP{_><;>$@H1tK+Q*E)Z}Qaz10QudJ4F1yZ6(!NU6 z`bkIwDeKo#HN_MP-KAJ6YbIbkwufL_muQ-|X}wk6##rRF=jYe55`I99BK%50 zFJ}wl)I=lqPH+n8-$$%f~&Lj%5;R+ zx`lhZN2#Vg;;u$mDPQw-U})`#-F1PE+npCgjEXHZ#t;7QLKxkcCl@3WL58iy;sQqg z?iEJXde^FgnsVJEK)@#I{v+feKh&C9pbSAz4VgT&)!u|5|KUtd*M>?@C3)2}$Kb?_ zPJr?ni+eWapH8*(cGL=Gl#Bx4&9A&Xg=JVKkY(;EHJ^eb<1I5KK3 zK&%>0I_(xWduLyEm7DSA3bdGR6b5Xw3ehS;)w>U_wsf-nJnCAy9L|?Nv{essmdzCv z>DPMeFW)~3bl#+ik!Lr_3qh5`&|g7MirshEP_PWwJv)lsT=8mL+_L%3WsDOt2f)R-xKA6|MZ*NxJ2 zR&!(|!i%b1f~u!<&bj1atZm3zbqaEOrZR#lCcy%&0}K3Q(o~;*EF8g)P0X0q#*pV+ zef%|W#u9YwtVO{ElN~X&FYuaK1t3cj>pUZtYF{ApF~e7RbcC*SJ&O@dB`oDMxif{6 zY|v{NLy8-e8r^#75`^65*~as5$0M~dq=leoOKKvuOU9=ncE>F#o@tk%o$F3hOK64a zMLR)CRVJ?}$Mz@=pt)C7F|tRc#q<3$CGl10E~6h+Rulh%LW!(@rowbxg=z*x=@@X6 z>3$@47Rp zrsTk{H9KZv;#aw*-@vRrgM2&3X^>PE6HeonF1ovHL9q`cJD7w=A@@?2Ron zClm=m6=(#&=n017(#az(D%HjDA?sNhl4-g|qu9WYZAu^~x<%$!8{7YfwvI3Cb#@W@GNs3PWYP_H5= ze7R=P5F*ZSzlo_m6A}&o6>)DsQAj>TvN!MO)hBs>(6h?h-uGIY(rw2KYoVjsXCFqg ziEl>F8W=3VE2Be;9#v%?+qu#+L}HJe4L0DHNFbc+xFsf3x2rp8_asoJ8FJn&Eb8UV z1X+eG?m|X#E>bG+^t7FW zzfd4Ef=U{+a}VDp7UjwOW_Ad>MlN6GM1&ca4c$^jT9zs2z@AWrAmK_{PoBD!E3s4# zE%OOtUnnCW$v$E*C0$XRNCF=dkTH1hrl>bhev1zAi*mL=km0R;254wZRrn_AQWoo$ zB(-=xO;*ViS%wp2ERxW|#(KupXJ(Kl&Fy^ywR>xev33v9K3r}o1V<7Q*&9?Nce}^hZ=d2!(v;n)V$?Sa`m#OQbqYy@*{5K>%CnkcMqTdnjBITP(0>M+i+V zV}v`EkxG7oQb0v?ot{EWr@P{-+@?ht2vdarX;hj8;IR}}y(4D!h0TM>+!?<1yhc9} zQ@FX7wIbZ&t8=7C(w0`?h){svNFzL!+`SrT-5^p+EGFr?wo6UfHd_(%oN2;pC(*qJ z@v(6kpsKqx!bifocr4+8a#W!z3$rRFX<`<2_{E(Ob&TE~js>MU4MEO2Oy)Ucw+cgi zi}4WiR*Ef&+S_s0ewZs>aM7aSLk3hh2_*uzR7|r_3{f@ zvs>|GBU?#mphKC`+)h~(Tt_aaKLwE=QZk2f3V|jxe=x@^*;;pCOOj%KEM`owkrajV zl{$i?OIeX9CB7iL69(&eiiF8h8qswg9S~`qOE!KEKT?-5h6!J@I9&2=l_ilNv!vLn zqD5Po{BS$Y;iRe-U; z1^Re!0~4+!`EWo)VjYBsUGpw?c?^379sboAwkl_S4@@P?RhH2i;y%hT6eCtRRH7uh zy%dGbg21of!GUi1ZwZi^*#pp6xVxOik{j*N*lVKGpugN+=kR8%brX`;WtZo_Yab}W z{>rHkz$7HNRYtHTelB~x{6qrq(1pIDiA1FMW@#pJ0yS;A_)ODQBg`&l;+Uco zg*+KY85T?8iUOCAf)Zgr$E-0;-9cV*Ln?-kIBVoYW{2!vf@z`lmVh~;5yE<{&*E;p z(7vaALo|x!Sf)|aXj!(erVOMQqG8}#_bfiOA*(m?Vdzbrn`h7Nx%ZCh%$i?8@m-;@ zkem|k|M*!LCYes~74YKk80)v`WafS2b>gJvB-^aKvNn_gWIS+$Bz>R(3&L3pR3ZM@ zl6B~-r*8t4;q^Tcxx@`yF21`noTIz5Zhpl~W9p?c4Qyfi??Mm9e4G=9&y_t@tgczC z&NU-~oYQ-u06G^4Dtb{|Udhr&B5#L9%^d-vp*DqQZF8{U%Kx~bD|Ki2Z!LA%al}a- zYEoA;mG5+BtxcZJ{|cQY@@OMD4$Cj8trZH5beus*uYF(gH5&Xn+O3#{^5Gj0R*%|5 z%&6z4#fzgJ$DFu@H=SQMy+jKWCs0XFe9^t|{=H_Kd2N+#&jlNcALRPTS{+DbZ98!L znqH31GKCcnc^z{$YQpcgN~~Vb885%^(e~*H zUer!fm(Ew%dD^Qup&}@Yh~q(&e%sE(q6xu zD+8R;!_OqhT`M!w`C2RntG3M=`x-cF=Etc4kQV4Y4;%LDTNx@wT1t@m;cbhaq@30t zS+St3bnQ`#a?&%_{#*Ma*P3`SIl_3ETpVW ztn{W;OCgIFmz6%A_rNzlb$iFbIoY~BXZl0M^JKx9SaBW5i(Z~yqwz`P5{hCq+X z^~Jyr0*9(VkgEVm*P=YikgkUYfS-xxlH@&vHB%>07H07xnDU6~cd2e0nl#l;^8utQi<35L5di-F(mv@# z$otGjbztQkS866fg6uZ5Rl|>O?7iqI8Q3*rCZ|RBDiT{sz>roWo2s#GjUlg2|3KD- zxFv-Si;m<87WL5CAb+VSx9JvVL6R!pZ$}ED@k*A$(R!0LSKHDgt@#NtE7)!sV-Wpe z<+d*}Z*-J1MC0L5mm%$sbhlzQOH~)PehpWKK1&wXmU~06`GZY_&X2)zPgTwvJPFeN zPF!Rb<=NBb1itCc5#RPQo+OEX3}KZV>GnyK({)@dI5cW&W3<@_jul2E=FlmI%($;_ zs#-d|Nox8Cp>!;+@@WrqzheD~T=`tu{;W}0{WX{OI%Yrf7?G(_k=Fgz_ObyAlO|h5 zP12Sm##vCHD^3X#6KbtlPx5ENLP70xys~WzT08ubM7#16;Q>NdyNdXbpe1#MLB0A` z%dSroggqjrovxXq9BN`F#x^oq{+||~D2YsLj6R6stg)jgPTQ0~ulA6H%^gHy8o<%0BvrL9&J?oYbg?z0ELIB#{LYeM<*jBL z3L0dcig`U*Yb3i3k24h|fhQ=)kiLrGSps{PLZNAC>xb%-b0#(9#7&I?q<8Aq_>f6jg4gnJ>t|UpA8iJPQqOseq z-4FKEQgLDB*bP30#fNOtl$nS9ywQrpH?CCNw6R7sZMuzH$v@T#V}kp&E^e&?gGRWC zKhxAsdK^o7PXhO1OPYkGp|{!@Bu`1nzJ7KA>=L!6w6?l3f(h6qbLZqq;&seb#|z%I zl7GQy+?n604@LDuZ|_MXf9k6`ku@oBl1pei^@R*w^+KX~-AC-xr361Nt3(M}x{|8A zc4C0=mBLYUd0brWsRnhdt2svT{M{$HTNFRKb~@rN+Gy)(gQqsM7qrPhp>Lf&l&s&f zO=#W9&ee9x$_!G*mNl1{4&RyEP6RWYhW>phjWAIL+eTl8LxAxsh|(!RFU{$*wk$e z6Bz?dbioxzf=1`!?J=Htu2-{J8YA?A%}P|eVZoeG4H}QWA-I0pZjTU}qRn+rD9I@b zTV?(Rz?&s28DKzC`ho$-YKnn8gV{*Xp;vyn5ht$cDrF;>6MUL zpq{cOlhwAUZSx@{?CVlCl!>I}MQzDX(|1RNWC@F6XE)k*&YwlW%%5$tKJ%!yH6Vv@ zC>ufv_V*#$e+!jcZD?q(5^0gyp?6&-TRAKB7M7KFBsYqSnq6gWS^>xQQv5r^ z{*6S2WEj;&wX)pfsL3>Wx2QeZQ3p8CrFA*9$tX;>6%i1^@Gkjv@Pt|M#M&-yWP*` z@%fx_7bxDi&In+JTlMB~MUJVASwBXNM8R`MJB#eAy@Ev2wc@9@sYPNQaCQIs_f*M3d_;n*iz8x8z5p??&yh)C%#XZ>y*|>Y-HhP7E=E zSpBR^%qK?-kO{NKMhm9qV_8S&lfryutE2}m#>)B`r{k8BIWJoB zbhi&k@iv5+^AVYf^Q$~mUc&Jm&N11AG7Uw~x&PtbC zqH^gfLK#QTHBKucRtDNS7@eZ+J8=kd*SmN%u8v&zEXe5!Ry6zJVrRvk*t;O2lH(%V z@X$BH*C%5g!eqQGmE7`hJmN1GEGIo~D4Qgtln6^-&}o)#c%GB>u70OId=3134TF zHNoZQ_HU4Ee+c;G=Rkm=aIV+W(t+PlR61tin0WdKZt6yu?8{t@eu=p=j`FTXsv_Ht zIwm$;IJjA_mBvH*Jpl*Jhxms}*}MxNs^ZMnq>G{?B$nhN&2z%js?fv`5-goKsTER`L8NokuyxuXr5ITI#6#uIvPkdtILK-N zb|fOIJ*N*xc)QYRC^K;VJSsZV+<@$+wx8=cJQ;KM^yzOBmlBZVPTH-RZbaE4PkVkrU;@w75 z#l=-xXC|`bnZqMF?6PXvA&rrm8MBHtU-M#iPTf5ZqZ6#!9F}|T!Vt<=DJ+?Xrye5Z z4n<7=Y;_odTa>{^=dJD!{o5&KH=m63&^4ylV6<0fG=|-Hu2J;3UrW|__wiIFH$$pb zdJ-gjw>weJDRpV>u*c)3qr?nd5bJl8>CgFuS^krRuawfA)JbSuFmzKq>gn0a8dWmw ztK_c!@SYx+J>_+hBD3;+fx>rjd!>lHU`MBkLqoI3EaOa4NQ^WkhZv*9RuW>^FI1H^ zACe(y>me(?Tb(Wtfrwzx32MCT4arTLL5k>daV4!M7ik=pykSibNf~H5bTQh_J243o0LQ5zJe|bOHb93H z$nc1G2nN7o?oM#2vhFE!lvk7HS_1BJh5S$f>feaIeFy6C)Cq@7PXldJ|_X#+iuD$HvQ}mgew1rAoc{VLSLf>%203DLLC^X6ZW-2VD{W`m9jaD zS8AXt)cDCf&8?=TDVPE>cW5NVEXZR8X~{>N?>H%6A(4{bid-QGR5EJL%TmH+zKe!N zu^F}xfm20OB}SgZZW+Qhg^FXOLKltlF$!jtp{?k40C#EF(MPOh7OFV|8mxvyB+09S zh!DG~F&xPrdJ1aCC5zqQ13x57i1Z@AyB#fXp#s> z77_x0w|GS%>-=i8)O$HP$=meKNuP~0y>%1P>Zj_l7M&)Pi~P$cs?ifv{^rKwP^UfN z8$F-6npAPB1fG!e6Vx8Feo51ulD?M=2a!lJ5KCU+MIxel2nm5tTDck!q9e`)H4YI$ z9IPp2M;z3%^&aB7Q}w>9UBboLzvG7Y3nNqb>^~jnN>jwN1`Q`B0mmv*~2 zBV!7}k#r?!p>vMo1x&Q9K!s72KZbREqizsp1qD5eX$}_0+0>IF^OzLMZ1~IMojgcqka5h&aN=+>n3w~{pOX|l6ZzBVt)xpc2^}GHnrRZl z&Yxc3!wM>=1l-Z(h0RzYkX~?#ECv#>pMBFBuKi_4WIffFJaHK%`TjKJaz}sLuRWs5 zRpGwe+!1Y)S0G}*yFUb@N&Rmz(Ps>%k#MY)*!J-V?ibhS?kw8{SrMJc85W-PF%p+w zPb*@OX4@1&T8ewakVX6K>FI?RN0f=ec2(kNiX4iC=$mw{b$f)wuBGLSSJ$#Rry^C= zz-@wbD}}JO=cY0A%G00t7n3JzSB26!q{;I=pX+HUaZ1gF(~oL`k6tg1Uo>*M-VMo0 z?k_6f-V>BfYa23OD5!RE2o&N-Hpjvrc)0r;NZko6DdxUo!tG;GqK!+8Dx9gI*G6Mz z1ec*}S%amSg0gJOQbDfd=g~Q&LXgLZ8g@lna+;&pq5wiby}$kUakOm)QvB0<++W?A zGr&hk`|FQ89>(a#MBQO%SJ{apc;_5!;ZaTJ%C@SG+LYKd6XM@spDTx+FC_9HvOYO8bnz_Yyqv(Y5Rudu ztuu>yL3;iOTi#Gf_=CD`8%n+DVsfm&j~FUxM}ug%5R{scJ;|^oHQ*8C5wvI)B$`Gc z+hX5D?D~4p6gTg>lk-Z@YKj#LVF=wC0$`lFb|k!(;_;VvS{)~%6a#@LNSR`@oKyvF zis=@xnzHj&F%&D;`r&A#%f!l!tB!DYY+)#6f2hHv5rQzZEX$SV7>LHGs_2W6(%(ag zq;EqX4->~JtSg!F2`{y#5RJ)13OOO0J1#))a4>T^4|=HD2Oi< z0X}3k>5~Sgau-FsRo1oaysH?rPDF_8j&<<5F%Wmo$`hx6M^cn|>!|6{#@q1YU306X z0aIO_vp-+O%Qxa{1$b&haHSV!Av%JH9jQ(&cRH9t)Hc11k5ZT7c(26c^?1cp~sIDXGF{zB%cXbs;!RXy!v8&&8b97WQ-lB>e z+@D=g(wIZKPP^#WK89mHe01iD9{R+pJEk?6ftP+u&84RHX*w+1fG?^ zse7)(E6u@iQ0vgHiklW69!eM{Ic1TLdy(oP=I(IazR08^#x{P1n)vno1{8!K(h>)s zEMc)T>yeZ9>-g3JqNuiu+jKO8EK4>;2>@Ae9wc|}GUeqfoTh0Ez9|oqiw648#g=$9 z1reGMH68T|dgf9!PGv7HT9uwaw-r4sgz&cYtNI3q!70UfNwVZ9tS;78CQmtSE{L7k7yxT*PUw?^3NUsb9n$jaSPl0i7(#0$5C#ArKWScLQW{ zSj4hAVzz7gXXjl8*rGWZb*R==5o*-V#;~~ljPGo%+tYw)0Ca!<{~10jJpTKeI(T`C zAgN5M@23i%4;Tpw?_2;nUCU|B)D{shD^N@Ssxun5-edz`z@9UjENTo5C- zXMN&2k471bE|ChYD#LJJ-~&MX6shp%K;Ds;f#yrwm|-XmpaP6%ien*}G9-G_dn+PT zWrwIips5DHHa%KnxO+E|g@Krx8uA@%r%QF~h`}|Z6UPZUJpmYA9Ei}VF@6`sd9M_D z%?ZttM2;O-;P><&0%t|h%HI`W79fKdWWhYGL|JYhMfgyHNj6FOOy`Joc`n}&0fZ4| zA!MsAPKMFsWwr!KGfgTZP%lwPoCx~1VXJsR5AT%-#BK|j6TyxHJRK?7L_4cNA)Jq3 z|Et-sQq%pfahLkt!!Mc`!fAYYnlJ%?jTV11w-sT-X-{J4m?~+7JGB?o42baWTWNwW zbc#U+3#L{GvGBmQ4mia?vdS-nc%9*|5$5@E&!EhDxL{6~IV~t*l;4u696>=6P}|dr z!U%hm3REjWcc#`whtv}s77d~p+}>9VfQCB6h|DTRC?kV$R=4nMj9($~#Qp&&@^sN# z3^bp9G=Pyjg7KOu0)u-L!ViI+sIr9rfa6XUFH#vf)O`xZSi?&f!|0^^Wk^%H<9MPV z%)u^36CNCIxMASB2if`1bEP#|U4tKgzO+0E#@sJJ!oP|(Ki=s;0 zsSlEsB_GelLWkbDW2J6%6DZFDaF~Z;6REoBHES(tWdBVdqHGgf~CY8-Qz4l zUcN|zc*XGcm&hlf2S`_lNlG3?EEI8q3#2nW6h)nOu96^IRQUv%i#ZL3D$(WT;dDbb zLJT-eG-i2jWzHnybHTR7uv3?W;4>wKs5-a-+DtCTSfD{Ro-1V%wKIcLq0vAP_qL8cTEvshD>HiT_alPHokN&u7?U2IN%yU{NaY=E z5e9w(+rQ?Jja5I3&GjmQgTK`{NF`L(fwCmE1PGA%-z!F4;*?{Xgcw8=hU`hFf-XBl zP>KmQGf{zY%=0AydM!E=$@ly%M;`u)Zi8 zJ5N|F)kY?xz?dm!*aAc}4IprvA*caBi(UHxre)oUKTGGiNQ*EPgl@2pYlE{&K_ima z0_ItCE7PpebX!YTn@0eSR-0c#bv=epmLsLqp_mL!L{}s%#SmNox}h>128q%j(MP7b zoM?JakR(r+%03NXi=Dyo2$ys?bKJRx{Xv{7mVyiFUIY^tDahFVI#hh|DwoMse@Ls@ z$DI&F6;AZtMiPiJ+a|S@GidV_rMaZsNCX9e+XVIhvPY$Z92uzhjEr!R66cJ_#1x*$ zclFvK)xY^ z;)!;P5`SF5E9D|3WJv?QV+^3C1`{n1krLfUiKS{SIUr=nBgb7X~$mO=*Ah zIT17wY1du;(qVXEu1x}uCp8p0t7wU5dlVg{Sccg>rUIp|A>{?3uE8vBMUuw5h&}y# zmgpK_m4OaQF&+q|@UxxOdN(cMwUs6N6sjs!1VCf5KcBqj|8RaV7Nkl>z*3=%Xi-zA zC|6V;yIGMHeMq{ zymx_*n-RW%(CtOwFNk|a_|=7N1}espUUU|VGKiQXSt1m;J_cL_AnlvA1ME_+Tvsc; z#yN`W7OFr;GfzOsRf?PGK`b+8Sy%+e*g>o83QS+Z;=S7Dmglb>M6m!xgr;EgWQEbh zXdRl9gwP*H>64-MDrJbVT?#7H!JY}QTV{}k*CM*CkQYIt2t_hY1K4Xwy51h?@J1UG z4fpx{idZ%ow%u}rXd-XPM!-c^_lA*H;}#t!Q54$chW7#6EF)=la@kp%` zZ!pF35zo<0oJabBW+#P$ywn%u(0nCO15=z5LoEc_0%X*YA;AE&!LJE1JR-+nO&1}2 zCcE3iYzPKm=?o^Ip|wBDhM`UuOB?urNQI<}v~Crk&oDw=`~5qp?E=^+8FVVlr||3$ zPUCP|g)3+?oCK<@a{a-&s$Qy6x{E*vDXV{T5y*o5Z{{*Q#a0t4Mg5K^vGJQqPu^IWBg@jie_EArwr)T80luh@+3p7ZeNTaC@?0M!5UZ;6>HD&LREuB$fy1^h*W^Id5t12+|(jSMiI02 z2MMOc50kT0E=2(w^7L5}P-${Qf37j?8o@7QDTFPb%JeY{gaQ)+< zlP%F~>@$Gy)M(R1L={GnFey>)L^*%j!YMA)RWL?`(@&0RyH)j&?i1i#FiYpVCd2^p%a` zj{JOxQFHcFMhkwP8#P*Ot`X_*d07ZUu+?w${g1APaD*minUKdAZkjRD<(k>E%L({M zb1RD{aF;g*FerCIDUveEWRPf(t7nQ36GjPwFCak=w{qFcX5W=Ak{tgElJ%@Qh`>U= z0RDui*eg+H=^k|wD-Y#KHD)j?5pml;AVhv$ur1U31z;p`Q{md~^zNmOmj#ase!NAqj)&%A0-^BE@3`o{oEc zqjXOoEizN13dzWSWCgXpJhp8~367e;D77!&N%AGVvf)xg?-1|)vX6kY`FSZagyASP z9t}d+w?oK^)v2+pN;AbQJAH#DAVmNo7)PNYF{(?O0ua_LlH@s9nTj+X{rGAPc+t4b z888nWWt3Okxo@nD?F)C$G3M%*F52o3WFnJ^B;*gpscR~n);&9qXoIYLoVdi0$Pv-E z0cBBTF2&M5I)tKQ8Ol?}ECXO3QZqdIr025Ij0)dY*BJR?vU37HOU$1Vn^QMLfSUZ} zDJ%jS*lw1@b$;f!2LU<(^)9;ETF7Td0tsG^jokB%? zzHCL!0d&Tv1Up1oCxVsDX3?$1=^<1kRgAIFsQ5t8_$ZF!gz`xw0iu?_Ju2)r5nqWG_N zd2cU53^-azm_+$!?~q%h$Un~2kpP4=Y#nWZOv@{BVPe_pH8~1Tw*T9(CKZ3pHD?Fc zVi=yULbFQ0ELxzXJ`}7J*+UbKl2?v#qmUCOnMWkki53^Y!3dxFu~a~BuSMHW4c@pZ z3vyQtA#BUBEBMQckAzzduW83^hhi~NqX9vlkTTC)^GNPMDb>bY{nZ#it2C`>+22IF zwG%cXR_Fms^IIMGVS-j={OXiZ+$O0*s7@zJ2U5j!GLTNUxm}i02QV;13)0ZaYGnte z@I#OV@;c+WaL@MwK&Y_v!S9`0R}*{!5(af}W`~~4aijOu$w5Z$^728Ig5VH?QD~m5 zY+cvAIEuT6Y9wnojh)$xM+nZ*)AnA9T{biW-3UHMAKi){|8-%+T9oH#x21;3eGeY9Gvay6IqKtw#m&ig2P zsTAo@%1K`gVN2$p93~)~G@t=KhBcD|DD5OxbmyUf&8fCaq^%D>>1vpST%9@29wo=~{``MAxny z=^uFhnf***5Qh@Dt%{q>mr;1uq*f;>0PMt769r9Wobx&}v{wi#1KqWGUsyVz@a|}j zfYcJm<=KAyM>#^BGDVl-eK?h)ml^^XN^y&)kq51ChkRxuuSNJr9m2HwAG>6r#kgyE zgm%T?SOA6SQm?@<_`56x3a}|59bX90c|O9C64@3Ymv0L$84<8GNn!5+MI3MSiaa%O z4wD9GN?kUg(bTEI+T!-WHxFixiL8haaGQtUHs*M0|(XEZpe`4TpIMUg~bz^Ev&xRkaM#B|qKPg)CiT4+Od zSwj~xnGced-25pP0uf_KkB2Cm<%;~-{J6tOUy1Vl3~fU~u|b~6ttvIc9%RcE{%Aw; zMJFIY0-zLu3nG2c10lOTv^?O5K9j2a@+KZZJ(k!&4^zlOg&8P=HO=p$Ya?)~VWvN- zDArVe&RGk85W6?n^Y&6Bydd))izgb%;Z!e>8j;EZ{V|99VOb)M0aL!XIG`PAd&hK*BHZ=SwJj{#hfw??VnrwfJB?AB8) zpXFW&1U4G_j00Cah+o^6I%Q%{Aq;VtJEG&N8{1wjV6sY{|1-w67%Elo|o z#KjTsUPM7!5cRj&sm1EXs}!I2#C%V`RB`|DUd62Y`ZXg756ZDEBZLT{CEc`+haqz) zA&*K9;|{I^dn_$91p7@(yHZ35#2+jMPF0bQIv%2|x@ogV2@+N}^pqLn3aflC5XeGE zi>l9Dz1@UBT(AWm&-9F+Q0PZb94WZJ0U!Ez|`TmEQ3QqOzpz9J0Cj3&QS%*a^%rhHG zc}ugBRC#<{&i|ux&N4t}-;RZWp9xTOSU2{W0WB^fc!_}&nkT(FUS&vZl_mGUn3sK> zkZyAoe)IDYEAP63tk<1-DS{YYbSFr%lko;xt$S>wk*)ryq8z^Z)vcC9%LahBw7Yhr z=KU<8Oqy~f4x)QnOQ7uf9yt;FiHPQW!^Bd@MRhS$>4R-Du<4ZF;m$i*!tmosqkTmb zV?|qhI*J2h)0Mn~vu+xPO-uzM7eZCEjncb z7BAlK66hPmJ-hOYsktnsTbobhTPpM-f8bb0QYkq3M-_~lr07QD$`b=%tj}kvx-5d& z@=VD=pjBU_n^gB;kPguva;xjQb0EiPnUHX_pPNzfZ3F3oj-n8;v=BZonMv6w%kiZpX)2l-Zs$MNBKupr2j2Z%14F-8Xl_ zS5jhd63J?~V^{0zO;HvgVZ96jUOa-YVu{7{V5|2b`_pKj@jr$`3FrE!jTl#GFMeMF z*lH__bwO_Rlo`n_^_e~i6bf*E<)_*6(#zz6g-#)}izY*>pkkV3aEyL-Ct*kxq~0t` zli+bpEF)7B^IC*v_Jxyq*?pBmvgTzI!(gk+|M*!LC!S6YY7Hd~c@Jz6trH~_ofUTF zm374=hKBulf^H8%?LQw09nJwuU<*p46+39YBf8UN=j5A&QVUc2dRF)X5c6@RDr{9{ z$`T7C z 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�SB?l}!Q{^d_^l79PHWz4Q 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∈s(L$Ox%!!Y{mR$^v^L{F$j=Z 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%0DR-Nk*JSC;RDNT@OA~ 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 z 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≈RSM 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 z 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 literal 0 HcmV?d00001 From 2fb8d887b18401c863f5b56fbc6525a7dbc01d64 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Sun, 6 Sep 2020 20:41:45 +0200 Subject: [PATCH 024/150] Fixes when seeking in an MP3 file (#303) * separate malloc structures * add desync() for user when randomly seeking in the input file fix corner cases leading to exceptions when seeking * additional test when trying to crash-shake everything with a rotary encoder seeking into the currently played file * use private instead of static * remove temporary debug code --- src/AudioGenerator.h | 1 + src/AudioGeneratorMP3.cpp | 78 +++++++++++++++++++++++++++++++++------ src/AudioGeneratorMP3.h | 24 ++++++++++-- 3 files changed, 88 insertions(+), 15 deletions(-) diff --git a/src/AudioGenerator.h b/src/AudioGenerator.h index 889b2285..6d974876 100644 --- a/src/AudioGenerator.h +++ b/src/AudioGenerator.h @@ -35,6 +35,7 @@ class AudioGenerator virtual bool loop() { return false; }; virtual bool stop() { return false; }; virtual bool isRunning() { return false;}; + virtual void desync () { }; public: virtual bool RegisterMetadataCB(AudioStatus::metadataCBFn fn, void *data) { return cb.RegisterMetadataCB(fn, data); } diff --git a/src/AudioGeneratorMP3.cpp b/src/AudioGeneratorMP3.cpp index 44e3f6ff..9cc90b7e 100644 --- a/src/AudioGeneratorMP3.cpp +++ b/src/AudioGeneratorMP3.cpp @@ -29,11 +29,23 @@ AudioGeneratorMP3::AudioGeneratorMP3() buff = NULL; nsCountMax = 1152/32; madInitted = false; - preallocateSpace = NULL; - preallocateSize = 0; } -AudioGeneratorMP3::AudioGeneratorMP3(void *space, int size) +AudioGeneratorMP3::AudioGeneratorMP3(void *space, int size): preallocateSpace(space), preallocateSize(size) +{ + running = false; + file = NULL; + output = NULL; + buff = NULL; + nsCountMax = 1152/32; + madInitted = false; +} + +AudioGeneratorMP3::AudioGeneratorMP3(void *buff, int buffSize, void *stream, int streamSize, void *frame, int frameSize, void *synth, int synthSize): + preallocateSpace(buff), preallocateSize(buffSize), + preallocateStreamSpace(stream), preallocateStreamSize(streamSize), + preallocateFrameSpace(frame), preallocateFrameSize(frameSize), + preallocateSynthSpace(synth), preallocateSynthSize(synthSize) { running = false; file = NULL; @@ -41,8 +53,6 @@ AudioGeneratorMP3::AudioGeneratorMP3(void *space, int size) buff = NULL; nsCountMax = 1152/32; madInitted = false; - preallocateSpace = space; - preallocateSize = size; } AudioGeneratorMP3::~AudioGeneratorMP3() @@ -109,7 +119,12 @@ enum mad_flow AudioGeneratorMP3::Input() if (stream->next_frame) { unused = lastBuffLen - (stream->next_frame - buff); - memmove(buff, stream->next_frame, unused); + if (unused < 0) { + desync(); + unused = 0; + } else { + memmove(buff, stream->next_frame, unused); + } stream->next_frame = NULL; } @@ -125,6 +140,10 @@ enum mad_flow AudioGeneratorMP3::Input() // Can't read any from the file, and we don't have anything left. It's done.... return MAD_FLOW_STOP; } + if (len < 0) { + desync(); + unused = 0; + } lastBuffLen = len + unused; mad_stream_buffer(stream, buff, lastBuffLen); @@ -132,6 +151,16 @@ enum mad_flow AudioGeneratorMP3::Input() return MAD_FLOW_CONTINUE; } +void AudioGeneratorMP3::desync () +{ + audioLogger->printf_P(PSTR("MP3:desync\n")); + if (stream) { + stream->next_frame = nullptr; + stream->this_frame = nullptr; + stream->sync = 0; + } + lastBuffLen = 0; +} bool AudioGeneratorMP3::DecodeNextFrame() { @@ -196,6 +225,17 @@ bool AudioGeneratorMP3::loop() } if (!DecodeNextFrame()) { + if (stream->error == MAD_ERROR_BUFLEN) { + // randomly seeking can lead to endless + // and unrecoverable "MAD_ERROR_BUFLEN" loop + audioLogger->printf_P(PSTR("MP3:ERROR_BUFLEN %d\n"), unrecoverable); + if (++unrecoverable >= 3) { + unrecoverable = 0; + return (running = false); + } + } else { + unrecoverable = 0; + } goto retry; } samplePtr = 9999; @@ -243,16 +283,32 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output) lastBuffLen = 0; // Allocate all large memory chunks - if (preallocateSpace) { + if (preallocateStreamSize + preallocateFrameSize + preallocateSynthSize) { + if (preallocateSize >= preAllocBuffSize() && + preallocateStreamSize >= preAllocStreamSize() && + preallocateFrameSize >= preAllocFrameSize() && + preallocateSynthSize >= preAllocSynthSize()) { + buff = reinterpret_cast(preallocateSpace); + stream = reinterpret_cast(preallocateStreamSpace); + frame = reinterpret_cast(preallocateFrameSpace); + synth = reinterpret_cast(preallocateSynthSpace); + } + else { + audioLogger->printf_P("OOM error in MP3: Want %d/%d/%d/%d bytes, have %d/%d/%d/%d bytes preallocated.\n", + preAllocBuffSize(), preAllocStreamSize(), preAllocFrameSize(), preAllocSynthSize(), + preallocateSize, preallocateStreamSize, preallocateFrameSize, preallocateSynthSize); + return false; + } + } else if (preallocateSpace) { uint8_t *p = reinterpret_cast(preallocateSpace); buff = reinterpret_cast(p); - p += (buffLen+7) & ~7; + p += preAllocBuffSize(); stream = reinterpret_cast(p); - p += (sizeof(struct mad_stream)+7) & ~7; + p += preAllocStreamSize(); frame = reinterpret_cast(p); - p += (sizeof(struct mad_frame)+7) & ~7; + p += preAllocFrameSize(); synth = reinterpret_cast(p); - p += (sizeof(struct mad_synth)+7) & ~7; + p += preAllocSynthSize(); int neededBytes = p - reinterpret_cast(preallocateSpace); if (neededBytes > preallocateSize) { audioLogger->printf_P("OOM error in MP3: Want %d bytes, have %d bytes preallocated.\n", neededBytes, preallocateSize); diff --git a/src/AudioGeneratorMP3.h b/src/AudioGeneratorMP3.h index 750cecac..0f4e439e 100644 --- a/src/AudioGeneratorMP3.h +++ b/src/AudioGeneratorMP3.h @@ -30,17 +30,31 @@ class AudioGeneratorMP3 : public AudioGenerator public: AudioGeneratorMP3(); AudioGeneratorMP3(void *preallocateSpace, int preallocateSize); + AudioGeneratorMP3(void *buff, int buffSize, void *stream, int streamSize, void *frame, int frameSize, void *synth, int synthSize); virtual ~AudioGeneratorMP3() override; virtual bool begin(AudioFileSource *source, AudioOutput *output) override; virtual bool loop() override; virtual bool stop() override; virtual bool isRunning() override; - + virtual void desync () override; + + static constexpr int preAllocSize () { return preAllocBuffSize() + preAllocStreamSize() + preAllocFrameSize() + preAllocSynthSize(); } + static constexpr int preAllocBuffSize () { return ((buffLen + 7) & ~7); } + static constexpr int preAllocStreamSize () { return ((sizeof(struct mad_stream) + 7) & ~7); } + static constexpr int preAllocFrameSize () { return (sizeof(struct mad_frame) + 7) & ~7; } + static constexpr int preAllocSynthSize () { return (sizeof(struct mad_synth) + 7) & ~7; } + protected: - void *preallocateSpace; - int preallocateSize; + void *preallocateSpace = nullptr; + int preallocateSize = 0; + void *preallocateStreamSpace = nullptr; + int preallocateStreamSize = 0; + void *preallocateFrameSpace = nullptr; + int preallocateFrameSize = 0; + void *preallocateSynthSpace = nullptr; + int preallocateSynthSize = 0; - const int buffLen = 0x600; // Slightly larger than largest MP3 frame + static constexpr int buffLen = 0x600; // Slightly larger than largest MP3 frame unsigned char *buff; int lastReadPos; int lastBuffLen; @@ -62,6 +76,8 @@ class AudioGeneratorMP3 : public AudioGenerator bool DecodeNextFrame(); bool GetOneSample(int16_t sample[2]); + private: + int unrecoverable = 0; }; #endif From 0ec3bc3b31582e914d5ff64955b7db5cecd1cab8 Mon Sep 17 00:00:00 2001 From: Parker Link Date: Sun, 25 Oct 2020 16:09:00 -0600 Subject: [PATCH 025/150] Fix the dependencies in the library's PIO config (#318) PlatformIO requires these dependencies to be explicitly mentioned. Please check the version numbers of the libraries specified are correct. However, v1.0 for each allows for successful builds. Thanks! --- library.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library.json b/library.json index 9aa7c913..13d70bf2 100644 --- a/library.json +++ b/library.json @@ -17,7 +17,10 @@ "version": "1.5.1", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { - "SPI": "1.0" + "SPI": "1.0", + "SPIFFS": "1.0", + "HTTPClient": "1.0", + "WiFiClientSecure": "1.0" }, "frameworks": "Arduino", "examples": [ From 90258c566a5d5326073e44a6c3cc0c862568cf99 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 25 Oct 2020 17:29:12 -0700 Subject: [PATCH 026/150] Fix HTTP redirects with latest releases on ESP8266 (#319) --- library.json | 2 +- src/AudioFileSourceHTTPStream.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 13d70bf2..1a7c3e73 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.5.1", + "version": "1.6", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { "SPI": "1.0", diff --git a/src/AudioFileSourceHTTPStream.cpp b/src/AudioFileSourceHTTPStream.cpp index ed659ee5..09d1e0c5 100644 --- a/src/AudioFileSourceHTTPStream.cpp +++ b/src/AudioFileSourceHTTPStream.cpp @@ -40,7 +40,7 @@ bool AudioFileSourceHTTPStream::open(const char *url) http.begin(client, url); http.setReuse(true); #ifndef ESP32 - http.setFollowRedirects(true); + http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); #endif int code = http.GET(); if (code != HTTP_CODE_OK) { From 299833dbf9543608a116cdedd47f4d36ed342cdf Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 25 Oct 2020 17:30:20 -0700 Subject: [PATCH 027/150] Update to release 1.6 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index baf9c748..80eb0f5a 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.5.1 +version=1.6 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines. From bbd8748f86d1234a2a60f7ff0b7fcb8278812ca2 Mon Sep 17 00:00:00 2001 From: piebrain <72815066+piebrain@users.noreply.github.com> Date: Mon, 26 Oct 2020 21:54:37 -0400 Subject: [PATCH 028/150] Reset errors and avoid memory leak (#321) When reusing the AudioGeneratorMP3 object to play multiple files with errors, the error count was never reset. Also, if 3 errors are encountered, it would stop running but never clean up the buffers. --- src/AudioGeneratorMP3.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/AudioGeneratorMP3.cpp b/src/AudioGeneratorMP3.cpp index 9cc90b7e..d962c9e0 100644 --- a/src/AudioGeneratorMP3.cpp +++ b/src/AudioGeneratorMP3.cpp @@ -231,7 +231,8 @@ bool AudioGeneratorMP3::loop() audioLogger->printf_P(PSTR("MP3:ERROR_BUFLEN %d\n"), unrecoverable); if (++unrecoverable >= 3) { unrecoverable = 0; - return (running = false); + stop(); + return running; } } else { unrecoverable = 0; @@ -269,6 +270,9 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output) return false; // Error } + // Reset error count from previous file + unrecoverable = 0; + output->SetBitsPerSample(16); // Constant for MP3 decoder output->SetChannels(2); From 1c7a2f7cb508578e6bfb37077f26e22186e4b1d3 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 1 Nov 2020 14:02:59 -0800 Subject: [PATCH 029/150] Add output via the ULP for the ESP32 (#326) Code courtesy of Martin Laclaustra. Uses the ULP coprocessor on the ESP32 to send samples to the onboard DACs, freeing the I2S port for other uses. Connect left output to pin 25, right to pin 26. --- src/AudioOutputULP.cpp | 258 +++++++++++++++++++++++++++++++++++++++++ src/AudioOutputULP.h | 63 ++++++++++ 2 files changed, 321 insertions(+) create mode 100644 src/AudioOutputULP.cpp create mode 100644 src/AudioOutputULP.h diff --git a/src/AudioOutputULP.cpp b/src/AudioOutputULP.cpp new file mode 100644 index 00000000..d7bc5f24 --- /dev/null +++ b/src/AudioOutputULP.cpp @@ -0,0 +1,258 @@ +/* + AudioOutputULP + Outputs to ESP32 DAC through the ULP, freeing I2S for other uses + + v 0.0.1 (2020-10-01) + + Copyright (C) 2020 Martin Laclaustra, based on bitluni's code + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ESP32 + +#include "AudioOutputULP.h" +#include +#include +#include +#include +#include + +uint32_t create_I_WR_REG(uint32_t reg, uint32_t low_bit, uint32_t high_bit, uint32_t val){ + typedef union {ulp_insn_t ulp_ins; uint32_t ulp_bin;} ulp_union; + const ulp_insn_t singleinstruction[] = {I_WR_REG(reg, low_bit, high_bit, val)}; + ulp_union recover_ins; + recover_ins.ulp_ins=singleinstruction[0]; + return (uint32_t)(recover_ins.ulp_bin); +} + +uint32_t create_I_BXI(uint32_t imm_pc){ + typedef union {ulp_insn_t ulp_ins; uint32_t ulp_bin;} ulp_union; + const ulp_insn_t singleinstruction[] = {I_BXI(imm_pc)}; + ulp_union recover_ins; + recover_ins.ulp_ins=singleinstruction[0]; + return (uint32_t)(recover_ins.ulp_bin); +} + +bool AudioOutputULP::begin() +{ + if(!stereoOutput){ + waitingOddSample = false; + //totalSampleWords += 512; + //dacTableStart2 = dacTableStart1; + } + + //calculate the actual ULP clock + unsigned long rtc_8md256_period = rtc_clk_cal(RTC_CAL_8MD256, 1000); + unsigned long rtc_fast_freq_hz = 1000000ULL * (1 << RTC_CLK_CAL_FRACT) * 256 / rtc_8md256_period; + + //initialize DACs + if(activeDACs & 1){ + dac_output_enable(DAC_CHANNEL_1); + dac_output_voltage(DAC_CHANNEL_1, 128); + } + if(activeDACs & 2){ + dac_output_enable(DAC_CHANNEL_2); + dac_output_voltage(DAC_CHANNEL_2, 128); + } + + int retAddress1 = 9; + int retAddress2 = 14; + + int loopCycles = 120; + int loopHalfCycles1 = 76; + int loopHalfCycles2 = 44; + + Serial.print("Real RTC clock: "); + Serial.println(rtc_fast_freq_hz); + + uint32_t dt = (rtc_fast_freq_hz / hertz) - loopCycles; + uint32_t dt2 = 0; + if(!stereoOutput){ + dt = (rtc_fast_freq_hz / hertz) - loopHalfCycles1; + dt2 = (rtc_fast_freq_hz / hertz) - loopHalfCycles2; + } + + Serial.print("dt: "); + Serial.println(dt); + + Serial.print("dt2: "); + Serial.println(dt2); + + const ulp_insn_t stereo[] = { + //reset offset register + I_MOVI(R3, 0), + //delay to get the right sampling rate + I_DELAY(dt), // 6 + dt + //reset sample index + I_MOVI(R0, 0), // 6 + //write the index back to memory for the main cpu + I_ST(R0, R3, indexAddress), // 8 + //load the samples + I_LD(R1, R0, bufferStart), // 8 + //mask the lower 8 bits + I_ANDI(R2, R1, 0x00ff), // 6 + //multiply by 2 + I_LSHI(R2, R2, 1), // 6 + //add start position + I_ADDI(R2, R2, dacTableStart1),// 6 + //jump to the dac opcode + I_BXR(R2), // 4 + //back from first dac + //delay between the two samples in mono rendering + I_DELAY(dt2), // 6 + dt2 + //mask the upper 8 bits + I_ANDI(R2, R1, 0xff00), // 6 + //shift the upper bits to right and multiply by 2 + I_RSHI(R2, R2, 8 - 1), // 6 + //add start position of second dac table + I_ADDI(R2, R2, dacTableStart2),// 6 + //jump to the dac opcode + I_BXR(R2), // 4 + //here we get back from writing the second sample + //increment the sample index + I_ADDI(R0, R0, 1), // 6 + //if reached end of the buffer, jump relative to index reset + I_BGE(-14, totalSampleWords), // 4 + //wait to get the right sample rate (2 cycles more to compensate the index reset) + I_DELAY((unsigned int)dt + 2), // 8 + dt + //if not, jump absolute to where index is written to memory + I_BXI(3) // 4 + }; + // write io and jump back another 12 + 4 + 12 + 4 + + size_t load_addr = 0; + size_t size = sizeof(stereo)/sizeof(ulp_insn_t); + ulp_process_macros_and_load(load_addr, stereo, &size); + // this is how to get the opcodes + // for(int i = 0; i < size; i++) + // Serial.println(RTC_SLOW_MEM[i], HEX); + + //create DAC opcode tables + switch(activeDACs){ + case 1: + for(int i = 0; i < 256; i++) + { + RTC_SLOW_MEM[dacTableStart1 + i * 2] = create_I_WR_REG(RTC_IO_PAD_DAC1_REG,19,26,i); //dac1: 0x1D4C0121 | (i << 10) + RTC_SLOW_MEM[dacTableStart1 + 1 + i * 2] = create_I_BXI(retAddress1); // 0x80000000 + retAddress1 * 4 + RTC_SLOW_MEM[dacTableStart2 + i * 2] = create_I_WR_REG(RTC_IO_PAD_DAC1_REG,19,26,i); //dac2: 0x1D4C0122 | (i << 10) + RTC_SLOW_MEM[dacTableStart2 + 1 + i * 2] = create_I_BXI(retAddress2); // 0x80000000 + retAddress2 * 4 + } + break; + case 2: + for(int i = 0; i < 256; i++) + { + RTC_SLOW_MEM[dacTableStart1 + i * 2] = create_I_WR_REG(RTC_IO_PAD_DAC2_REG,19,26,i); //dac1: 0x1D4C0121 | (i << 10) + RTC_SLOW_MEM[dacTableStart1 + 1 + i * 2] = create_I_BXI(retAddress1); // 0x80000000 + retAddress1 * 4 + RTC_SLOW_MEM[dacTableStart2 + i * 2] = create_I_WR_REG(RTC_IO_PAD_DAC2_REG,19,26,i); //dac2: 0x1D4C0122 | (i << 10) + RTC_SLOW_MEM[dacTableStart2 + 1 + i * 2] = create_I_BXI(retAddress2); // 0x80000000 + retAddress2 * 4 + } + break; + case 3: + for(int i = 0; i < 256; i++) + { + RTC_SLOW_MEM[dacTableStart1 + i * 2] = create_I_WR_REG(RTC_IO_PAD_DAC1_REG,19,26,i); //dac1: 0x1D4C0121 | (i << 10) + RTC_SLOW_MEM[dacTableStart1 + 1 + i * 2] = create_I_BXI(retAddress1); // 0x80000000 + retAddress1 * 4 + RTC_SLOW_MEM[dacTableStart2 + i * 2] = create_I_WR_REG(RTC_IO_PAD_DAC1_REG,19,26,i); //dac2: 0x1D4C0122 | (i << 10) + RTC_SLOW_MEM[dacTableStart2 + 1 + i * 2] = create_I_BXI(retAddress2); // 0x80000000 + retAddress2 * 4 + } + break; + } + + //set all samples to 128 (silence) + for(int i = 0; i < totalSampleWords; i++) + RTC_SLOW_MEM[bufferStart + i] = 0x8080; + + //start + RTC_SLOW_MEM[indexAddress] = 0; + ulp_run(0); + + //wait until ULP starts using samples and the index of output sample advances + while(RTC_SLOW_MEM[indexAddress] == 0) + delay(1); + + return true; +} + +bool AudioOutputULP::ConsumeSample(int16_t sample[2]) +{ + int16_t ms[2]; + ms[0] = sample[0]; + ms[1] = sample[1]; + MakeSampleStereo16( ms ); + + // TODO: needs improvement (counting is different here with respect to ULP code) + int currentSample = RTC_SLOW_MEM[indexAddress] & 0xffff; + int currentWord = currentSample >> 1; + + for (int i=0; i<2; i++) { + ms[i] = ((ms[i] >> 8) + 128) & 0xff; + } + if(!stereoOutput) // mix both channels + ms[0] = (uint16_t)(( (uint32_t)((int32_t)(ms[0]) + (int32_t)(ms[1])) >> 1 ) & 0xff); + + if(waitingOddSample){ // always true for stereo because samples are consumed in pairs + if(lastFilledWord != currentWord) // accept sample if writing index lastFilledWord has not reached index of output sample + { + unsigned int w = ms[0]; + if(stereoOutput){ + w |= ms[1] << 8; + } else { + w |= bufferedOddSample << 8; + bufferedOddSample = 128; + waitingOddSample = false; + } + RTC_SLOW_MEM[bufferStart + lastFilledWord] = w; + lastFilledWord++; + if(lastFilledWord == totalSampleWords) + lastFilledWord = 0; + return true; + } else { + return false; + } + } else { + bufferedOddSample = ms[0]; + waitingOddSample = true; + return true; + } +} + + +bool AudioOutputULP::stop() +{ + audioLogger->printf_P(PSTR("\n\n\nstop\n\n\n")); + const ulp_insn_t stopulp[] = { + //stop the timer + I_END(), + //end the program + I_HALT()}; + + size_t load_addr = 0; + size_t size = sizeof(stopulp)/sizeof(ulp_insn_t); + ulp_process_macros_and_load(load_addr, stopulp, &size); + + //start + ulp_run(0); + + if(activeDACs & 1){ + dac_output_voltage(DAC_CHANNEL_1, 128); + } + if(activeDACs & 2){ + dac_output_voltage(DAC_CHANNEL_2, 128); + } + + return true; +} + +#endif diff --git a/src/AudioOutputULP.h b/src/AudioOutputULP.h new file mode 100644 index 00000000..4fc0e95f --- /dev/null +++ b/src/AudioOutputULP.h @@ -0,0 +1,63 @@ +/* + AudioOutputULP + Outputs to ESP32 DAC through the ULP, freeing I2S for other uses + + v 0.0.1 (2020-10-01) + + Copyright (C) 2020 Martin Laclaustra, based on bitluni's code + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +// Connect left channel on pin 25 +// Connect right channel on pin 26 + +#ifndef _AUDIOOUTPUTULP_H +#define _AUDIOOUTPUTULP_H + +#include "AudioOutput.h" + +#ifdef ESP32 + +class AudioOutputULP : public AudioOutput +{ + public: + AudioOutputULP(int argActiveDACs=3) {if(argActiveDACs<1||argActiveDACs>2)argActiveDACs=3;activeDACs=argActiveDACs;stereoOutput=activeDACs==3;}; + ~AudioOutputULP() {}; + virtual bool begin() override; + virtual bool ConsumeSample(int16_t sample[2]) override; + virtual bool stop() override; + enum : int { DAC1 = 1, DAC2 = 2 }; + private: + int lastFilledWord = 0; + uint8_t bufferedOddSample = 128; + bool waitingOddSample = true; // must be set to false for mono output + int activeDACs = 3; // 1:DAC1; 2:DAC2; 3:both; + bool stereoOutput = true; + const int opcodeCount = 18; + const uint32_t dacTableStart1 = 2048 - 512; + const uint32_t dacTableStart2 = dacTableStart1 - 512; + uint32_t totalSampleWords = 2048 - 512 - 512 - (opcodeCount + 1); // add 512 for mono + const int totalSamples = totalSampleWords * 2; + const uint32_t indexAddress = opcodeCount; + const uint32_t bufferStart = indexAddress + 1; +}; + +#else + +#error Only the ESP32 supports ULP audio output + +#endif + +#endif From 0c4c9e163770483e34710072db8bfb86e29ca09c Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 14 Nov 2020 10:40:16 -0800 Subject: [PATCH 030/150] Update to release 1.7.0 (#333) --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 1a7c3e73..185eadbf 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.6", + "version": "1.7", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { "SPI": "1.0", diff --git a/library.properties b/library.properties index 80eb0f5a..3a621460 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.6 +version=1.7 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines. From 299db3d03d7de2047167a8a0a5eb8a4734b3cbf4 Mon Sep 17 00:00:00 2001 From: Adamcbrz Date: Sat, 14 Nov 2020 13:02:48 -0600 Subject: [PATCH 031/150] Modify AudioOutputI2S to initialize i2s during begin (#331) Fixes #330 --- src/AudioOutputI2S.cpp | 276 ++++++++++++++++++++++++----------------- src/AudioOutputI2S.h | 6 + 2 files changed, 167 insertions(+), 115 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index f7e194ea..e575472f 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -35,113 +35,77 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int output_mode = EXTERNAL_I2S; } this->output_mode = output_mode; -#ifdef ESP32 - if (!i2sOn) { - if (use_apll == APLL_AUTO) { - // don't use audio pll on buggy rev0 chips - use_apll = APLL_DISABLE; - esp_chip_info_t out_info; - esp_chip_info(&out_info); - if(out_info.revision > 0) { - use_apll = APLL_ENABLE; - } - } - - i2s_mode_t mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); - if (output_mode == INTERNAL_DAC) { - mode = (i2s_mode_t)(mode | I2S_MODE_DAC_BUILT_IN); - } else if (output_mode == INTERNAL_PDM) { - mode = (i2s_mode_t)(mode | I2S_MODE_PDM); - } - - i2s_comm_format_t comm_fmt = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); - if (output_mode == INTERNAL_DAC) { - comm_fmt = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB; - } + this->use_apll = use_apll; - i2s_config_t i2s_config_dac = { - .mode = mode, - .sample_rate = 44100, - .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, - .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, - .communication_format = comm_fmt, - .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // lowest interrupt priority - .dma_buf_count = dma_buf_count, - .dma_buf_len = 64, - .use_apll = use_apll // Use audio PLL - }; - audioLogger->printf("+%d %p\n", portNo, &i2s_config_dac); - if (i2s_driver_install((i2s_port_t)portNo, &i2s_config_dac, 0, NULL) != ESP_OK) { - audioLogger->println("ERROR: Unable to install I2S drives\n"); - } - if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) { - i2s_set_pin((i2s_port_t)portNo, NULL); - i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); - } else { - SetPinout(26, 25, 22); - } - i2s_zero_dma_buffer((i2s_port_t)portNo); - } -#else - (void) dma_buf_count; - (void) use_apll; - if (!i2sOn) { - orig_bck = READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U); - orig_ws = READ_PERI_REG(PERIPHS_IO_MUX_GPIO2_U); - i2s_begin(); - } -#endif - i2sOn = true; + //set defaults mono = false; bps = 16; channels = 2; + hertz = 44100; + bclkPin = 26; + wclkPin = 25; + doutPin = 22; SetGain(1.0); - SetRate(44100); // Default } AudioOutputI2S::~AudioOutputI2S() { -#ifdef ESP32 - if (i2sOn) { - audioLogger->printf("UNINSTALL I2S\n"); - i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver - } -#else - if (i2sOn) i2s_end(); -#endif + #ifdef ESP32 + if (i2sOn) { + audioLogger->printf("UNINSTALL I2S\n"); + i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver + } + #else + if (i2sOn) + i2s_end(); + #endif i2sOn = false; } bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout) { -#ifdef ESP32 - if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) return false; // Not allowed - - i2s_pin_config_t pins = { - .bck_io_num = bclk, - .ws_io_num = wclk, - .data_out_num = dout, - .data_in_num = I2S_PIN_NO_CHANGE - }; - i2s_set_pin((i2s_port_t)portNo, &pins); + bclkPin = bclk; + wclkPin = wclk; + doutPin = dout; + if (i2sOn) + return SetPinout(); + return true; -#else - (void) bclk; - (void) wclk; - (void) dout; - return false; -#endif +} + +bool AudioOutputI2S::SetPinout() +{ + #ifdef ESP32 + if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) + return false; // Not allowed + + i2s_pin_config_t pins = { + .bck_io_num = bclkPin, + .ws_io_num = wclkPin, + .data_out_num = doutPin, + .data_in_num = I2S_PIN_NO_CHANGE}; + i2s_set_pin((i2s_port_t)portNo, &pins); + return true; + #else + (void)bclkPin; + (void)wclkPin; + (void)doutPin; + return false; + #endif } bool AudioOutputI2S::SetRate(int hz) { // TODO - have a list of allowable rates from constructor, check them this->hertz = hz; -#ifdef ESP32 - i2s_set_sample_rates((i2s_port_t)portNo, AdjustI2SRate(hz)); -#else - i2s_set_rate(AdjustI2SRate(hz)); -#endif + if (i2sOn) + { + #ifdef ESP32 + i2s_set_sample_rates((i2s_port_t)portNo, AdjustI2SRate(hz)); + #else + i2s_set_rate(AdjustI2SRate(hz)); + #endif + } return true; } @@ -167,11 +131,86 @@ bool AudioOutputI2S::SetOutputModeMono(bool mono) bool AudioOutputI2S::begin() { + #ifdef ESP32 + if (!i2sOn) + { + if (use_apll == APLL_AUTO) + { + // don't use audio pll on buggy rev0 chips + use_apll = APLL_DISABLE; + esp_chip_info_t out_info; + esp_chip_info(&out_info); + if (out_info.revision > 0) + { + use_apll = APLL_ENABLE; + } + } + + i2s_mode_t mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); + if (output_mode == INTERNAL_DAC) + { + mode = (i2s_mode_t)(mode | I2S_MODE_DAC_BUILT_IN); + } + else if (output_mode == INTERNAL_PDM) + { + mode = (i2s_mode_t)(mode | I2S_MODE_PDM); + } + + i2s_comm_format_t comm_fmt = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); + if (output_mode == INTERNAL_DAC) + { + comm_fmt = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB; + } + + i2s_config_t i2s_config_dac = { + .mode = mode, + .sample_rate = 44100, + .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, + .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, + .communication_format = comm_fmt, + .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // lowest interrupt priority + .dma_buf_count = dma_buf_count, + .dma_buf_len = 64, + .use_apll = use_apll // Use audio PLL + }; + audioLogger->printf("+%d %p\n", portNo, &i2s_config_dac); + if (i2s_driver_install((i2s_port_t)portNo, &i2s_config_dac, 0, NULL) != ESP_OK) + { + audioLogger->println("ERROR: Unable to install I2S drives\n"); + } + if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) + { + i2s_set_pin((i2s_port_t)portNo, NULL); + i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); + } + else + { + SetPinout(); + } + i2s_zero_dma_buffer((i2s_port_t)portNo); + } + #else + (void)dma_buf_count; + (void)use_apll; + if (!i2sOn) + { + orig_bck = READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U); + orig_ws = READ_PERI_REG(PERIPHS_IO_MUX_GPIO2_U); + i2s_begin(); + } + #endif + i2sOn = true; + SetRate(hertz); // Default return true; } bool AudioOutputI2S::ConsumeSample(int16_t sample[2]) { + + //return if we haven't called ::begin yet + if (!i2sOn) + return false; + int16_t ms[2]; ms[0] = sample[0]; @@ -183,41 +222,48 @@ bool AudioOutputI2S::ConsumeSample(int16_t sample[2]) int32_t ttl = ms[LEFTCHANNEL] + ms[RIGHTCHANNEL]; ms[LEFTCHANNEL] = ms[RIGHTCHANNEL] = (ttl>>1) & 0xffff; } -#ifdef ESP32 - uint32_t s32; - if (output_mode == INTERNAL_DAC) { - int16_t l = Amplify(ms[LEFTCHANNEL]) + 0x8000; - int16_t r = Amplify(ms[RIGHTCHANNEL]) + 0x8000; - s32 = (r<<16) | (l&0xffff); - } else { - s32 = ((Amplify(ms[RIGHTCHANNEL]))<<16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); - } - return i2s_write_bytes((i2s_port_t)portNo, (const char*)&s32, sizeof(uint32_t), 0); -#else - uint32_t s32 = ((Amplify(ms[RIGHTCHANNEL]))<<16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); - return i2s_write_sample_nb(s32); // If we can't store it, return false. OTW true -#endif + #ifdef ESP32 + uint32_t s32; + if (output_mode == INTERNAL_DAC) + { + int16_t l = Amplify(ms[LEFTCHANNEL]) + 0x8000; + int16_t r = Amplify(ms[RIGHTCHANNEL]) + 0x8000; + s32 = (r << 16) | (l & 0xffff); + } + else + { + s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); + } + return i2s_write_bytes((i2s_port_t)portNo, (const char *)&s32, sizeof(uint32_t), 0); + #else + uint32_t s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); + return i2s_write_sample_nb(s32); // If we can't store it, return false. OTW true + #endif } -void AudioOutputI2S::flush() { -#ifdef ESP32 - // makes sure that all stored DMA samples are consumed / played - int buffersize = 64 * this->dma_buf_count; - int16_t samples[2] = {0x0,0x0}; - for (int i=0;idma_buf_count; + int16_t samples[2] = {0x0, 0x0}; + for (int i = 0; i < buffersize; i++) + { + while (!ConsumeSample(samples)) + { + delay(10); + } } - } -#endif + #endif } bool AudioOutputI2S::stop() { -#ifdef ESP32 - i2s_zero_dma_buffer((i2s_port_t)portNo); -#endif + if (!i2sOn) + return false; + + #ifdef ESP32 + i2s_zero_dma_buffer((i2s_port_t)portNo); + #endif return true; } - - diff --git a/src/AudioOutputI2S.h b/src/AudioOutputI2S.h index 6070ca4e..3e881e7b 100644 --- a/src/AudioOutputI2S.h +++ b/src/AudioOutputI2S.h @@ -43,15 +43,21 @@ class AudioOutputI2S : public AudioOutput enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 }; protected: + bool SetPinout(); virtual int AdjustI2SRate(int hz) { return hz; } uint8_t portNo; int output_mode; bool mono; bool i2sOn; int dma_buf_count; + int use_apll; // We can restore the old values and free up these pins when in NoDAC mode uint32_t orig_bck; uint32_t orig_ws; + + uint8_t bclkPin; + uint8_t wclkPin; + uint8_t doutPin; }; #endif From 7f3908c239a45316c742ff3db359725f28298d4b Mon Sep 17 00:00:00 2001 From: Pierre-Loup M Date: Sun, 15 Nov 2020 19:20:21 +0100 Subject: [PATCH 032/150] Modified AudioFileSourceFS.h to add resolution operator on items defined into the fs namespace in esp32 libraries. (#335) Co-authored-by: Pierre-Loup Martin --- src/AudioFileSourceFS.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/AudioFileSourceFS.h b/src/AudioFileSourceFS.h index fea34c29..4e1cb8ec 100644 --- a/src/AudioFileSourceFS.h +++ b/src/AudioFileSourceFS.h @@ -29,8 +29,8 @@ class AudioFileSourceFS : public AudioFileSource { public: - AudioFileSourceFS(FS &fs) { filesystem = &fs; } - AudioFileSourceFS(FS &fs, const char *filename); + AudioFileSourceFS(fs::FS &fs) { filesystem = &fs; } + AudioFileSourceFS(fs::FS &fs, const char *filename); virtual ~AudioFileSourceFS() override; virtual bool open(const char *filename) override; @@ -42,8 +42,8 @@ class AudioFileSourceFS : public AudioFileSource virtual uint32_t getPos() override { if (!f) return 0; else return f.position(); }; private: - FS *filesystem; - File f; + fs::FS *filesystem; + fs::File f; }; From 2dc245ff2ecd9a0d89577afb82d6698624ebfd7c Mon Sep 17 00:00:00 2001 From: Pierre-Loup M Date: Mon, 16 Nov 2020 19:02:57 +0100 Subject: [PATCH 033/150] Fix tags framesize endless loop, add add'l tag support (#336) * Modified AudioFileSourceFS.h to add resolution operator on items defined into the fs namespace in esp32 libraries. * Added track, set, popularimeter, compilation tags. Changed framesize loop with 32bit counter to avoid endless loops for large frames (like APIC). Co-authored-by: Pierre-Loup Martin --- src/AudioFileSourceID3.cpp | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/AudioFileSourceID3.cpp b/src/AudioFileSourceID3.cpp index 1723b8d4..7e79e6e0 100644 --- a/src/AudioFileSourceID3.cpp +++ b/src/AudioFileSourceID3.cpp @@ -143,6 +143,7 @@ uint32_t AudioFileSourceID3::read(void *data, uint32_t len) if (ret<10) return ret; if ((buff[0]!='I') || (buff[1]!='D') || (buff[2]!='3') || (buff[3]>0x04) || (buff[3]<0x02) || (buff[4]!=0)) { + cb.md("eof", false, "id3"); return 10 + src->read(buff+10, len-10); } @@ -212,7 +213,7 @@ uint32_t AudioFileSourceID3::read(void *data, uint32_t len) // Read the value and send to callback char value[64]; - uint16_t i; + uint32_t i; bool isUnicode = (id3.getByte()==1) ? true : false; for (i=0; iread(data, len); } From 1c548c884646f7a91d599910bfe56db5746035fa Mon Sep 17 00:00:00 2001 From: Martin-Laclaustra Date: Mon, 23 Nov 2020 21:30:56 +0100 Subject: [PATCH 034/150] Fixes for the ULP driver (#340) * Fix the order of mono samples (each pair was swapped) * Remove comment on version and date (currently tracked within ESP8266Audio repo) * Added some usage instructions to the header file * Delete sample in buffer after being rendered (ULP) to avoid sound looping in the buffer at the end of playback Co-authored-by: Martin-Laclaustra --- src/AudioOutputULP.cpp | 18 +++++++++++------- src/AudioOutputULP.h | 12 +++++++++--- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/AudioOutputULP.cpp b/src/AudioOutputULP.cpp index d7bc5f24..63177e3a 100644 --- a/src/AudioOutputULP.cpp +++ b/src/AudioOutputULP.cpp @@ -2,8 +2,6 @@ AudioOutputULP Outputs to ESP32 DAC through the ULP, freeing I2S for other uses - v 0.0.1 (2020-10-01) - Copyright (C) 2020 Martin Laclaustra, based on bitluni's code This program is free software: you can redistribute it and/or modify @@ -70,8 +68,8 @@ bool AudioOutputULP::begin() int retAddress1 = 9; int retAddress2 = 14; - int loopCycles = 120; - int loopHalfCycles1 = 76; + int loopCycles = 134; + int loopHalfCycles1 = 90; int loopHalfCycles2 = 44; Serial.print("Real RTC clock: "); @@ -121,10 +119,14 @@ bool AudioOutputULP::begin() //jump to the dac opcode I_BXR(R2), // 4 //here we get back from writing the second sample + //load 0x8080 as sample + I_MOVI(R1, 0x8080), // 6 + //write 0x8080 in the sample buffer + I_ST(R1, R0, indexAddress), // 8 //increment the sample index I_ADDI(R0, R0, 1), // 6 //if reached end of the buffer, jump relative to index reset - I_BGE(-14, totalSampleWords), // 4 + I_BGE(-16, totalSampleWords), // 4 //wait to get the right sample rate (2 cycles more to compensate the index reset) I_DELAY((unsigned int)dt + 2), // 8 + dt //if not, jump absolute to where index is written to memory @@ -205,11 +207,13 @@ bool AudioOutputULP::ConsumeSample(int16_t sample[2]) if(waitingOddSample){ // always true for stereo because samples are consumed in pairs if(lastFilledWord != currentWord) // accept sample if writing index lastFilledWord has not reached index of output sample { - unsigned int w = ms[0]; + unsigned int w; if(stereoOutput){ + w = ms[0]; w |= ms[1] << 8; } else { - w |= bufferedOddSample << 8; + w = bufferedOddSample; + w |= ms[0] << 8; bufferedOddSample = 128; waitingOddSample = false; } diff --git a/src/AudioOutputULP.h b/src/AudioOutputULP.h index 4fc0e95f..fc4e438c 100644 --- a/src/AudioOutputULP.h +++ b/src/AudioOutputULP.h @@ -2,8 +2,6 @@ AudioOutputULP Outputs to ESP32 DAC through the ULP, freeing I2S for other uses - v 0.0.1 (2020-10-01) - Copyright (C) 2020 Martin Laclaustra, based on bitluni's code This program is free software: you can redistribute it and/or modify @@ -20,8 +18,16 @@ along with this program. If not, see . */ +// Instructions: +// AudioOutputULP out = new AudioOutputULP(); // stereo // Connect left channel on pin 25 // Connect right channel on pin 26 +// OR +// Connect mono channel on either of them (stereo samples are downmixed) +// AudioOutputULP out = new AudioOutputULP(1); // mono, only DAC 1 +// OR +// AudioOutputULP out = new AudioOutputULP(2); // mono, only DAC 2 + #ifndef _AUDIOOUTPUTULP_H #define _AUDIOOUTPUTULP_H @@ -45,7 +51,7 @@ class AudioOutputULP : public AudioOutput bool waitingOddSample = true; // must be set to false for mono output int activeDACs = 3; // 1:DAC1; 2:DAC2; 3:both; bool stereoOutput = true; - const int opcodeCount = 18; + const int opcodeCount = 20; const uint32_t dacTableStart1 = 2048 - 512; const uint32_t dacTableStart2 = dacTableStart1 - 512; uint32_t totalSampleWords = 2048 - 512 - 512 - (opcodeCount + 1); // add 512 for mono From e65cc0fab00467364a25005d55ac58272621bab5 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 8 Dec 2020 10:25:27 -0800 Subject: [PATCH 035/150] Remove assert() redefinition warnings --- src/libmad/global.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libmad/global.h b/src/libmad/global.h index a6debfd8..a688495f 100644 --- a/src/libmad/global.h +++ b/src/libmad/global.h @@ -48,6 +48,7 @@ # endif # if !defined(HAVE_ASSERT_H) +# undef assert # if defined(NDEBUG) # define assert(x) /* nothing */ # else From dd8ac07e4e95e07a6788d926b563a6242061ca37 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 8 Dec 2020 10:29:35 -0800 Subject: [PATCH 036/150] Remove ID3 signedness warning --- src/AudioFileSourceID3.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioFileSourceID3.cpp b/src/AudioFileSourceID3.cpp index 7e79e6e0..2a22bb18 100644 --- a/src/AudioFileSourceID3.cpp +++ b/src/AudioFileSourceID3.cpp @@ -215,7 +215,7 @@ uint32_t AudioFileSourceID3::read(void *data, uint32_t len) char value[64]; uint32_t i; bool isUnicode = (id3.getByte()==1) ? true : false; - for (i=0; i Date: Sat, 12 Dec 2020 01:46:07 +0100 Subject: [PATCH 037/150] Fix for esp8266 I2S/NoDAC (#344) * esp8266: Allows I2S-NoDAC to use only I2S-out-data GPIO avoiding conflicts with repurposed GPIO, especially conflicting with SDFS. * +message * new upstream API update * check i2s_begin's return value --- src/AudioOutputI2S.cpp | 15 +++++++++++++-- src/AudioOutputI2S.h | 3 ++- src/AudioOutputI2SNoDAC.h | 1 + 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index e575472f..6d0762db 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -129,7 +129,7 @@ bool AudioOutputI2S::SetOutputModeMono(bool mono) return true; } -bool AudioOutputI2S::begin() +bool AudioOutputI2S::begin(bool txDAC) { #ifdef ESP32 if (!i2sOn) @@ -196,7 +196,18 @@ bool AudioOutputI2S::begin() { orig_bck = READ_PERI_REG(PERIPHS_IO_MUX_MTDO_U); orig_ws = READ_PERI_REG(PERIPHS_IO_MUX_GPIO2_U); - i2s_begin(); + #ifdef I2S_HAS_BEGIN_RXTX_DRIVE_CLOCKS + if (!i2s_rxtxdrive_begin(false, true, false, txDAC)) { + return false; + } + #else + if (!i2s_rxtx_begin(false, true)) { + return false; + } + if (!txDAC) { + audioLogger->printf_P(PSTR("I2SNoDAC: esp8266 arduino core should be upgraded to avoid conflicts with SPI\n")); + } + #endif } #endif i2sOn = true; diff --git a/src/AudioOutputI2S.h b/src/AudioOutputI2S.h index 3e881e7b..f221d2e4 100644 --- a/src/AudioOutputI2S.h +++ b/src/AudioOutputI2S.h @@ -32,11 +32,12 @@ class AudioOutputI2S : public AudioOutput virtual bool SetRate(int hz) override; virtual bool SetBitsPerSample(int bits) override; virtual bool SetChannels(int channels) override; - virtual bool begin() override; + virtual bool begin() override { return begin(true); } virtual bool ConsumeSample(int16_t sample[2]) override; virtual void flush() override; virtual bool stop() override; + bool begin (bool txDAC); bool SetOutputModeMono(bool mono); // Force mono output no matter the input enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 }; diff --git a/src/AudioOutputI2SNoDAC.h b/src/AudioOutputI2SNoDAC.h index b5f32145..d1738d19 100644 --- a/src/AudioOutputI2SNoDAC.h +++ b/src/AudioOutputI2SNoDAC.h @@ -28,6 +28,7 @@ class AudioOutputI2SNoDAC : public AudioOutputI2S public: AudioOutputI2SNoDAC(int port = 0); virtual ~AudioOutputI2SNoDAC() override; + virtual bool begin() override { return AudioOutputI2S::begin(false); } virtual bool ConsumeSample(int16_t sample[2]) override; bool SetOversampling(int os); From 7cb02a69860e53902160ae00a15efb8458a59ac3 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 29 Dec 2020 08:42:08 -0800 Subject: [PATCH 038/150] Ensure only 1 ICY packet processed per reading (#356) Thanks to @cjwhoishe, fixes #355 . When a large enough read size was requested it is possible that for some streams multiple ICY blocks could appear. The logic doesn't support that, so only read up to 1/2 the ICY block interval to ensure there is no way to see two ICY blocks in one readInternal call. --- src/AudioFileSourceICYStream.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/AudioFileSourceICYStream.cpp b/src/AudioFileSourceICYStream.cpp index cc7cc5e2..ac03f610 100644 --- a/src/AudioFileSourceICYStream.cpp +++ b/src/AudioFileSourceICYStream.cpp @@ -83,6 +83,8 @@ AudioFileSourceICYStream::~AudioFileSourceICYStream() uint32_t AudioFileSourceICYStream::readInternal(void *data, uint32_t len, bool nonBlock) { + // Ensure we can't possibly read 2 ICY headers in a single go #355 + len = std::min((int)(icyMetaInt >> 1), (int)len); retry: if (!http.connected()) { cb.st(STATUS_DISCONNECTED, PSTR("Stream disconnected")); From b832ec24348346a84c320a8cbe6ead5415dc721a Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 2 Jan 2021 11:02:07 -0800 Subject: [PATCH 039/150] Work around Arduino-Builder bug causing ESP8266 build fail (#358) Thanks to @d-a-v for the debug! --- tests/common.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index cabad512..fab4e590 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -93,9 +93,11 @@ function install_libraries() function install_ide() { local ide_path=$1 - wget -q -O arduino.tar.xz https://www.arduino.cc/download.php?f=/arduino-nightly-linux64.tar.xz + local idever='1.8.10' + local ideurl="https://downloads.arduino.cc/arduino-$idever" + wget -q -O arduino.tar.xz "${ideurl}-linux64.tar.xz" tar xf arduino.tar.xz - mv arduino-nightly $ide_path + mv arduino-${idever} $ide_path export PATH="$ide_path:$PATH" } From 0cee4d410e9a618d63d374982badb5cf4e3e46b5 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Sun, 3 Jan 2021 00:09:01 +0100 Subject: [PATCH 040/150] Proposal for various tiny fixes (#357) * replace a disappeared shoutcast url by a working one from another example * increase a buffer size (found by valgrind) * make emulated example closer to the not emulated one use `./onHost diff` to show the diff -u * add `diff` option to onHost script * add a delay to local copy of AudioOutputNull * increase another buffer size * make AudioOutputNullSlow.h compatible with arduino api (not only emulation on host) --- .../StreamMP3FromHTTP/StreamMP3FromHTTP.ino | 2 +- examples/StreamOnHost/AudioOutputNullSlow.h | 54 +++++++++++++++++++ examples/StreamOnHost/StreamOnHost.ino | 16 +++--- examples/StreamOnHost/onHost | 16 ++++-- src/AudioFileSourceHTTPStream.cpp | 2 +- src/AudioFileSourceICYStream.cpp | 6 ++- 6 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 examples/StreamOnHost/AudioOutputNullSlow.h diff --git a/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino b/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino index 8ea45157..84d7d5b3 100644 --- a/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino +++ b/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino @@ -22,7 +22,7 @@ const char* ssid = STASSID; const char* password = STAPSK; // Randomly picked URL -const char *URL="http://streaming.shoutcast.com/80sPlanet?lang=en-US"; +const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; AudioGeneratorMP3 *mp3; AudioFileSourceICYStream *file; diff --git a/examples/StreamOnHost/AudioOutputNullSlow.h b/examples/StreamOnHost/AudioOutputNullSlow.h new file mode 100644 index 00000000..95548f6b --- /dev/null +++ b/examples/StreamOnHost/AudioOutputNullSlow.h @@ -0,0 +1,54 @@ +/* + AudioOutput + Base class of an audio output player + + Copyright (C) 2017 Earle F. Philhower, III + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _AUDIOOUTPUTNULLSLOW_H +#define _AUDIOOUTPUTNULLSLOW_H + +#include "AudioOutput.h" + +class AudioOutputNullSlow : public AudioOutput +{ + public: + AudioOutputNullSlow(int hertz) { SetRate(hertz); }; + ~AudioOutputNullSlow() {}; + virtual bool begin() { samples = 0; startms = millis(); return true; } + virtual bool ConsumeSample(int16_t sample[2]) { + // return false (= output buffer full) + // sometimes to let the main loop running + constexpr int everylog2 = 10; + if ((++samples & ((1<> everylog2)); + return false; + } + return true; + } + virtual bool stop() { endms = millis(); return true; }; + unsigned long GetMilliseconds() { return endms - startms; } + int GetSamples() { return samples; } + int GetFrequency() { return hertz; } + + protected: + unsigned long startms; + unsigned long endms; + int samples; +}; + +#endif + diff --git a/examples/StreamOnHost/StreamOnHost.ino b/examples/StreamOnHost/StreamOnHost.ino index 4f79777d..e2a66f70 100644 --- a/examples/StreamOnHost/StreamOnHost.ino +++ b/examples/StreamOnHost/StreamOnHost.ino @@ -8,27 +8,27 @@ #include "AudioFileSourceICYStream.h" #include "AudioFileSourceBuffer.h" #include "AudioGeneratorMP3.h" -#include "AudioOutputNull.h" +#include "AudioOutputNullSlow.h" // To run, set your ESP8266 build to 160MHz, update the SSID info, and upload. // Enter your WiFi setup here: #ifndef STASSID -#define STASSID "" -#define STAPSK "" +#define STASSID "your-ssid" +#define STAPSK "your-password" #endif const char* ssid = STASSID; const char* password = STAPSK; // Randomly picked URL -const char *URL="http://icecast.radiofrance.fr/franceinter-lofi.mp3"; -//const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; +const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; +//const char *URL="http://icecast.radiofrance.fr/franceinter-lofi.mp3"; AudioGeneratorMP3 *mp3; AudioFileSourceICYStream *file; AudioFileSourceBuffer *buff; -AudioOutputNull *out; +AudioOutputNullSlow *out; // Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc. void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string) @@ -80,9 +80,9 @@ void setup() audioLogger = &Serial; file = new AudioFileSourceICYStream(URL); file->RegisterMetadataCB(MDCallback, (void*)"ICY"); - buff = new AudioFileSourceBuffer(file, 4096); + buff = new AudioFileSourceBuffer(file, 2048); buff->RegisterStatusCB(StatusCallback, (void*)"buffer"); - out = new AudioOutputNull(); + out = new AudioOutputNullSlow(44100); mp3 = new AudioGeneratorMP3(); mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); mp3->begin(buff, out); diff --git a/examples/StreamOnHost/onHost b/examples/StreamOnHost/onHost index 5220cb6a..a02939f0 100755 --- a/examples/StreamOnHost/onHost +++ b/examples/StreamOnHost/onHost @@ -17,16 +17,22 @@ if [ "$1" = "clean" ]; then cd ${THISLIB} rm -f src/*.o src/libmad/*.o exit 0 -fi - -if [ "$1" = "-h" ]; then +elif [ "$1" = diff ]; then + cd ${THISLIB}/examples + diff -u StreamMP3FromHTTP/StreamMP3FromHTTP.ino ${ino}/${ino}.ino + exit 0 +else + echo "" echo "usage:" echo " $0" echo " $0 clean" + echo " $0 diff" echo " FORCE32=0 $0 (run with valgrind)" echo " FORCE32=1 $0 (run in 32 bits)" echo "variable ESP8266ARDUINO must point to esp8266 Arduino core directory" - exit 0 + echo "" + [ "$1" = "-h" ] && exit 0 + sleep 1 fi [ -z "${FORCE32}" ] && FORCE32=0 @@ -37,7 +43,7 @@ else run= fi -eval make FORCE32=${FORCE32} V=1 -j \ +eval make FORCE32=${FORCE32} -j \ USERCSOURCES=\"${MAD}\" \ USERCXXSOURCES=\"${THISLIB}/src/AudioFileSourceBuffer.cpp ${THISLIB}/src/AudioLogger.cpp ${THISLIB}/src/AudioGeneratorMP3.cpp ${THISLIB}/src/AudioFileSourceICYStream.cpp ${THISLIB}/src/AudioFileSourceHTTPStream.cpp\" \ USERCFLAGS=\"-I${THISLIB}/src/\" \ diff --git a/src/AudioFileSourceHTTPStream.cpp b/src/AudioFileSourceHTTPStream.cpp index 09d1e0c5..2917fbc1 100644 --- a/src/AudioFileSourceHTTPStream.cpp +++ b/src/AudioFileSourceHTTPStream.cpp @@ -84,7 +84,7 @@ uint32_t AudioFileSourceHTTPStream::readInternal(void *data, uint32_t len, bool cb.st(STATUS_DISCONNECTED, PSTR("Stream disconnected")); http.end(); for (int i = 0; i < reconnectTries; i++) { - char buff[32]; + char buff[64]; sprintf_P(buff, PSTR("Attempting to reconnect, try %d"), i); cb.st(STATUS_RECONNECTING, buff); delay(reconnectDelayMs); diff --git a/src/AudioFileSourceICYStream.cpp b/src/AudioFileSourceICYStream.cpp index ac03f610..522db406 100644 --- a/src/AudioFileSourceICYStream.cpp +++ b/src/AudioFileSourceICYStream.cpp @@ -84,13 +84,15 @@ AudioFileSourceICYStream::~AudioFileSourceICYStream() uint32_t AudioFileSourceICYStream::readInternal(void *data, uint32_t len, bool nonBlock) { // Ensure we can't possibly read 2 ICY headers in a single go #355 - len = std::min((int)(icyMetaInt >> 1), (int)len); + if (icyMetaInt > 1) { + len = std::min((int)(icyMetaInt >> 1), (int)len); + } retry: if (!http.connected()) { cb.st(STATUS_DISCONNECTED, PSTR("Stream disconnected")); http.end(); for (int i = 0; i < reconnectTries; i++) { - char buff[32]; + char buff[64]; sprintf_P(buff, PSTR("Attempting to reconnect, try %d"), i); cb.st(STATUS_RECONNECTING, buff); delay(reconnectDelayMs); From 40d0d997a8239f8cc486982aa3f7669a0ab2e4f0 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 3 Jan 2021 09:49:35 -0800 Subject: [PATCH 041/150] Release 1.8 Ensure the ICY decoder fixes make their way out. --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index 185eadbf..20e5dacb 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.7", + "version": "1.8", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { "SPI": "1.0", diff --git a/library.properties b/library.properties index 3a621460..53b5c623 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.7 +version=1.8 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines. From 3349608b114e839087a328f196d3d93dbe6e008f Mon Sep 17 00:00:00 2001 From: david gauchard Date: Fri, 8 Jan 2021 16:41:03 +0100 Subject: [PATCH 042/150] StreamOnHost: play audio on host (#359) * StreamOnHost: actually play audio * (spaces) * fix comment * update message --- examples/StreamOnHost/AudioOutputLinuxDSP.h | 118 ++++++++++++++++++++ examples/StreamOnHost/AudioOutputNullSlow.h | 7 +- examples/StreamOnHost/StreamOnHost.ino | 10 +- examples/StreamOnHost/onHost | 28 +++-- 4 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 examples/StreamOnHost/AudioOutputLinuxDSP.h diff --git a/examples/StreamOnHost/AudioOutputLinuxDSP.h b/examples/StreamOnHost/AudioOutputLinuxDSP.h new file mode 100644 index 00000000..743410e8 --- /dev/null +++ b/examples/StreamOnHost/AudioOutputLinuxDSP.h @@ -0,0 +1,118 @@ +/* + AudioOutput + Base class of an audio output player + + Copyright (C) 2017 Earle F. Philhower, III + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _AUDIOOUTPUTNULLSLOW_H +#define _AUDIOOUTPUTNULLSLOW_H + +#include +#include +#include +#include +#include +#include +#include + +#include "AudioOutput.h" + +class AudioOutputNullSlow : public AudioOutput +{ + public: + AudioOutputNullSlow() { }; + ~AudioOutputNullSlow() {}; + virtual bool begin() { samples = 0; startms = millis(); return true; } + + virtual bool ConsumeSample(int16_t sample[2]) { + + if (fd < 0) { + fd = open("/dev/dsp", O_RDWR); + if (fd < 0) { + perror("open of /dev/dsp failed (Try with 'padsp this-exec')"); + exit(1); + } + } + + if (channels && lastchannels != channels) { + Serial.printf("CHANNELS=%d\n", channels); + int arg = channels; /* mono or stereo */ + int status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg); + if (status == -1) { + perror("SOUND_PCM_WRITE_CHANNELS ioctl failed"); + exit(1); + } else if (arg != channels) { + perror("unable to set number of channels"); + exit(1); + } + lastchannels = channels; + } + + if (lastchannels > 0 && hertz && lasthertz != hertz) { + Serial.printf("FREQ=%d\n", hertz); + int arg = hertz*4/lastchannels; /* sampling rate */ + int status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg); + if (status == -1) { + perror("SOUND_PCM_WRITE_RATE ioctl failed"); + exit(1); + } + lasthertz = hertz; + } + + if (bps && lastbps != bps) { + Serial.printf("BPS=%d\n", bps); + int arg = bps; /* sample size */ + int status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg); + if (status == -1) { + perror("SOUND_PCM_WRITE_BITS ioctl failed"); + exit(1); + } else if (arg != bps) { + perror("unable to set sample size"); + exit(1); + } + lastbps = bps; + } + + if ((++samples & ((1<<9)-1)) == 0) { + // let the main loop a chance to run + return false; + } + + if (write(fd, sample, sizeof(sample)) != sizeof(sample)) { + perror("doing sound"); + exit(1); + } + + return true; + } + + virtual bool stop() { endms = millis(); return true; }; + unsigned long GetMilliseconds() { return endms - startms; } + int GetSamples() { return samples; } + int GetFrequency() { return hertz; } + + protected: + unsigned long startms; + unsigned long endms; + int samples; + int lastchannels = -1; + int lasthertz = -1; + int lastbps = -1; + int fd = -1; +}; + +#endif diff --git a/examples/StreamOnHost/AudioOutputNullSlow.h b/examples/StreamOnHost/AudioOutputNullSlow.h index 95548f6b..e85cd9ee 100644 --- a/examples/StreamOnHost/AudioOutputNullSlow.h +++ b/examples/StreamOnHost/AudioOutputNullSlow.h @@ -26,7 +26,7 @@ class AudioOutputNullSlow : public AudioOutput { public: - AudioOutputNullSlow(int hertz) { SetRate(hertz); }; + AudioOutputNullSlow() { }; ~AudioOutputNullSlow() {}; virtual bool begin() { samples = 0; startms = millis(); return true; } virtual bool ConsumeSample(int16_t sample[2]) { @@ -34,7 +34,10 @@ class AudioOutputNullSlow : public AudioOutput // sometimes to let the main loop running constexpr int everylog2 = 10; if ((++samples & ((1<> everylog2)); + if (hertz > 0) { + // simulate real time + delay(1000/(hertz >> everylog2)); + } return false; } return true; diff --git a/examples/StreamOnHost/StreamOnHost.ino b/examples/StreamOnHost/StreamOnHost.ino index e2a66f70..1308c371 100644 --- a/examples/StreamOnHost/StreamOnHost.ino +++ b/examples/StreamOnHost/StreamOnHost.ino @@ -8,7 +8,13 @@ #include "AudioFileSourceICYStream.h" #include "AudioFileSourceBuffer.h" #include "AudioGeneratorMP3.h" +#if AUDIO +#pragma message("Outputting audio") +#include "AudioOutputLinuxDSP.h" +#else +#pragma message("No audio") #include "AudioOutputNullSlow.h" +#endif // To run, set your ESP8266 build to 160MHz, update the SSID info, and upload. @@ -23,6 +29,8 @@ const char* password = STAPSK; // Randomly picked URL const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; +//const char *URL="http://stream2.pvpjamz.com:8706/stream"; +// that one is not well decoded: //const char *URL="http://icecast.radiofrance.fr/franceinter-lofi.mp3"; AudioGeneratorMP3 *mp3; @@ -82,7 +90,7 @@ void setup() file->RegisterMetadataCB(MDCallback, (void*)"ICY"); buff = new AudioFileSourceBuffer(file, 2048); buff->RegisterStatusCB(StatusCallback, (void*)"buffer"); - out = new AudioOutputNullSlow(44100); + out = new AudioOutputNullSlow(); mp3 = new AudioGeneratorMP3(); mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); mp3->begin(buff, out); diff --git a/examples/StreamOnHost/onHost b/examples/StreamOnHost/onHost index a02939f0..01484569 100755 --- a/examples/StreamOnHost/onHost +++ b/examples/StreamOnHost/onHost @@ -9,6 +9,7 @@ fi THISLIB=$(pwd)/../.. MAD=$(ls ${THISLIB}/src/libmad/*.c) +PAGER=${PAGER:-less} cd ${ESP8266ARDUINO}/tests/host @@ -19,7 +20,7 @@ if [ "$1" = "clean" ]; then exit 0 elif [ "$1" = diff ]; then cd ${THISLIB}/examples - diff -u StreamMP3FromHTTP/StreamMP3FromHTTP.ino ${ino}/${ino}.ino + diff -u StreamMP3FromHTTP/StreamMP3FromHTTP.ino ${ino}/${ino}.ino | ${PAGER} exit 0 else echo "" @@ -27,30 +28,39 @@ else echo " $0" echo " $0 clean" echo " $0 diff" - echo " FORCE32=0 $0 (run with valgrind)" - echo " FORCE32=1 $0 (run in 32 bits)" + echo " AUDIO=a VALGRIND=v FORCE32=f $0" + echo " a=1 play sound (use padsp, open /dev/dsp)" + echo " v=1 run in native mode (FORCE32=0) with valgrind" + echo " f=1 run in 32 bits mode (if gcc-multilib is installed)" echo "variable ESP8266ARDUINO must point to esp8266 Arduino core directory" echo "" [ "$1" = "-h" ] && exit 0 sleep 1 fi +run="" + [ -z "${FORCE32}" ] && FORCE32=0 +[ -z "${AUDIO}" ] && AUDIO=1 -if [ "${FORCE32}" = 0 ]; then - run=valgrind -else - run= +if [ "${AUDIO}" = 1 ]; then + run="${run} padsp" +fi + +if [ "${VALGRIND}" = 1 ]; then + FORCE32=0 + run="$run valgrind" fi +touch ${THISLIB}/examples/${ino}/${ino}.ino # rebuild + eval make FORCE32=${FORCE32} -j \ USERCSOURCES=\"${MAD}\" \ USERCXXSOURCES=\"${THISLIB}/src/AudioFileSourceBuffer.cpp ${THISLIB}/src/AudioLogger.cpp ${THISLIB}/src/AudioGeneratorMP3.cpp ${THISLIB}/src/AudioFileSourceICYStream.cpp ${THISLIB}/src/AudioFileSourceHTTPStream.cpp\" \ - USERCFLAGS=\"-I${THISLIB}/src/\" \ + USERCFLAGS=\"-I${THISLIB}/src/ -DAUDIO=${AUDIO}\" \ ${THISLIB}/examples/${ino}/${ino} set -x $run ./bin/${ino}/${ino} "$@" stty sane - From 3e3bc354937e8ec071c9c77aba9250671826df3e Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 14 Jan 2021 15:15:17 -0800 Subject: [PATCH 043/150] Add arduino-lint CI check (#360) * Add arduino-lint CI check * Fix linting warnings --- .github/workflows/pr-or-master-push.yml | 7 ++++ library.json | 2 +- library.properties | 2 +- src/ESP8266Audio.h | 50 +++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 src/ESP8266Audio.h diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index 88d6fca7..52bf8a9e 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -86,3 +86,10 @@ jobs: valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./wav valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./midi + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: arduino/arduino-lint-action@v1 + with: + library-manager: 'update' diff --git a/library.json b/library.json index 20e5dacb..c351e329 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.8", + "version": "1.8.1", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "dependencies": { "SPI": "1.0", diff --git a/library.properties b/library.properties index 53b5c623..72da8a86 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.8 +version=1.8.1 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines. diff --git a/src/ESP8266Audio.h b/src/ESP8266Audio.h new file mode 100644 index 00000000..eb0acc52 --- /dev/null +++ b/src/ESP8266Audio.h @@ -0,0 +1,50 @@ +// Lazy "include all the things" header for simplicity. +// In general a user should only include the specific headers they need +// to miniimize build times. + +// Input stage +#include "AudioFileSourceBuffer.h" +#include "AudioFileSourceFATFS.h" +#include "AudioFileSourceFS.h" +#include "AudioFileSource.h" +#include "AudioFileSourceHTTPStream.h" +#include "AudioFileSourceICYStream.h" +#include "AudioFileSourceID3.h" +#include "AudioFileSourceLittleFS.h" +#include "AudioFileSourcePROGMEM.h" +#include "AudioFileSourceSD.h" +#include "AudioFileSourceSPIFFS.h" +#include "AudioFileSourceSPIRAMBuffer.h" +#include "AudioFileSourceSTDIO.h" + +// Misc. plumbing +#include "AudioFileStream.h" +#include "AudioLogger.h" +#include "AudioStatus.h" + +// Actual decode/audio generation logic +#include "AudioGeneratorAAC.h" +#include "AudioGeneratorFLAC.h" +#include "AudioGenerator.h" +#include "AudioGeneratorMIDI.h" +#include "AudioGeneratorMOD.h" +#include "AudioGeneratorMP3a.h" +#include "AudioGeneratorMP3.h" +#include "AudioGeneratorOpus.h" +#include "AudioGeneratorRTTTL.h" +#include "AudioGeneratorTalkie.h" +#include "AudioGeneratorWAV.h" + +// Render(output) sounds +#include "AudioOutputBuffer.h" +#include "AudioOutputFilterDecimate.h" +#include "AudioOutput.h" +#include "AudioOutputI2S.h" +#include "AudioOutputI2SNoDAC.h" +#include "AudioOutputMixer.h" +#include "AudioOutputNull.h" +#include "AudioOutputSerialWAV.h" +#include "AudioOutputSPDIF.h" +#include "AudioOutputSPIFFSWAV.h" +#include "AudioOutputSTDIO.h" +#include "AudioOutputULP.h" From 4994de7cb7065c3efd848b6409cebfb85fcf0bd3 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 27 Jan 2021 16:26:44 -0800 Subject: [PATCH 044/150] Revert "Work around Arduino-Builder bug causing ESP8266 build fail (#358)" (#365) This reverts commit b832ec24348346a84c320a8cbe6ead5415dc721a. Arduino-CLI has fixed a bug in their code, attempt to run nightly builds in CI again. --- tests/common.sh | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index fab4e590..cabad512 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -93,11 +93,9 @@ function install_libraries() function install_ide() { local ide_path=$1 - local idever='1.8.10' - local ideurl="https://downloads.arduino.cc/arduino-$idever" - wget -q -O arduino.tar.xz "${ideurl}-linux64.tar.xz" + wget -q -O arduino.tar.xz https://www.arduino.cc/download.php?f=/arduino-nightly-linux64.tar.xz tar xf arduino.tar.xz - mv arduino-${idever} $ide_path + mv arduino-nightly $ide_path export PATH="$ide_path:$PATH" } From 6ecb6afe3059375c19377cd94a2c99f83c64e3c8 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Thu, 28 Jan 2021 01:27:04 +0100 Subject: [PATCH 045/150] API to force HTTPv1.0 allowing streaming clean data from some servers (#363) --- examples/StreamOnHost/StreamOnHost.ino | 8 +++++--- src/AudioFileSourceHTTPStream.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/examples/StreamOnHost/StreamOnHost.ino b/examples/StreamOnHost/StreamOnHost.ino index 1308c371..876562d1 100644 --- a/examples/StreamOnHost/StreamOnHost.ino +++ b/examples/StreamOnHost/StreamOnHost.ino @@ -28,10 +28,10 @@ const char* ssid = STASSID; const char* password = STAPSK; // Randomly picked URL -const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; +//const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; //const char *URL="http://stream2.pvpjamz.com:8706/stream"; // that one is not well decoded: -//const char *URL="http://icecast.radiofrance.fr/franceinter-lofi.mp3"; +const char *URL="http://icecast.radiofrance.fr/franceinter-lofi.mp3"; AudioGeneratorMP3 *mp3; AudioFileSourceICYStream *file; @@ -86,8 +86,10 @@ void setup() Serial.println("Connected"); audioLogger = &Serial; - file = new AudioFileSourceICYStream(URL); + file = new AudioFileSourceICYStream(); file->RegisterMetadataCB(MDCallback, (void*)"ICY"); + file->useHTTP10(); + file->open(URL); buff = new AudioFileSourceBuffer(file, 2048); buff->RegisterStatusCB(StatusCallback, (void*)"buffer"); out = new AudioOutputNullSlow(); diff --git a/src/AudioFileSourceHTTPStream.h b/src/AudioFileSourceHTTPStream.h index e7ef88d1..bb5014d2 100644 --- a/src/AudioFileSourceHTTPStream.h +++ b/src/AudioFileSourceHTTPStream.h @@ -47,6 +47,7 @@ class AudioFileSourceHTTPStream : public AudioFileSource virtual uint32_t getSize() override; virtual uint32_t getPos() override; bool SetReconnect(int tries, int delayms) { reconnectTries = tries; reconnectDelayMs = delayms; return true; } + void useHTTP10 () { http.useHTTP10(true); } enum { STATUS_HTTPFAIL=2, STATUS_DISCONNECTED, STATUS_RECONNECTING, STATUS_RECONNECTED, STATUS_NODATA }; From 714e8cf594c92b2f55e369e5b9880bf07ae4d7a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?William=20B=C3=A9rub=C3=A9?= Date: Sat, 13 Feb 2021 18:32:45 -0500 Subject: [PATCH 046/150] Adding a working implementation of a Biquad filter adapted for use with the fixed-point CPU of the ESP8266 (#370) --- src/AudioOutputFilterBiquad.cpp | 245 ++++++++++++++++++++++++++++++++ src/AudioOutputFilterBiquad.h | 80 +++++++++++ 2 files changed, 325 insertions(+) create mode 100644 src/AudioOutputFilterBiquad.cpp create mode 100644 src/AudioOutputFilterBiquad.h diff --git a/src/AudioOutputFilterBiquad.cpp b/src/AudioOutputFilterBiquad.cpp new file mode 100644 index 00000000..5c8af8e5 --- /dev/null +++ b/src/AudioOutputFilterBiquad.cpp @@ -0,0 +1,245 @@ +/* + AudioOutputFilterBiquad + Implements a Biquad filter + + Copyright (C) 2012 Nigel Redmon + Copyright (C) 2021 William Bérubé + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include +#include "AudioOutputFilterBiquad.h" + +AudioOutputFilterBiquad::AudioOutputFilterBiquad(AudioOutput *sink) +{ + this->sink = sink; + + type = bq_type_lowpass; + a0 = 1.0; + a1 = a2 = b1 = b2 = 0.0; + Fc = 0.50; + Q = 0.707; + peakGain = 0.0; + z1 = z2 = 0.0; +} + +AudioOutputFilterBiquad::AudioOutputFilterBiquad(int type, float Fc, float Q, float peakGain, AudioOutput *sink) +{ + this->sink = sink; + + SetBiquad(type, Fc, Q, peakGain); + z1 = z2 = 0.0; +} + +AudioOutputFilterBiquad::~AudioOutputFilterBiquad() {} + +bool AudioOutputFilterBiquad::SetRate(int hz) +{ + return sink->SetRate(hz); +} + +bool AudioOutputFilterBiquad::SetBitsPerSample(int bits) +{ + return sink->SetBitsPerSample(bits); +} + +bool AudioOutputFilterBiquad::SetChannels(int channels) +{ + return sink->SetChannels(channels); +} + +bool AudioOutputFilterBiquad::SetGain(float gain) +{ + return sink->SetGain(gain); +} + +void AudioOutputFilterBiquad::SetType(int type) +{ + this->type = type; + CalcBiquad(); +} + +void AudioOutputFilterBiquad::SetFc(float Fc) +{ + this->Fc = Fc; + CalcBiquad(); +} + +void AudioOutputFilterBiquad::SetQ(float Q) +{ + this->Q = Q; + CalcBiquad(); +} + +void AudioOutputFilterBiquad::SetPeakGain(float peakGain) +{ + this->peakGain = peakGain; + CalcBiquad(); +} + +void AudioOutputFilterBiquad::SetBiquad(int type, float Fc, float Q, float peakGain) +{ + this->type = type; + this->Fc = Fc; + this->Q = Q; + this->peakGain = peakGain; + CalcBiquad(); +} + +void AudioOutputFilterBiquad::CalcBiquad() +{ + float norm; + float V = pow(10, fabs(peakGain) / 20.0); + float K = tan(M_PI * Fc); + + switch (this->type) { + case bq_type_lowpass: + norm = 1 / (1 + K / Q + K * K); + a0 = K * K * norm; + a1 = 2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_highpass: + norm = 1 / (1 + K / Q + K * K); + a0 = 1 * norm; + a1 = -2 * a0; + a2 = a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_bandpass: + norm = 1 / (1 + K / Q + K * K); + a0 = K / Q * norm; + a1 = 0; + a2 = -a0; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_notch: + norm = 1 / (1 + K / Q + K * K); + a0 = (1 + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = a0; + b1 = a1; + b2 = (1 - K / Q + K * K) * norm; + break; + + case bq_type_peak: + if (peakGain >= 0) { // boost + norm = 1 / (1 + 1/Q * K + K * K); + a0 = (1 + V/Q * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - V/Q * K + K * K) * norm; + b1 = a1; + b2 = (1 - 1/Q * K + K * K) * norm; + } else { // cut + norm = 1 / (1 + V/Q * K + K * K); + a0 = (1 + 1/Q * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - 1/Q * K + K * K) * norm; + b1 = a1; + b2 = (1 - V/Q * K + K * K) * norm; + } + break; + + case bq_type_lowshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + a0 = (1 + sqrt(2*V) * K + V * K * K) * norm; + a1 = 2 * (V * K * K - 1) * norm; + a2 = (1 - sqrt(2*V) * K + V * K * K) * norm; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (1 + sqrt(2*V) * K + V * K * K); + a0 = (1 + sqrt(2) * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - sqrt(2) * K + K * K) * norm; + b1 = 2 * (V * K * K - 1) * norm; + b2 = (1 - sqrt(2*V) * K + V * K * K) * norm; + } + break; + + case bq_type_highshelf: + if (peakGain >= 0) { // boost + norm = 1 / (1 + sqrt(2) * K + K * K); + a0 = (V + sqrt(2*V) * K + K * K) * norm; + a1 = 2 * (K * K - V) * norm; + a2 = (V - sqrt(2*V) * K + K * K) * norm; + b1 = 2 * (K * K - 1) * norm; + b2 = (1 - sqrt(2) * K + K * K) * norm; + } + else { // cut + norm = 1 / (V + sqrt(2*V) * K + K * K); + a0 = (1 + sqrt(2) * K + K * K) * norm; + a1 = 2 * (K * K - 1) * norm; + a2 = (1 - sqrt(2) * K + K * K) * norm; + b1 = 2 * (K * K - V) * norm; + b2 = (V - sqrt(2*V) * K + K * K) * norm; + } + break; + } + + i_a0 = a0 * BQ_DECAL; + i_a1 = a1 * BQ_DECAL; + i_a2 = a2 * BQ_DECAL; + + i_b1 = b1 * BQ_DECAL; + i_b2 = b2 * BQ_DECAL; + + i_lz1 = i_rz1 = z1 * BQ_DECAL; + i_lz2 = i_rz2 = z2 * BQ_DECAL; + + i_Fc = Fc * BQ_DECAL; + i_Q = Q * BQ_DECAL; + i_peakGain = peakGain * BQ_DECAL; +} + +bool AudioOutputFilterBiquad::begin() +{ + return sink->begin(); +} + +bool AudioOutputFilterBiquad::ConsumeSample(int16_t sample[2]) +{ + + int32_t leftSample = (sample[LEFTCHANNEL] << BQ_SHIFT) / 2; + int32_t rightSample = (sample[RIGHTCHANNEL] << BQ_SHIFT) / 2; + + int64_t leftOutput = ((leftSample * i_a0) >> BQ_SHIFT) + i_lz1; + i_lz1 = ((leftSample * i_a1) >> BQ_SHIFT) + i_lz2 - ((i_b1 * leftOutput) >> BQ_SHIFT); + i_lz2 = ((leftSample * i_a2) >> BQ_SHIFT) - ((i_b2 * leftOutput) >> BQ_SHIFT); + + int64_t rightOutput = ((rightSample * i_a0) >> BQ_SHIFT) + i_rz1; + i_rz1 = ((rightSample * i_a1) >> BQ_SHIFT) + i_rz2 - ((i_b1 * rightOutput) >> BQ_SHIFT); + i_rz2 = ((rightSample * i_a2) >> BQ_SHIFT) - ((i_b2 * rightOutput) >> BQ_SHIFT); + + int16_t out[2]; + out[LEFTCHANNEL] = (int16_t)(leftOutput >> BQ_SHIFT); + out[RIGHTCHANNEL] = (int16_t)(rightOutput >> BQ_SHIFT); + + return sink->ConsumeSample(out); +} + +bool AudioOutputFilterBiquad::stop() +{ + return sink->stop(); +} diff --git a/src/AudioOutputFilterBiquad.h b/src/AudioOutputFilterBiquad.h new file mode 100644 index 00000000..f4dc95f5 --- /dev/null +++ b/src/AudioOutputFilterBiquad.h @@ -0,0 +1,80 @@ +/* + AudioOutputFilterBiquad + Implements a Biquad filter + + Copyright (C) 2012 Nigel Redmon + Copyright (C) 2021 William Bérubé + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _AudioOutputFilterBiquad_H +#define _AudioOutputFilterBiquad_H + +#include "AudioOutput.h" + +#define BQ_SHIFT 16 +#define BQ_DECAL 65536 + +enum { + bq_type_lowpass = 0, + bq_type_highpass, + bq_type_bandpass, + bq_type_notch, + bq_type_peak, + bq_type_lowshelf, + bq_type_highshelf +}; + +class AudioOutputFilterBiquad : public AudioOutput +{ + public: + AudioOutputFilterBiquad(AudioOutput *sink); + AudioOutputFilterBiquad(int type, float Fc, float Q, float peakGain, AudioOutput *sink); + virtual ~AudioOutputFilterBiquad() override; + virtual bool SetRate(int hz) override; + virtual bool SetBitsPerSample(int bits) override; + virtual bool SetChannels(int chan) override; + virtual bool SetGain(float f) override; + virtual bool begin() override; + virtual bool ConsumeSample(int16_t sample[2]) override; + virtual bool stop() override; + + private: + void SetType(int type); + void SetFc(float Fc); + void SetQ(float Q); + void SetPeakGain(float peakGain); + void SetBiquad(int type, float Fc, float Q, float peakGain); + + protected: + AudioOutput *sink; + int buffSize; + int16_t *leftSample; + int16_t *rightSample; + int writePtr; + int readPtr; + bool filled; + int type; + void CalcBiquad(); + int64_t i_a0, i_a1, i_a2, i_b1, i_b2; + int64_t i_Fc, i_Q, i_peakGain; + int64_t i_lz1, i_lz2, i_rz1, i_rz2; + float a0, a1, a2, b1, b2; + float Fc, Q, peakGain; + float z1, z2; +}; + +#endif + From f4d4e693325bc15286df2496a3ac47c0d0bac51d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 24 Feb 2021 20:50:22 -0800 Subject: [PATCH 047/150] Move large OPUS locals to the heap (#374) --- src/libopus/celt/celt_decoder.c | 3 +- src/libopus/config.h | 2 + src/libopus/repacketizer.c | 71 +++++++++++++------ src/libopus/silk/NLSF2A.c | 11 ++- src/libopus/silk/fixed/burg_modified_FIX.c | 18 +++-- .../silk/fixed/warped_autocorrelation_FIX.c | 6 +- src/libopus/silk/resampler_down2_3.c | 4 +- src/opusfile/opusfile.c | 67 ++++++++++------- tests/host/Makefile | 4 +- 9 files changed, 122 insertions(+), 64 deletions(-) diff --git a/src/libopus/celt/celt_decoder.c b/src/libopus/celt/celt_decoder.c index 329b6f6c..7e7296ed 100644 --- a/src/libopus/celt/celt_decoder.c +++ b/src/libopus/celt/celt_decoder.c @@ -482,7 +482,7 @@ static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch) int pitch_index; VARDECL( opus_val16, lp_pitch_buf ); SAVE_STACK; - ALLOC( lp_pitch_buf, DECODE_BUFFER_SIZE>>1, opus_val16 ); + opus_val16 *lp_pitch_buf = (opus_val16*)malloc((DECODE_BUFFER_SIZE>>1) * sizeof(opus_val16)); //ALLOC( lp_pitch_buf, DECODE_BUFFER_SIZE>>1, opus_val16 ); pitch_downsample(decode_mem, lp_pitch_buf, DECODE_BUFFER_SIZE, C, arch); pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf, @@ -490,6 +490,7 @@ static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch) PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, arch); pitch_index = PLC_PITCH_LAG_MAX-pitch_index; RESTORE_STACK; + free(lp_pitch_buf); return pitch_index; } diff --git a/src/libopus/config.h b/src/libopus/config.h index 3577204b..dc1ee1e9 100644 --- a/src/libopus/config.h +++ b/src/libopus/config.h @@ -206,3 +206,5 @@ # define _Restrict # define __restrict__ #endif + +#include diff --git a/src/libopus/repacketizer.c b/src/libopus/repacketizer.c index 5a1eb675..36732293 100644 --- a/src/libopus/repacketizer.c +++ b/src/libopus/repacketizer.c @@ -239,21 +239,30 @@ opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) { - OpusRepacketizer rp; + OpusRepacketizer *rp = (OpusRepacketizer*)malloc(sizeof(OpusRepacketizer)); opus_int32 ret; - if (len < 1) + if (len < 1) { + free(rp); return OPUS_BAD_ARG; - if (len==new_len) + } + if (len==new_len) { + free(rp); return OPUS_OK; - else if (len > new_len) + } + else if (len > new_len) { + free(rp); return OPUS_BAD_ARG; - opus_repacketizer_init(&rp); + } + opus_repacketizer_init(rp); /* Moving payload to the end of the packet so we can do in-place padding */ OPUS_MOVE(data+new_len-len, data, len); - ret = opus_repacketizer_cat(&rp, data+new_len-len, len); - if (ret != OPUS_OK) + ret = opus_repacketizer_cat(rp, data+new_len-len, len); + if (ret != OPUS_OK) { + free(rp); return ret; - ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1); + } + ret = opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, new_len, 0, 1); + free(rp); if (ret > 0) return OPUS_OK; else @@ -262,15 +271,20 @@ int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len) opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len) { - OpusRepacketizer rp; + OpusRepacketizer *rp = (OpusRepacketizer*)malloc(sizeof(OpusRepacketizer)); opus_int32 ret; - if (len < 1) + if (len < 1) { + free(rp); return OPUS_BAD_ARG; - opus_repacketizer_init(&rp); - ret = opus_repacketizer_cat(&rp, data, len); - if (ret < 0) + } + opus_repacketizer_init(rp); + ret = opus_repacketizer_cat(rp, data, len); + if (ret < 0) { + free(rp); return ret; - ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0); + } + ret = opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, len, 0, 0); + free(rp); celt_assert(ret > 0 && ret <= len); return ret; } @@ -312,12 +326,14 @@ opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, in unsigned char toc; opus_int16 size[48]; opus_int32 packet_offset; - OpusRepacketizer rp; + OpusRepacketizer *rp = (OpusRepacketizer*)malloc(sizeof(OpusRepacketizer)); unsigned char *dst; opus_int32 dst_len; - if (len < 1) + if (len < 1){ + free(rp); return OPUS_BAD_ARG; + } dst = data; dst_len = 0; /* Unpad all frames */ @@ -325,25 +341,34 @@ opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, in { opus_int32 ret; int self_delimited = s!=nb_streams-1; - if (len<=0) + if (len<=0) { + free(rp); return OPUS_INVALID_PACKET; - opus_repacketizer_init(&rp); + } + opus_repacketizer_init(rp); ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL, size, NULL, &packet_offset); - if (ret<0) + if (ret<0) { + free(rp); return ret; - ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited); - if (ret < 0) + } + ret = opus_repacketizer_cat_impl(rp, data, packet_offset, self_delimited); + if (ret < 0) { + free(rp); return ret; - ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0); - if (ret < 0) + } + ret = opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, dst, len, self_delimited, 0); + if (ret < 0) { + free(rp); return ret; + } else dst_len += ret; dst += ret; data += packet_offset; len -= packet_offset; } + free(rp); return dst_len; } diff --git a/src/libopus/silk/NLSF2A.c b/src/libopus/silk/NLSF2A.c index 40718e7a..2b3e3340 100644 --- a/src/libopus/silk/NLSF2A.c +++ b/src/libopus/silk/NLSF2A.c @@ -80,10 +80,11 @@ void silk_NLSF2A( }; const unsigned char *ordering; opus_int k, i, dd; - opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ]; - opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ]; + opus_int32 *cos_LSF_QA = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC ); + opus_int32 *P = (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC / 2 + 1)); + opus_int32 *Q= (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC / 2 + 1)); opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta; - opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ]; + opus_int32 *a32_QA1 = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC ); silk_assert( LSF_COS_TAB_SZ_FIX == 128 ); celt_assert( d==10 || d==16 ); @@ -137,5 +138,9 @@ void silk_NLSF2A( a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */ } } + free(cos_LSF_QA); + free(P); + free(Q); + free(a32_QA1); } diff --git a/src/libopus/silk/fixed/burg_modified_FIX.c b/src/libopus/silk/fixed/burg_modified_FIX.c index b4a31d60..dd786298 100644 --- a/src/libopus/silk/fixed/burg_modified_FIX.c +++ b/src/libopus/silk/fixed/burg_modified_FIX.c @@ -57,12 +57,12 @@ void silk_burg_modified_c( opus_int k, n, s, lz, rshifts, reached_max_gain; opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2; const opus_int16 *x_ptr; - opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ]; - opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ]; - opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ]; - opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ]; - opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ]; - opus_int32 xcorr[ SILK_MAX_ORDER_LPC ]; + opus_int32 *C_first_row = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC); + opus_int32 *C_last_row = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC); + opus_int32 *Af_QA = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC); + opus_int32 *CAf = (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC+1)); + opus_int32 *CAb = (opus_int32*)malloc(sizeof(opus_int32) * (SILK_MAX_ORDER_LPC+1)); + opus_int32 *xcorr = (opus_int32*)malloc(sizeof(opus_int32) * SILK_MAX_ORDER_LPC); opus_int64 C0_64; celt_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE ); @@ -277,4 +277,10 @@ void silk_burg_modified_c( *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */ *res_nrg_Q = -rshifts; } + free(C_first_row); + free(C_last_row); + free(Af_QA); + free(CAf); + free(CAb); + free(xcorr); } diff --git a/src/libopus/silk/fixed/warped_autocorrelation_FIX.c b/src/libopus/silk/fixed/warped_autocorrelation_FIX.c index 7ef3a7ef..9c21f2a9 100644 --- a/src/libopus/silk/fixed/warped_autocorrelation_FIX.c +++ b/src/libopus/silk/fixed/warped_autocorrelation_FIX.c @@ -49,8 +49,8 @@ void silk_warped_autocorrelation_FIX_c( { opus_int n, i, lsh; opus_int32 tmp1_QS, tmp2_QS; - opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; - opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 }; + opus_int32 *state_QS = (opus_int32*)calloc(MAX_SHAPE_LPC_ORDER + 1, sizeof(opus_int32)); + opus_int64 *corr_QC = (opus_int64*)calloc(MAX_SHAPE_LPC_ORDER + 1, sizeof(opus_int64)); /* Order must be even */ celt_assert( ( order & 1 ) == 0 ); @@ -88,5 +88,7 @@ void silk_warped_autocorrelation_FIX_c( } } silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/ + free(state_QS); + free(corr_QC); } #endif /* OVERRIDE_silk_warped_autocorrelation_FIX_c */ diff --git a/src/libopus/silk/resampler_down2_3.c b/src/libopus/silk/resampler_down2_3.c index d8ce95c6..62aab568 100644 --- a/src/libopus/silk/resampler_down2_3.c +++ b/src/libopus/silk/resampler_down2_3.c @@ -48,7 +48,8 @@ void silk_resampler_down2_3( opus_int32 *buf_ptr; SAVE_STACK; - ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 ); +// ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 ); + opus_int32 *buf = (opus_int32*)malloc((RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR) * sizeof(opus_int32)); /* Copy buffered samples to start of buffer */ silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) ); @@ -99,5 +100,6 @@ void silk_resampler_down2_3( /* Copy last part of filtered signal to the state for the next call */ silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) ); + free(buf); RESTORE_STACK; } diff --git a/src/opusfile/opusfile.c b/src/opusfile/opusfile.c index bfd3c9e5..7ffe32f8 100644 --- a/src/opusfile/opusfile.c +++ b/src/opusfile/opusfile.c @@ -90,12 +90,12 @@ int op_test(OpusHead *_head, ogg_sync_init(&oy); data=ogg_sync_buffer(&oy,(long)_initial_bytes); if(data!=NULL){ - ogg_stream_state os; + ogg_stream_state *os = (ogg_stream_state*)malloc(sizeof(ogg_stream_state)); ogg_page og; int ret; memcpy(data,_initial_data,_initial_bytes); ogg_sync_wrote(&oy,(long)_initial_bytes); - ogg_stream_init(&os,-1); + ogg_stream_init(os,-1); err=OP_FALSE; do{ ogg_packet op; @@ -104,11 +104,11 @@ int op_test(OpusHead *_head, if(ret<0)continue; /*Stop if we run out of data.*/ if(!ret)break; - ogg_stream_reset_serialno(&os,ogg_page_serialno(&og)); - ogg_stream_pagein(&os,&og); + ogg_stream_reset_serialno(os,ogg_page_serialno(&og)); + ogg_stream_pagein(os,&og); /*Only process the first packet on this page (if it's a BOS packet, it's required to be the only one).*/ - if(ogg_stream_packetout(&os,&op)==1){ + if(ogg_stream_packetout(os,&op)==1){ if(op.b_o_s){ ret=opus_head_parse(_head,op.packet,op.bytes); /*If this didn't look like Opus, keep going.*/ @@ -122,7 +122,8 @@ int op_test(OpusHead *_head, } } while(err==OP_FALSE); - ogg_stream_clear(&os); + ogg_stream_clear(os); + free(os); } else err=OP_EFAULT; ogg_sync_clear(&oy); @@ -835,7 +836,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, ogg_int64_t cur_page_gp; ogg_uint32_t serialno; opus_int32 total_duration; - int durations[255]; + int *durations = (int*)malloc(255 * sizeof(int)); int cur_page_eos; int op_count; int pi; @@ -852,26 +853,31 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, Otherwise there are no audio data packets in the whole logical stream.*/ if(OP_UNLIKELY(page_offset<0)){ /*Fail if there was a read error.*/ - if(page_offsethead.pre_skip>0)return OP_EBADTIMESTAMP; + if(_link->head.pre_skip>0) {free(durations); return OP_EBADTIMESTAMP;} _link->pcm_file_offset=0; /*Set pcm_end and end_offset so we can skip the call to op_find_final_pcm_offset().*/ _link->pcm_start=_link->pcm_end=0; _link->end_offset=_link->data_offset; + free(durations); return 0; } /*Similarly, if we hit the next link in the chain, we've gone too far.*/ if(OP_UNLIKELY(ogg_page_bos(_og))){ - if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP; + if(_link->head.pre_skip>0) { + free(durations); + return OP_EBADTIMESTAMP; + } /*Set pcm_end and end_offset so we can skip the call to op_find_final_pcm_offset().*/ _link->pcm_file_offset=0; _link->pcm_start=_link->pcm_end=0; _link->end_offset=_link->data_offset; /*Tell the caller we've got a buffered page for them.*/ + free(durations); return 1; } /*Ignore pages from other streams (not strictly necessary, because of the @@ -901,7 +907,10 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, cur_page_gp=_of->op[op_count-1].granulepos; /*But getting a packet without a valid granule position on the page is not okay.*/ - if(cur_page_gp==-1)return OP_EBADTIMESTAMP; + if(cur_page_gp==-1) { + free(durations); + return OP_EBADTIMESTAMP; + } cur_page_eos=_of->op[op_count-1].e_o_s; if(OP_LIKELY(!cur_page_eos)){ /*The EOS flag wasn't set. @@ -910,6 +919,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){ /*The starting granule position MUST not be smaller than the amount of audio on the first page with completed packets.*/ + free(durations); return OP_EBADTIMESTAMP; } } @@ -923,6 +933,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, /*However, the end-trimming MUST not ask us to trim more samples than exist after applying the pre-skip.*/ if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){ + free(durations); return OP_EBADTIMESTAMP; } } @@ -957,6 +968,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of, _link->pcm_file_offset=0; _of->prev_packet_gp=_link->pcm_start=pcm_start; _of->prev_page_offset=page_offset; + free(durations); return 0; } @@ -1391,32 +1403,34 @@ static int op_open_seekable2_impl(OggOpusFile *_of){ /*64 seek records should be enough for anybody. Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE granularity, much more than enough.*/ - OpusSeekRecord sr[64]; + OpusSeekRecord *sr = (OpusSeekRecord*)malloc(64 * sizeof(OpusSeekRecord)); opus_int64 data_offset; int ret; /*We can seek, so set out learning all about this file.*/ (*_of->callbacks.seek)(_of->stream,0,SEEK_END); _of->offset=_of->end=(*_of->callbacks.tell)(_of->stream); - if(OP_UNLIKELY(_of->end<0))return OP_EREAD; + if(OP_UNLIKELY(_of->end<0)){free(sr); return OP_EREAD;} data_offset=_of->links[0].data_offset; - if(OP_UNLIKELY(_of->endendend, _of->links[0].serialno,_of->serialnos,_of->nserialnos); - if(OP_UNLIKELY(ret<0))return ret; + if(OP_UNLIKELY(ret<0)){free(sr); return ret;} /*If there's any trailing junk, forget about it.*/ _of->end=sr[0].offset+sr[0].size; - if(OP_UNLIKELY(_of->endendserialnos,&_of->nserialnos,&_of->cserialnos); + free(sr); + return ret; } static int op_open_seekable2(OggOpusFile *_of){ ogg_sync_state oy_start; - ogg_stream_state os_start; + ogg_stream_state *os_start = (ogg_stream_state*)malloc(sizeof(ogg_stream_state)); ogg_packet *op_start; opus_int64 prev_page_offset; opus_int64 start_offset; @@ -1435,9 +1449,9 @@ static int op_open_seekable2(OggOpusFile *_of){ start_op_count=_of->op_count; /*This is a bit too large to put on the stack unconditionally.*/ op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count); - if(op_start==NULL)return OP_EFAULT; + if(op_start==NULL){free(os_start); return OP_EFAULT;} *&oy_start=_of->oy; - *&os_start=_of->os; + *os_start=_of->os; prev_page_offset=_of->prev_page_offset; start_offset=_of->offset; memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count); @@ -1449,7 +1463,7 @@ static int op_open_seekable2(OggOpusFile *_of){ ogg_stream_clear(&_of->os); ogg_sync_clear(&_of->oy); *&_of->oy=*&oy_start; - *&_of->os=*&os_start; + *&_of->os=*os_start; _of->offset=start_offset; _of->op_count=start_op_count; memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count); @@ -1457,9 +1471,10 @@ static int op_open_seekable2(OggOpusFile *_of){ _of->prev_packet_gp=_of->links[0].pcm_start; _of->prev_page_offset=prev_page_offset; _of->cur_discard_count=_of->links[0].head.pre_skip; - if(OP_UNLIKELY(ret<0))return ret; + if(OP_UNLIKELY(ret<0)){free(os_start); return ret;} /*And restore the position indicator.*/ ret=(*_of->callbacks.seek)(_of->stream,op_position(_of),SEEK_SET); + free(os_start); return OP_UNLIKELY(ret<0)?OP_EREAD:0; } @@ -1980,7 +1995,7 @@ static int op_fetch_and_process_page(OggOpusFile *_of, ogg_stream_pagein(&_of->os,&og); if(OP_LIKELY(_of->ready_state>=OP_INITSET)){ opus_int32 total_duration; - int durations[255]; + int *durations = (int*)malloc(255 * sizeof(int)); int op_count; int report_hole; report_hole=0; @@ -2037,7 +2052,7 @@ static int op_fetch_and_process_page(OggOpusFile *_of, Proceed to the next link, rather than risk playing back some samples that shouldn't have been played.*/ _of->op_count=0; - if(report_hole)return OP_HOLE; + if(report_hole){ free(durations); return OP_HOLE; } continue; } /*By default discard 80 ms of data after a seek, unless we seek @@ -2145,9 +2160,9 @@ static int op_fetch_and_process_page(OggOpusFile *_of, _of->prev_page_offset=_page_offset; _of->op_count=op_count=pi; } - if(report_hole)return OP_HOLE; + if(report_hole) { free(durations); return OP_HOLE; } /*If end-trimming didn't trim all the packets, we're done.*/ - if(op_count>0)return 0; + if(op_count>0) { free(durations); return 0; } } } } diff --git a/tests/host/Makefile b/tests/host/Makefile index 835724fa..25156dbc 100644 --- a/tests/host/Makefile +++ b/tests/host/Makefile @@ -78,8 +78,8 @@ libflac=../../src/libflac/md5.c ../../src/libflac/window.c ../../src/libflac/mem ../../src/libflac/bitreader.c ../../src/libflac/bitmath.c ../../src/libflac/stream_decoder.c ../../src/libflac/float.c -CCOPTS=-g -Wunused-parameter -Wall -m32 -include Arduino.h -CPPOPTS=-g -Wunused-parameter -Wall -std=c++11 -m32 -include Arduino.h +CCOPTS=-g -Wunused-parameter -Wall -m32 -include Arduino.h -Wstack-usage=300 +CPPOPTS=-g -Wunused-parameter -Wall -std=c++11 -m32 -Wstack-usage=300 -include Arduino.h .phony: all From b37e9d232b48d76d15b5f423ef410bf5acf15cbf Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 2 Apr 2021 19:27:12 -0700 Subject: [PATCH 048/150] Add support for Raspberry Pi Pico Arduino Core Adds support for the RP2040 core and the PIO based I2S output device. https://github.com/earlephilhower/arduino-pico Poisons some ARM optimizations which don't work on modern Thumbs. --- keywords.txt | 1 + library.json | 10 +--- library.properties | 8 +-- src/AudioFileSourceHTTPStream.cpp | 4 ++ src/AudioFileSourceHTTPStream.h | 4 +- src/AudioFileSourceICYStream.cpp | 5 ++ src/AudioFileSourceICYStream.h | 6 +- src/AudioFileSourceSPIRAMBuffer.cpp | 4 ++ src/AudioFileSourceSPIRAMBuffer.h | 4 +- src/AudioGeneratorFLAC.cpp | 6 +- src/AudioOutputI2S.cpp | 87 +++++++++++++++++++---------- src/AudioOutputI2S.h | 19 +++---- src/AudioOutputI2SNoDAC.cpp | 13 ++++- src/AudioOutputI2SNoDAC.h | 6 +- src/AudioOutputSPDIF.cpp | 3 + src/AudioOutputSPDIF.h | 4 +- src/libflac/cpu.c | 2 +- src/libhelix-aac/assembly.h | 4 +- src/libhelix-aac/sbr.c | 1 + src/libhelix-aac/sbrhfgen.c | 4 +- src/libhelix-mp3/assembly.h | 4 +- 21 files changed, 121 insertions(+), 78 deletions(-) diff --git a/keywords.txt b/keywords.txt index 251f431e..75b11139 100644 --- a/keywords.txt +++ b/keywords.txt @@ -22,6 +22,7 @@ AudioGeneratorWAV KEYWORD1 AudioOutput KEYWORD1 AudioOutputI2S KEYWORD1 AudioOutputI2SNoDAC KEYWORD1 +AudioOutputI2SClass KEYWORD1 AudioOutputNull KEYWORD1 AudioOutputBuffer KEYWORD1 AudioOutputSerialWAV KEYWORD1 diff --git a/library.json b/library.json index c351e329..c6c2e355 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "ESP8266Audio", - "description": "Audio file format and I2S DAC library", + "description": "Audio file format and I2S DAC library for ESP8266, ESP32, and Raspberry Pi Pico RP2040", "keywords": "ESP8266, ESP32, MP3, AAC, WAV, MOD, FLAC, RTTTL, MIDI, I2S, DAC, Delta-Sigma, TTS", "authors": [ { @@ -14,14 +14,8 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.8.1", + "version": "1.9.0", "homepage": "https://github.com/earlephilhower/ESP8266Audio", - "dependencies": { - "SPI": "1.0", - "SPIFFS": "1.0", - "HTTPClient": "1.0", - "WiFiClientSecure": "1.0" - }, "frameworks": "Arduino", "examples": [ "examples/*/*.ino" diff --git a/library.properties b/library.properties index 72da8a86..0560012f 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=ESP8266Audio -version=1.8.1 +version=1.9.0 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III -sentence=Audio file and I2S sound playing routines. -paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Talkie, and WAV and play on an I2S DAC or a software-driven delta-sigma DAC and 1-transistor amplifier. +sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 +.paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Talkie, and WAV and play on an I2S DAC or a software-driven delta-sigma DAC and 1-transistor amplifier. category=Signal Input/Output url=https://github.com/earlephilhower/ESP8266Audio -architectures=esp8266,esp32 +architectures=esp8266,esp32,rp2040 diff --git a/src/AudioFileSourceHTTPStream.cpp b/src/AudioFileSourceHTTPStream.cpp index 2917fbc1..c5d0b833 100644 --- a/src/AudioFileSourceHTTPStream.cpp +++ b/src/AudioFileSourceHTTPStream.cpp @@ -18,6 +18,8 @@ along with this program. If not, see . */ +#if defined(ESP32) || defined(ESP8266) + #include "AudioFileSourceHTTPStream.h" AudioFileSourceHTTPStream::AudioFileSourceHTTPStream() @@ -152,3 +154,5 @@ uint32_t AudioFileSourceHTTPStream::getPos() { return pos; } + +#endif diff --git a/src/AudioFileSourceHTTPStream.h b/src/AudioFileSourceHTTPStream.h index bb5014d2..34e54663 100644 --- a/src/AudioFileSourceHTTPStream.h +++ b/src/AudioFileSourceHTTPStream.h @@ -18,8 +18,8 @@ along with this program. If not, see . */ -#ifndef _AUDIOFILESOURCEHTTPSTREAM_H -#define _AUDIOFILESOURCEHTTPSTREAM_H +#if defined(ESP32) || defined(ESP8266) +#pragma once #include #ifdef ESP32 diff --git a/src/AudioFileSourceICYStream.cpp b/src/AudioFileSourceICYStream.cpp index 522db406..63c84f32 100644 --- a/src/AudioFileSourceICYStream.cpp +++ b/src/AudioFileSourceICYStream.cpp @@ -17,6 +17,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ + +#if defined(ESP32) || defined(ESP8266) + #define _GNU_SOURCE #include "AudioFileSourceICYStream.h" @@ -215,3 +218,5 @@ uint32_t AudioFileSourceICYStream::readInternal(void *data, uint32_t len, bool n icyByteCount += ret; return read; } + +#endif diff --git a/src/AudioFileSourceICYStream.h b/src/AudioFileSourceICYStream.h index 479c16b4..97688a57 100644 --- a/src/AudioFileSourceICYStream.h +++ b/src/AudioFileSourceICYStream.h @@ -18,8 +18,8 @@ along with this program. If not, see . */ -#ifndef _AUDIOFILESOURCEICYSTREAM_H -#define _AUDIOFILESOURCEICYSTREAM_H +#if defined(ESP32) || defined(ESP8266) +#pragma once #include #ifdef ESP32 @@ -45,6 +45,4 @@ class AudioFileSourceICYStream : public AudioFileSourceHTTPStream int icyByteCount; }; - #endif - diff --git a/src/AudioFileSourceSPIRAMBuffer.cpp b/src/AudioFileSourceSPIRAMBuffer.cpp index fafadcea..2c9eb3b9 100644 --- a/src/AudioFileSourceSPIRAMBuffer.cpp +++ b/src/AudioFileSourceSPIRAMBuffer.cpp @@ -22,6 +22,8 @@ along with this program. If not, see . */ +#if defined(ESP32) || defined(ESP8266) + #include #include "AudioFileSourceSPIRAMBuffer.h" @@ -165,3 +167,5 @@ bool AudioFileSourceSPIRAMBuffer::loop() } return true; } + +#endif diff --git a/src/AudioFileSourceSPIRAMBuffer.h b/src/AudioFileSourceSPIRAMBuffer.h index 19d915f1..d8c05540 100644 --- a/src/AudioFileSourceSPIRAMBuffer.h +++ b/src/AudioFileSourceSPIRAMBuffer.h @@ -19,8 +19,8 @@ along with this program. If not, see . */ -#ifndef _AUDIOFILESOURCESPIRAMBUFFER_H -#define _AUDIOFILESOURCESPIRAMBUFFER_H +#if defined(ESP32) || defined(ESP8266) +#pragma once #include "AudioFileSource.h" #include diff --git a/src/AudioGeneratorFLAC.cpp b/src/AudioGeneratorFLAC.cpp index 1af00ce3..bd6e801c 100644 --- a/src/AudioGeneratorFLAC.cpp +++ b/src/AudioGeneratorFLAC.cpp @@ -177,9 +177,9 @@ FLAC__StreamDecoderWriteStatus AudioGeneratorFLAC::write_cb(const FLAC__StreamDe // Hackish warning here. FLAC sends the buffer but doesn't free it until the next call to decode_frame, so we stash // the pointers here and use it in our loop() instead of memcpy()'ing into yet another buffer. buffLen = frame->header.blocksize; - buff[0] = buffer[0]; - if (frame->header.channels>1) buff[1] = buffer[1]; - else buff[1] = buffer[0]; + buff[0] = (const int *)buffer[0]; + if (frame->header.channels>1) buff[1] = (const int *)buffer[1]; + else buff[1] = (const int *)buffer[0]; buffPtr = 0; return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; } diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 6d0762db..496c2d14 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -21,11 +21,14 @@ #include #ifdef ESP32 #include "driver/i2s.h" -#else +#elif defined(ESP8266) #include +#elif defined(ARDUINO_ARCH_RP2040) + #include #endif #include "AudioOutputI2S.h" +#if defined(ESP32) || defined(ESP8266) AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int use_apll) { this->portNo = port; @@ -48,18 +51,25 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int SetGain(1.0); } -AudioOutputI2S::~AudioOutputI2S() +bool AudioOutputI2S::SetPinout() { #ifdef ESP32 - if (i2sOn) { - audioLogger->printf("UNINSTALL I2S\n"); - i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver - } + if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) + return false; // Not allowed + + i2s_pin_config_t pins = { + .bck_io_num = bclkPin, + .ws_io_num = wclkPin, + .data_out_num = doutPin, + .data_in_num = I2S_PIN_NO_CHANGE}; + i2s_set_pin((i2s_port_t)portNo, &pins); + return true; #else - if (i2sOn) - i2s_end(); + (void)bclkPin; + (void)wclkPin; + (void)doutPin; + return false; #endif - i2sOn = false; } bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout) @@ -72,26 +82,33 @@ bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout) return true; } +#elif defined(ARDUINO_ARCH_RP2040) +AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) { + i2sOn = false; + mono = false; + bps = 16; + channels = 2; + hertz = sampleRate; + bclkPin = sck; + doutPin = data; + SetGain(1.0); +} +#endif -bool AudioOutputI2S::SetPinout() +AudioOutputI2S::~AudioOutputI2S() { #ifdef ESP32 - if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) - return false; // Not allowed - - i2s_pin_config_t pins = { - .bck_io_num = bclkPin, - .ws_io_num = wclkPin, - .data_out_num = doutPin, - .data_in_num = I2S_PIN_NO_CHANGE}; - i2s_set_pin((i2s_port_t)portNo, &pins); - return true; - #else - (void)bclkPin; - (void)wclkPin; - (void)doutPin; - return false; + if (i2sOn) { + audioLogger->printf("UNINSTALL I2S\n"); + i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver + } + #elif defined(ESP8266) + if (i2sOn) + i2s_end(); + #elif defined(ARDUINO_ARCH_RP2040) + stop(); #endif + i2sOn = false; } bool AudioOutputI2S::SetRate(int hz) @@ -102,8 +119,10 @@ bool AudioOutputI2S::SetRate(int hz) { #ifdef ESP32 i2s_set_sample_rates((i2s_port_t)portNo, AdjustI2SRate(hz)); - #else + #elif defined(ESP8266) i2s_set_rate(AdjustI2SRate(hz)); + #elif defined(ARDUINO_ARCH_RP2040) + I2S.setFrequency(hz); #endif } return true; @@ -189,7 +208,7 @@ bool AudioOutputI2S::begin(bool txDAC) } i2s_zero_dma_buffer((i2s_port_t)portNo); } - #else + #elif defined(ESP8266) (void)dma_buf_count; (void)use_apll; if (!i2sOn) @@ -209,6 +228,11 @@ bool AudioOutputI2S::begin(bool txDAC) } #endif } + #elif defined(ARDUINO_ARCH_RP2040) + (void)txDAC; + if (!i2sOn) { + I2S.begin(hertz, bclkPin, doutPin); + } #endif i2sOn = true; SetRate(hertz); // Default @@ -246,9 +270,11 @@ bool AudioOutputI2S::ConsumeSample(int16_t sample[2]) s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); } return i2s_write_bytes((i2s_port_t)portNo, (const char *)&s32, sizeof(uint32_t), 0); - #else + #elif defined(ESP8266) uint32_t s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); return i2s_write_sample_nb(s32); // If we can't store it, return false. OTW true + #elif defined(ARDUINO_ARCH_RP2040) + return !!I2S.write((void*)ms, 4); #endif } @@ -265,6 +291,8 @@ void AudioOutputI2S::flush() delay(10); } } + #elif defined(ARDUINO_ARCH_RP2040) + I2S.flush(); #endif } @@ -275,6 +303,9 @@ bool AudioOutputI2S::stop() #ifdef ESP32 i2s_zero_dma_buffer((i2s_port_t)portNo); + #elif defined(ARDUINO_ARCH_RP2040) + I2S.end(); #endif + i2sOn = false; return true; } diff --git a/src/AudioOutputI2S.h b/src/AudioOutputI2S.h index f221d2e4..90370dc2 100644 --- a/src/AudioOutputI2S.h +++ b/src/AudioOutputI2S.h @@ -18,17 +18,22 @@ along with this program. If not, see . */ -#ifndef _AUDIOOUTPUTI2S_H -#define _AUDIOOUTPUTI2S_H +#pragma once #include "AudioOutput.h" class AudioOutputI2S : public AudioOutput { public: +#if defined(ESP32) || defined(ESP8266) AudioOutputI2S(int port=0, int output_mode=EXTERNAL_I2S, int dma_buf_count = 8, int use_apll=APLL_DISABLE); - virtual ~AudioOutputI2S() override; bool SetPinout(int bclkPin, int wclkPin, int doutPin); + enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 }; + enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 }; +#elif defined(ARDUINO_ARCH_RP2040) + AudioOutputI2S(long sampleRate = 44100, pin_size_t sck = 26, pin_size_t data = 28); +#endif + virtual ~AudioOutputI2S() override; virtual bool SetRate(int hz) override; virtual bool SetBitsPerSample(int bits) override; virtual bool SetChannels(int channels) override; @@ -37,12 +42,9 @@ class AudioOutputI2S : public AudioOutput virtual void flush() override; virtual bool stop() override; - bool begin (bool txDAC); + bool begin(bool txDAC); bool SetOutputModeMono(bool mono); // Force mono output no matter the input - enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 }; - enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 }; - protected: bool SetPinout(); virtual int AdjustI2SRate(int hz) { return hz; } @@ -60,6 +62,3 @@ class AudioOutputI2S : public AudioOutput uint8_t wclkPin; uint8_t doutPin; }; - -#endif - diff --git a/src/AudioOutputI2SNoDAC.cpp b/src/AudioOutputI2SNoDAC.cpp index cb36e13e..b8040e3e 100644 --- a/src/AudioOutputI2SNoDAC.cpp +++ b/src/AudioOutputI2SNoDAC.cpp @@ -21,8 +21,10 @@ #include #ifdef ESP32 #include "driver/i2s.h" -#else +#elif defined(ESP8266) #include +#elif defined(ARDUINO_ARCH_RP2040) + #include #endif #include "AudioOutputI2SNoDAC.h" @@ -32,7 +34,7 @@ AudioOutputI2SNoDAC::AudioOutputI2SNoDAC(int port) : AudioOutputI2S(port, false) SetOversampling(32); lastSamp = 0; cumErr = 0; -#ifndef ESP32 +#ifdef ESP8266 WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U, orig_bck); WRITE_PERI_REG(PERIPHS_IO_MUX_GPIO2_U, orig_ws); #endif @@ -97,12 +99,17 @@ bool AudioOutputI2SNoDAC::ConsumeSample(int16_t sample[2]) #ifdef ESP32 if (!i2s_write_bytes((i2s_port_t)portNo, (const char *)dsBuff, sizeof(uint32_t) * (oversample/32), 0)) return false; -#else +#elif defined(ESP8266) if (!i2s_write_sample_nb(dsBuff[0])) return false; // No room at the inn // At this point we've sent in first of possibly 8 32-bits, need to send // remaining ones even if they block. for (int i = 32; i < oversample; i+=32) i2s_write_sample( dsBuff[i / 32]); +#elif defined(ARDUINO_ARCH_RP2040) + int16_t *p = (int16_t *) dsBuff; + for (int i = 0; i < oversample / 16; i++) { + I2S.write(*(p++)); + } #endif return true; } diff --git a/src/AudioOutputI2SNoDAC.h b/src/AudioOutputI2SNoDAC.h index d1738d19..2a632252 100644 --- a/src/AudioOutputI2SNoDAC.h +++ b/src/AudioOutputI2SNoDAC.h @@ -18,8 +18,7 @@ along with this program. If not, see . */ -#ifndef _AUDIOOUTPUTI2SNODAC_H -#define _AUDIOOUTPUTI2SNODAC_H +#pragma once #include "AudioOutputI2S.h" @@ -42,6 +41,3 @@ class AudioOutputI2SNoDAC : public AudioOutputI2S fixed24p8_t lastSamp; // Last sample value fixed24p8_t cumErr; // Running cumulative error since time began }; - -#endif - diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index 8c993c5f..53483d4a 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -37,6 +37,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#if defined(ESP32) || defined(ESP8266) #include #if defined(ESP32) @@ -286,3 +287,5 @@ bool AudioOutputSPDIF::stop() frame_num = 0; return true; } + +#endif diff --git a/src/AudioOutputSPDIF.h b/src/AudioOutputSPDIF.h index 92a4e46e..5da160b3 100644 --- a/src/AudioOutputSPDIF.h +++ b/src/AudioOutputSPDIF.h @@ -30,8 +30,8 @@ along with this program. If not, see . */ -#ifndef _AUDIOOUTPUTSPDIF_H -#define _AUDIOOUTPUTSPDIF_H +#if defined(ESP32) || defined(ESP8266) +#pragma once #include "AudioOutput.h" diff --git a/src/libflac/cpu.c b/src/libflac/cpu.c index efed11b7..cd650a09 100644 --- a/src/libflac/cpu.c +++ b/src/libflac/cpu.c @@ -31,7 +31,7 @@ */ //#ifdef HAVE_CONFIG_H -# include +# include "config.h" //#endif #include "private/cpu.h" diff --git a/src/libhelix-aac/assembly.h b/src/libhelix-aac/assembly.h index fc4d7673..595a8fc9 100644 --- a/src/libhelix-aac/assembly.h +++ b/src/libhelix-aac/assembly.h @@ -223,7 +223,7 @@ Word64 MADD64(Word64 sum64, int x, int y); /* toolchain: ARM ADS or RealView * target architecture: ARM v.4 and above (requires 'M' type processor for 32x32->64 multiplier) */ -#elif defined (__arm) && defined (__ARMCC_VERSION) +#elif defined (XXX__arm) && defined (__ARMCC_VERSION) static __inline int MULSHIFT32(int x, int y) { @@ -336,7 +336,7 @@ static __inline Word64 MADD64(Word64 sum64, int x, int y) /* toolchain: ARM gcc * target architecture: ARM v.4 and above (requires 'M' type processor for 32x32->64 multiplier) */ -#elif defined(__GNUC__) && defined(__arm__) +#elif defined(__GNUC__) && defined(XXXX__arm__) static inline int MULSHIFT32(int x, int y) { diff --git a/src/libhelix-aac/sbr.c b/src/libhelix-aac/sbr.c index ec046720..e4639158 100644 --- a/src/libhelix-aac/sbr.c +++ b/src/libhelix-aac/sbr.c @@ -44,6 +44,7 @@ **************************************************************************************/ #if defined(USE_DEFAULT_STDLIB) || defined(ARDUINO) +#include #include #else #include "hlxclib/stdlib.h" diff --git a/src/libhelix-aac/sbrhfgen.c b/src/libhelix-aac/sbrhfgen.c index 7ebc047a..e5f27eb6 100644 --- a/src/libhelix-aac/sbrhfgen.c +++ b/src/libhelix-aac/sbrhfgen.c @@ -76,7 +76,7 @@ static const int newBWTab[4][4] PROGMEM = { * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrcov.s when building for ARM! **************************************************************************************/ -#if (defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__)) +#if (defined (XXXX__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(XXXX__arm__)) #ifdef __cplusplus extern "C" #endif @@ -237,7 +237,7 @@ static int CalcCovariance1(int *XBuf, int *p01reN, int *p01imN, int *p12reN, int * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrcov.s when building for ARM! **************************************************************************************/ -#if (defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__)) +#if (defined (XXXX__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(XXXX__arm__)) #ifdef __cplusplus extern "C" #endif diff --git a/src/libhelix-mp3/assembly.h b/src/libhelix-mp3/assembly.h index 9c10c4da..b9e46c52 100644 --- a/src/libhelix-mp3/assembly.h +++ b/src/libhelix-mp3/assembly.h @@ -217,7 +217,7 @@ static __inline int CLZ(int x) return numZeros; } -#elif defined ARM_ADS +#elif defined XXXARM_ADS static __inline int MULSHIFT32(int x, int y) { @@ -267,7 +267,7 @@ static __inline int CLZ(int x) return numZeros; } -#elif defined(__GNUC__) && defined(__thumb__) +#elif defined(__GNUC__) && defined(XXXX__thumb__) static __inline int MULSHIFT32(int x, int y) From 09b1fd17888fc05493fbaeab2b77aebb2a410a2c Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 2 Apr 2021 19:43:20 -0700 Subject: [PATCH 049/150] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 0560012f..fefe4a7c 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=1.9.0 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 -.paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Talkie, and WAV and play on an I2S DAC or a software-driven delta-sigma DAC and 1-transistor amplifier. +paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Talkie, and WAV and play on an I2S DAC or a software-driven delta-sigma DAC and 1-transistor amplifier. category=Signal Input/Output url=https://github.com/earlephilhower/ESP8266Audio architectures=esp8266,esp32,rp2040 From a72bee6d739f2d245deb245a04c8d3cf5f51ef08 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 2 Apr 2021 19:54:28 -0700 Subject: [PATCH 050/150] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c8c92ff6..f243db52 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ESP8266Audio - supports ESP8266 & ESP32 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +# ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi RP2040[![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTTL files and playing them on an I2S DAC or even using a software-simulated delta-sigma DAC with dynamic 32x-128x oversampling. ESP8266 is fully supported and most mature, but ESP32 is also mostly there with built-in DAC as well as external ones. From 8d6631e4ab6894eb299ba2e5a24ab58a6879c58d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 5 Apr 2021 17:03:34 -0700 Subject: [PATCH 051/150] Update I2S class API for RP2040 --- src/AudioOutputI2S.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 496c2d14..f4393e25 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -231,7 +231,9 @@ bool AudioOutputI2S::begin(bool txDAC) #elif defined(ARDUINO_ARCH_RP2040) (void)txDAC; if (!i2sOn) { - I2S.begin(hertz, bclkPin, doutPin); + I2S.setBCLK(bclkPin); + I2S.setDOUT(doutPin); + I2S.begin(hertz); } #endif i2sOn = true; From 9b4f36009b8c2c8c9ed8715bbba08ccc783b3a2f Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Mon, 12 Apr 2021 05:57:55 +0900 Subject: [PATCH 052/150] Fix compile error due to insufficient capacity (#384) --- examples/PlayWAVFromPROGMEM/PlayWAVFromPROGMEM.ino | 6 ------ 1 file changed, 6 deletions(-) diff --git a/examples/PlayWAVFromPROGMEM/PlayWAVFromPROGMEM.ino b/examples/PlayWAVFromPROGMEM/PlayWAVFromPROGMEM.ino index 5221c913..cb488f1c 100644 --- a/examples/PlayWAVFromPROGMEM/PlayWAVFromPROGMEM.ino +++ b/examples/PlayWAVFromPROGMEM/PlayWAVFromPROGMEM.ino @@ -1,9 +1,4 @@ #include -#ifdef ESP32 - #include -#else - #include -#endif #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorWAV.h" @@ -18,7 +13,6 @@ AudioOutputI2SNoDAC *out; void setup() { - WiFi.mode(WIFI_OFF); Serial.begin(115200); delay(1000); Serial.printf("WAV start\n"); From f974af9bf323f1cf93a4663f9b26c050cc78c39c Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Mon, 12 Apr 2021 10:37:38 +0900 Subject: [PATCH 053/150] Add `AudioFileSourceFunction` which can generate sound from functions (#383) --- .../PlayWAVFromFunction.ino | 78 +++++++++ src/AudioFileSourceFunction.cpp | 148 ++++++++++++++++++ src/AudioFileSourceFunction.h | 119 ++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 examples/PlayWAVFromFunction/PlayWAVFromFunction.ino create mode 100644 src/AudioFileSourceFunction.cpp create mode 100644 src/AudioFileSourceFunction.h diff --git a/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino b/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino new file mode 100644 index 00000000..fe0cc896 --- /dev/null +++ b/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino @@ -0,0 +1,78 @@ +#include +#include "AudioFileSourceFunction.h" +#include "AudioGeneratorWAV.h" +#include "AudioOutputI2SNoDAC.h" + +float hz = 440.f; + +// pre-defined function can also be used to generate the wave +float sine_wave(const float time) { + float v = sin(TWO_PI * hz * time); // C + v *= fmod(time, 1.f); // change linear + v *= 0.5; // scale + return v; +}; + +AudioGeneratorWAV* wav; +AudioFileSourceFunction* file; +AudioOutputI2SNoDAC* out; + +void setup() { + Serial.begin(115200); + delay(1000); + + // ===== create instance with length of song in [sec] ===== + file = new AudioFileSourceFunction(8.); + // + // you can set (sec, channels, hz, bit/sample) but you should care about + // the trade-off between performance and the audio quality + // + // file = new AudioFileSourceFunction(sec, channels, hz, bit/sample); + // channels : default = 1 + // hz : default = 8000 (8000, 11025, 22050, 44100, 48000, etc.) + // bit/sample : default = 16 (8, 16, 32) + + // ===== set your sound function ===== + file->addAudioGenerators([&](const float time) { + float v = sin(TWO_PI * hz * time); // generate sine wave + v *= fmod(time, 1.f); // change linear + v *= 0.5; // scale + return v; + }); + // + // sound function should have one argument(float) and one return(float) + // param : float (current time [sec] of the song) + // return : float (the amplitude of sound which varies from -1.f to +1.f) + // + // sound function can be registerd only one or the same number with channels + // if the channels > 1 && the number of function == 1, + // same function are used to generate the sound in every channel + // + // file = new AudioFileSourceFunction(8., 2); + // file->addAudioGenerators( + // // L (channel 0) + // [](const float time) { + // return 0.25 * sin(TWO_PI * 440.f * time) * fmod(time, 1.f); // C + // }, + // // R (channel 1) + // [](const float time) { + // return 0.25 * sin(TWO_PI * 550.f * time) * fmod(time, 1.f); // E + // } + // ); + // + // you can also use the pre-defined function + // file->addAudioGenerators(sine_wave); + + out = new AudioOutputI2SNoDAC(); + wav = new AudioGeneratorWAV(); + wav->begin(file, out); +} + +void loop() { + if (wav->isRunning()) { + if (!wav->loop()) wav->stop(); + } else { + Serial.println("function done!"); + delay(1000); + } +} diff --git a/src/AudioFileSourceFunction.cpp b/src/AudioFileSourceFunction.cpp new file mode 100644 index 00000000..48dd59f8 --- /dev/null +++ b/src/AudioFileSourceFunction.cpp @@ -0,0 +1,148 @@ +/* + AudioFileSourceFunction + Audio ouptut generator which can generate WAV file data from function + + Copyright (C) 2021 Hideaki Tai + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "AudioFileSourceFunction.h" + +AudioFileSourceFunction::AudioFileSourceFunction(float sec, uint16_t channels, uint32_t sample_per_sec, uint16_t bits_per_sample) { + uint32_t bytes_per_sec = sample_per_sec * channels * bits_per_sample / 8; + uint32_t len = uint32_t(sec * (float)bytes_per_sec); + + // RIFF chunk + strncpy(wav_header.riff.chunk_id, "RIFF", 4); + wav_header.riff.chunk_size = 4 // size of riff chunk w/o chunk_id and chunk_size + + 8 + 16 // size of format chunk + + 8 + len; // size of data chunk + strncpy(wav_header.riff.format, "WAVE", 4); + + // format chunk + strncpy(wav_header.format.chunk_id, "fmt ", 4); + wav_header.format.chunk_size = 16; + wav_header.format.format_tag = 0x0001; // PCM + wav_header.format.channels = channels; + wav_header.format.sample_per_sec = sample_per_sec; + wav_header.format.avg_bytes_per_sec = bytes_per_sec; + wav_header.format.block_align = channels * bits_per_sample / 8; + wav_header.format.bits_per_sample = bits_per_sample; + + // data chunk + strncpy(wav_header.data.chunk_id, "data", 4); + wav_header.data.chunk_size = len; + + funcs.reserve(channels); + pos = 0; + size = sizeof(WavHeader) + len; + is_ready = false; + is_unique = false; +} + +AudioFileSourceFunction::~AudioFileSourceFunction() { + close(); +} + +uint32_t AudioFileSourceFunction::read(void* data, uint32_t len) { + // callback size must be 1 or equal to channels + if (!is_ready) + return 0; + + uint8_t* d = reinterpret_cast(data); + uint32_t i = 0; + while (i < len) { + uint32_t p = pos + i; + if (p < sizeof(WavHeader)) { + // header bytes + d[i] = wav_header.bytes[p]; + i += 1; + } else { + // data bytes + float time = (float)p / (float)wav_header.format.avg_bytes_per_sec; + float v = funcs[0](time); + for (size_t ch = 0; ch < wav_header.format.channels; ++ch) { + if (!is_unique && ch > 0) + v = funcs[ch](time); + + switch (wav_header.format.bits_per_sample) { + case 8: { + Uint8AndInt8 vs {int8_t(v * (float)0x7F)}; + d[i] = vs.u; + break; + } + case 32: { + Uint8AndInt32 vs {int32_t(v * (float)0x7FFFFFFF)}; + d[i + 0] = vs.u[0]; + d[i + 1] = vs.u[1]; + d[i + 2] = vs.u[2]; + d[i + 3] = vs.u[3]; + break; + } + case 16: + default: { + Uint8AndInt16 vs {int16_t(v * (float)0x7FFF)}; + d[i + 0] = vs.u[0]; + d[i + 1] = vs.u[1]; + break; + } + } + } + i += wav_header.format.block_align; + } + } + pos += i; + return (pos >= size) ? 0 : i; +} + +bool AudioFileSourceFunction::seek(int32_t pos, int dir) { + if (dir == SEEK_SET) { + if (pos < 0 || (uint32_t)pos >= size) + return false; + this->pos = pos; + } else if (dir == SEEK_CUR) { + int32_t p = (int32_t)this->pos + pos; + if (p < 0 || (uint32_t)p >= size) + return false; + this->pos = p; + } else { + int32_t p = (int32_t)this->size + pos; + if (p < 0 || (uint32_t)p >= size) + return false; + this->pos = p; + } + return true; +} + +bool AudioFileSourceFunction::close() { + funcs.clear(); + pos = 0; + size = 0; + is_ready = false; + is_unique = false; + return true; +} + +bool AudioFileSourceFunction::isOpen() { + return is_ready; +} + +uint32_t AudioFileSourceFunction::getSize() { + return size; +} + +uint32_t AudioFileSourceFunction::getPos() { + return pos; +} diff --git a/src/AudioFileSourceFunction.h b/src/AudioFileSourceFunction.h new file mode 100644 index 00000000..6c41229a --- /dev/null +++ b/src/AudioFileSourceFunction.h @@ -0,0 +1,119 @@ +/* + AudioFileSourceFunction + Audio ouptut generator which can generate WAV file data from function + + Copyright (C) 2021 Hideaki Tai + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef _AUDIOFILESOURCEFUNCTION_H +#define _AUDIOFILESOURCEFUNCTION_H + +#include +#include +#include + +#include "AudioFileSource.h" + +class AudioFileSourceFunction : public AudioFileSource { + union WavHeader { + struct { + // RIFF chunk + struct { + char chunk_id[4]; // "RIFF" + uint32_t chunk_size; // 4 + (8 + sizeof(format_chunk)(16)) + (8 + sizeof(data_chunk)) + char format[4]; // "WAVE" + } riff; + // format chunk + struct { + char chunk_id[4]; // "fmt " + uint32_t chunk_size; // 16 + uint16_t format_tag; // 1: PCM + uint16_t channels; // 1: MONO, 2: STEREO + uint32_t sample_per_sec; // 8000, 11025, 22050, 44100, 48000 + uint32_t avg_bytes_per_sec; // sample_per_sec * channels * bits_per_sample / 8 + uint16_t block_align; // channels * bits_per_sample / 8 + uint16_t bits_per_sample; // 8, 16, 32 + } format; + // data chunk + struct { + char chunk_id[4]; // "data" + uint32_t chunk_size; // num_samples * channels * bytes_per_sample + // audio data follows here... + } data; + }; + uint8_t bytes[44]; + } wav_header; + + union Uint8AndInt8 { + int8_t i; + uint8_t u; + }; + + union Uint8AndInt16 { + int16_t i; + uint8_t u[2]; + }; + + union Uint8AndInt32 { + int32_t i; + uint8_t u[4]; + }; + + using callback_t = std::function; + std::vector funcs; + uint32_t pos; + uint32_t size; + bool is_ready; + bool is_unique; + +public: + AudioFileSourceFunction(float sec, uint16_t channels = 1, uint32_t sample_per_sec = 8000, uint16_t bits_per_sample = 16); + virtual ~AudioFileSourceFunction() override; + + template + bool addAudioGenerators(const F& f, Fs&&... fs) { + funcs.emplace_back(f); + return addAudioGenerators(std::forward(fs)...); + } + bool addAudioGenerators() { + funcs.shrink_to_fit(); + if (funcs.size() == 1) { + is_ready = true; + is_unique = true; + return true; + } else if (funcs.size() == wav_header.format.channels) { + is_ready = true; + is_unique = false; + return true; + } else { + is_ready = false; + is_unique = false; + funcs.clear(); + return false; + } + } + + virtual uint32_t read(void* data, uint32_t len) override; + virtual bool seek(int32_t pos, int dir) override; + + virtual bool close() override; + virtual bool isOpen() override; + + virtual uint32_t getSize() override; + virtual uint32_t getPos() override; +}; + +#endif // _AUDIOFILESOURCEFUNCTION_H From 8bf52d4c11d7920fe530279a3758f220edcef0b6 Mon Sep 17 00:00:00 2001 From: Hideaki Tai Date: Tue, 13 Apr 2021 23:35:52 +0900 Subject: [PATCH 054/150] =?UTF-8?q?Fix=20the=20start=20of=20the=20arg=20?= =?UTF-8?q?=E2=80=9Ctime=E2=80=9D=20is=20not=20zero=20(#386)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In the first call of funcs[0](time), time should be zero but it was not. --- src/AudioFileSourceFunction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioFileSourceFunction.cpp b/src/AudioFileSourceFunction.cpp index 48dd59f8..9e86eff2 100644 --- a/src/AudioFileSourceFunction.cpp +++ b/src/AudioFileSourceFunction.cpp @@ -71,7 +71,7 @@ uint32_t AudioFileSourceFunction::read(void* data, uint32_t len) { i += 1; } else { // data bytes - float time = (float)p / (float)wav_header.format.avg_bytes_per_sec; + float time = (float)(p - sizeof(WavHeader)) / (float)wav_header.format.avg_bytes_per_sec; float v = funcs[0](time); for (size_t ch = 0; ch < wav_header.format.channels; ++ch) { if (!is_unique && ch > 0) From d4c09498c574fb9f24bc4a64b4611f1c716b79e8 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 12 Jun 2021 15:15:21 -0700 Subject: [PATCH 055/150] Update library.json --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index c6c2e355..d416bc29 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.0", + "version": "1.9.1", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ From 4111404bac618ff0613043d74ffa1481fa2a2a96 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 12 Jun 2021 15:15:44 -0700 Subject: [PATCH 056/150] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index fefe4a7c..4a67f0c0 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.0 +version=1.9.1 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From c3c9a147c59c64c8f28dc1ccc9e30b84a79c05b1 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Tue, 29 Jun 2021 06:45:16 +0200 Subject: [PATCH 057/150] i2s on esp8266: fix include (#402) --- src/AudioOutputI2S.cpp | 4 +--- src/AudioOutputI2SNoDAC.cpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index f4393e25..cec3abe7 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -21,9 +21,7 @@ #include #ifdef ESP32 #include "driver/i2s.h" -#elif defined(ESP8266) - #include -#elif defined(ARDUINO_ARCH_RP2040) +#elif defined(ARDUINO_ARCH_RP2040) || defined(ESP8266) #include #endif #include "AudioOutputI2S.h" diff --git a/src/AudioOutputI2SNoDAC.cpp b/src/AudioOutputI2SNoDAC.cpp index b8040e3e..c38b4b5f 100644 --- a/src/AudioOutputI2SNoDAC.cpp +++ b/src/AudioOutputI2SNoDAC.cpp @@ -21,9 +21,7 @@ #include #ifdef ESP32 #include "driver/i2s.h" -#elif defined(ESP8266) - #include -#elif defined(ARDUINO_ARCH_RP2040) +#elif defined(ARDUINO_ARCH_RP2040) || defined(ESP8266) #include #endif #include "AudioOutputI2SNoDAC.h" From 5a5c2a88a3312749494f0608a10a9df162c157cc Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 28 Jun 2021 21:46:50 -0700 Subject: [PATCH 058/150] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 4a67f0c0..111915c1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.1 +version=1.9.2 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From 6ed2604015ac611806e5ea18007f44082113021d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 28 Jun 2021 21:47:06 -0700 Subject: [PATCH 059/150] Update library.json --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index d416bc29..13929188 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.1", + "version": "1.9.2", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ From 6882b6e1b695bef9981420fd41d7af13290d918a Mon Sep 17 00:00:00 2001 From: qnxsgwy Date: Wed, 8 Sep 2021 23:57:25 +0800 Subject: [PATCH 060/150] Fix 'i2s_write_bytes' was not declared in this scope on ESP32 (#428) --- src/AudioOutputI2S.cpp | 7 ++++++- src/AudioOutputI2SNoDAC.cpp | 8 +++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index cec3abe7..5bc6cb00 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -269,7 +269,12 @@ bool AudioOutputI2S::ConsumeSample(int16_t sample[2]) { s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); } - return i2s_write_bytes((i2s_port_t)portNo, (const char *)&s32, sizeof(uint32_t), 0); +//"i2s_write_bytes" has been removed in the ESP32 Arduino 2.0.0, use "i2s_write" instead. +// return i2s_write_bytes((i2s_port_t)portNo, (const char *)&s32, sizeof(uint32_t), 0); + + size_t i2s_bytes_written; + i2s_write((i2s_port_t)portNo, (const char*)&s32, sizeof(uint32_t), &i2s_bytes_written, 0); + return i2s_bytes_written; #elif defined(ESP8266) uint32_t s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); return i2s_write_sample_nb(s32); // If we can't store it, return false. OTW true diff --git a/src/AudioOutputI2SNoDAC.cpp b/src/AudioOutputI2SNoDAC.cpp index c38b4b5f..501634e6 100644 --- a/src/AudioOutputI2SNoDAC.cpp +++ b/src/AudioOutputI2SNoDAC.cpp @@ -95,8 +95,14 @@ bool AudioOutputI2SNoDAC::ConsumeSample(int16_t sample[2]) // Either send complete pulse stream or nothing #ifdef ESP32 - if (!i2s_write_bytes((i2s_port_t)portNo, (const char *)dsBuff, sizeof(uint32_t) * (oversample/32), 0)) +//"i2s_write_bytes" has been removed in the ESP32 Arduino 2.0.0, use "i2s_write" instead. +// if (!i2s_write_bytes((i2s_port_t)portNo, (const char *)dsBuff, sizeof(uint32_t) * (oversample/32), 0)) + + size_t i2s_bytes_written; + i2s_write((i2s_port_t)portNo, (const char *)dsBuff, sizeof(uint32_t) * (oversample/32), &i2s_bytes_written, 0); + if (!i2s_bytes_written){ return false; + } #elif defined(ESP8266) if (!i2s_write_sample_nb(dsBuff[0])) return false; // No room at the inn // At this point we've sent in first of possibly 8 32-bits, need to send From 627a1064797c6c6c87fb79ce6910cc65e4fbcc9e Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 8 Sep 2021 08:57:51 -0700 Subject: [PATCH 061/150] Update library.json --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index 13929188..bab90529 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.2", + "version": "1.9.3", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ From 9dd4f24056821a2591f825c743d152bab862984a Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 8 Sep 2021 08:58:14 -0700 Subject: [PATCH 062/150] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 111915c1..1f130374 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.2 +version=1.9.3 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From f47793bc4c4d0110d1073a0edef06f32c47fcd44 Mon Sep 17 00:00:00 2001 From: Martin-Laclaustra Date: Tue, 14 Sep 2021 03:06:55 +0200 Subject: [PATCH 063/150] Make LittleFS file source available for ESP32 (#430) --- src/AudioFileSourceLittleFS.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/AudioFileSourceLittleFS.h b/src/AudioFileSourceLittleFS.h index 27d94bb8..b57b89fa 100644 --- a/src/AudioFileSourceLittleFS.h +++ b/src/AudioFileSourceLittleFS.h @@ -21,8 +21,6 @@ #ifndef _AUDIOFILESOURCESPIFFS_H #define _AUDIOFILESOURCESPIFFS_H -#ifndef ESP32 // No LittleFS there, yet - #include #include @@ -39,5 +37,3 @@ class AudioFileSourceLittleFS : public AudioFileSourceFS #endif -#endif - From 5411abef6bf12075961ecc19043a4f90c7e8a31c Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 19 Oct 2021 12:19:10 -0700 Subject: [PATCH 064/150] Update Linear Clock links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f243db52..8b36ac1c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ JohannesMTC has built a similar project especially for model trains: https://git A neat MQTT-driven ESP8266 light-and-sound device (alarm? toy? who can say!) was built by @CosmicMac, available at https://github.com/CosmicMac/ESParkle -A very interesting "linear clock" with a stepper motor, NTP time keeping, and configurable recorded chimes with schematics, 3D printer plans, and source code, is now available http://home.kpn.nl/bderogee1980/projects/linear_clock/linear_clock.html +A very interesting "linear clock" with a stepper motor, NTP time keeping, and configurable recorded chimes with schematics, 3D printer plans, and source code, is now available https://janderogee.com/projects/linear_clock/linear_clock.htm ## Prerequisites First, make sure you are running the 2.6.3/later or GIT head version of the Arduino libraries for ESP8266, or the latest ESP32 SDK from Espressif. From c55abbfba54cce1918c90b161b5244b14a9b43c6 Mon Sep 17 00:00:00 2001 From: pintomax Date: Wed, 3 Nov 2021 03:55:43 +0100 Subject: [PATCH 065/150] Stream MP3 from HTTP to SPDIF (#436) Stream MP3 from HTTP to SPDIF --- .../StreamMP3FromHTTPToSPDIF.ino | 142 ++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino diff --git a/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino b/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino new file mode 100644 index 00000000..b082f7a1 --- /dev/null +++ b/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino @@ -0,0 +1,142 @@ +#include + +#ifdef ESP32 + #include +#else + #include +#endif +#include "AudioFileSourceICYStream.h" +#include "AudioFileSourceBuffer.h" +#include "AudioGeneratorMP3.h" +//#include "AudioOutputI2SNoDAC.h" +#include "AudioOutputSPDIF.h" + +// +// Stream MP3 from HTTP to SPDIF +// + +// To run, set your ESP8266 build to 160MHz, update the SSID info, and upload. + +// Note: +// If using ESP8266 NodeMCU connect LED to RX pin and GND pin + +// Enter your WiFi setup here: +#ifndef STASSID +#define STASSID "your-ssid" +#define STAPSK "your-password" +#endif + +const char* ssid = STASSID; +const char* password = STAPSK; + +// Examples URLs +//const char *URL="http://kvbstreams.dyndns.org:8000/wkvi-am"; + +// Italian Rock Radio +const char *URL="http://streamingv2.shoutcast.com/radiofreccia"; + +// Stream URL of Logitech Media Server, aka LMS, Version: 8.2.0 (August 2021) +// const char *URL="http://192.168.1.121:9000/stream.mp3"; + +AudioGeneratorMP3 *mp3; +AudioFileSourceICYStream *file; +AudioFileSourceBuffer *buff; + +// Output device is SPDIF +AudioOutputSPDIF *out; + + +// Called when a metadata event occurs (i.e. an ID3 tag, an ICY block, etc. +void MDCallback(void *cbData, const char *type, bool isUnicode, const char *string) +{ + const char *ptr = reinterpret_cast(cbData); + (void) isUnicode; // Punt this ball for now + // Note that the type and string may be in PROGMEM, so copy them to RAM for printf + char s1[32], s2[64]; + strncpy_P(s1, type, sizeof(s1)); + s1[sizeof(s1)-1]=0; + strncpy_P(s2, string, sizeof(s2)); + s2[sizeof(s2)-1]=0; + Serial.printf("METADATA(%s) '%s' = '%s'\n", ptr, s1, s2); + Serial.flush(); +} + +// Called when there's a warning or error (like a buffer underflow or decode hiccup) +void StatusCallback(void *cbData, int code, const char *string) +{ + const char *ptr = reinterpret_cast(cbData); + // Note that the string may be in PROGMEM, so copy it to RAM for printf + char s1[64]; + strncpy_P(s1, string, sizeof(s1)); + s1[sizeof(s1)-1]=0; + Serial.printf("STATUS(%s) '%d' = '%s'\n", ptr, code, s1); + Serial.flush(); +} + + +void setup() +{ + Serial.begin(115200); + delay(1000); + Serial.println("Connecting to WiFi"); + + WiFi.disconnect(); + WiFi.softAPdisconnect(true); + WiFi.mode(WIFI_STA); + + WiFi.begin(ssid, password); + + // Try forever + while (WiFi.status() != WL_CONNECTED) { + Serial.println("...Connecting to WiFi"); + delay(1000); + } + Serial.println("Connected"); + + audioLogger = &Serial; + file = new AudioFileSourceICYStream(URL); + + // Commented out for performance issues with high rate MP3 stream + //file->RegisterMetadataCB(MDCallback, (void*)"ICY"); + + buff = new AudioFileSourceBuffer(file, 4096); // Doubled form default 2048 + + // Commented out for performance issues with high rate MP3 stream + //buff->RegisterStatusCB(StatusCallback, (void*)"buffer"); + + // Set SPDIF outout + out = new AudioOutputSPDIF(); + mp3 = new AudioGeneratorMP3(); + + // Commented out for performance issues with high rate MP3 stream + //mp3->RegisterStatusCB(StatusCallback, (void*)"mp3"); + + mp3->begin(buff, out); +} + + +void loop() +{ + // Commented out + //static int lastms = 0; + + if (mp3->isRunning()) { + /* Commented out + if (millis()-lastms > 1000) { + lastms = millis(); + Serial.printf("Running for %d ms...\n", lastms); + Serial.flush(); + } + */ + if (!mp3->loop()) { + mp3->stop(); + } + } else { + Serial.printf("MP3 done\n"); + + // Restart ESP when streaming is done or errored + delay(10000); + + ESP.restart(); + } +} From 62463b15f775c11f2083e939eb30a58d8966d8b0 Mon Sep 17 00:00:00 2001 From: Oderik Date: Thu, 4 Nov 2021 18:29:02 +0100 Subject: [PATCH 066/150] Document ESP8266 I2S pinout (#439) --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b36ac1c..6ff31be9 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,15 @@ AudioOutputSPIFFSWAV: Writes a binary WAV format with headers to a SPIFFS files AudioOutputNull: Just dumps samples to /dev/null. Used for speed testing as it doesn't artificially limit the AudioGenerator output speed since there are no buffers to fill/drain. ## I2S DACs -I've used both the Adafruit [I2S +3W amp DAC](https://www.adafruit.com/product/3006) and a generic PCM5102 based DAC with success. The biggest problems I've seen from users involve pinouts from the ESP8266 for GPIO and hooking up all necessary pins on the DAC board. +I've used both the Adafruit [I2S +3W amp DAC](https://www.adafruit.com/product/3006) and a generic PCM5102 based DAC with success. The biggest problems I've seen from users involve pinouts from the ESP8266 for GPIO and hooking up all necessary pins on the DAC board. The essential pins are: + +I2S pin | Common label* | ESP8266 pin +--------|---------------|------------- +LRC | D4 | GPIO2 +BCLK | D8 | GPIO15 +DIN | RX | GPIO3 + +\* The "common label" column applies to common NodeMCU and D1 Mini development boards. Unfortunately some manufacturers use different mappings so the labels listed here might not apply to your particular model. ### Adafruit I2S DAC This is quite simple and only needs the GND, VIN, LRC, BCLK< and DIN pins to be wired. Be sure to use +5V on the VIN to get the loudest sound. See the [Adafruit example page](https://learn.adafruit.com/adafruit-max98357-i2s-class-d-mono-amp) for more info. From 9485887879acb4d17c06017a60981b82c617f4c5 Mon Sep 17 00:00:00 2001 From: Pixtxa <30337073+Pixtxa@users.noreply.github.com> Date: Sat, 27 Nov 2021 21:35:07 +0100 Subject: [PATCH 067/150] Set FollowRedirects in AudioFileSourceICYStream (#448) --- src/AudioFileSourceICYStream.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AudioFileSourceICYStream.cpp b/src/AudioFileSourceICYStream.cpp index 63c84f32..edeba761 100644 --- a/src/AudioFileSourceICYStream.cpp +++ b/src/AudioFileSourceICYStream.cpp @@ -47,6 +47,7 @@ bool AudioFileSourceICYStream::open(const char *url) http.addHeader("Icy-MetaData", "1"); http.collectHeaders( hdr, 4 ); http.setReuse(true); + http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); int code = http.GET(); if (code != HTTP_CODE_OK) { http.end(); From 84593933e5440fb471d523134f0c9946b6791313 Mon Sep 17 00:00:00 2001 From: Wouter van der Put Date: Sun, 28 Nov 2021 19:28:40 +0100 Subject: [PATCH 068/150] Fix typo in comment (#446) --- src/AudioGeneratorMIDI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index e3be2b2d..b73da9d3 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -331,7 +331,7 @@ void AudioGeneratorMIDI::find_note (int tracknum) { } -// Open file, parse headers, get ready tio process MIDI +// Open file, parse headers, get ready to process MIDI void AudioGeneratorMIDI::PrepareMIDI(AudioFileSource *src) { MakeStreamFromAFS(src, &afsMIDI); From 701ca39669925cb8e868a3849e55845816f18c1e Mon Sep 17 00:00:00 2001 From: Wouter van der Put Date: Sun, 28 Nov 2021 19:29:06 +0100 Subject: [PATCH 069/150] Fix typo in comment (#445) --- src/AudioGeneratorMIDI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index b73da9d3..63722058 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -172,7 +172,7 @@ unsigned int AudioGeneratorMIDI::buffer_int32 (int offset) { unsigned long AudioGeneratorMIDI::get_varlen (int *ptr) { /* Get a 1-4 byte variable-length value and adjust the pointer past it. - These are a succession of 7-bit values with a MSB bit of zero marking the end */ + These are a succession of 7-bit values with an MSB bit of zero marking the end */ unsigned long val; int i, byte; From f9a78e7ef583f2d159819e50691c07d1c2c33d57 Mon Sep 17 00:00:00 2001 From: Wouter van der Put Date: Sun, 28 Nov 2021 19:29:24 +0100 Subject: [PATCH 070/150] Fix typo in comment (#444) --- src/AudioGeneratorMIDI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index 63722058..a76e757c 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -1,6 +1,6 @@ /* AudioGeneratorMIDI - Audio output generator that plays MIDI files using a SF2 SoundFont + Audio output generator that plays MIDI files using an SF2 SoundFont Copyright (C) 2017 Earle F. Philhower, III From b65bc2df8f4c71740f814225cc2b619ff79393d9 Mon Sep 17 00:00:00 2001 From: Wouter van der Put Date: Sun, 28 Nov 2021 19:31:36 +0100 Subject: [PATCH 071/150] Fix: add missing SPIFFS.begin() (#443) Without this fix, there is no sound and the serial monitor shows: Starting up... [E][vfs_api.cpp:22] open(): File system is not mounted [E][vfs_api.cpp:22] open(): File system is not mounted BEGIN... MIDI done MIDI done After this fix there is sound and no error on the serial monitor. Then change is similar to the code in https://github.com/earlephilhower/ESP8266Audio/blob/master/examples/PlayMP3FromSPIFFS/PlayMP3FromSPIFFS.ino --- examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino index dcfa8f98..da9f685c 100644 --- a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino +++ b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino @@ -25,6 +25,7 @@ void setup() WiFi.mode(WIFI_OFF); Serial.begin(115200); + SPIFFS.begin(); Serial.println("Starting up...\n"); audioLogger = &Serial; From 86a1818da5ae8a9231388b9556ab9d8392bb3c98 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 28 Nov 2021 10:52:33 -0800 Subject: [PATCH 072/150] Add codespell to CI checks (#450) --- .github/workflows/pr-or-master-push.yml | 17 +++++++++++++++++ README.md | 2 +- .../PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino | 2 +- .../PlayWAVFromFunction/PlayWAVFromFunction.ino | 2 +- .../StreamMP3FromHTTPToSPDIF.ino | 2 +- src/AudioFileSourceFunction.cpp | 2 +- src/AudioFileSourceFunction.h | 2 +- src/AudioGeneratorMIDI.cpp | 2 +- src/AudioOutputSPDIF.cpp | 2 +- src/AudioOutputSPDIF.h | 2 +- src/driver/SinglePinI2SDriver.cpp | 8 ++++---- src/libflac/stream_decoder.c | 12 ++++++------ src/libhelix-mp3/RPSL.txt | 2 +- src/libhelix-mp3/assembly.h | 4 ++-- src/libhelix-mp3/scalfact.c | 2 +- src/libogg/README.md | 4 ++-- src/libtinysoundfont/README.ESP8266 | 2 +- src/libtinysoundfont/tsf.h | 4 ++-- src/opusfile/opusfile.h | 4 ++-- tests/common.sh | 2 +- 20 files changed, 48 insertions(+), 31 deletions(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index 52bf8a9e..fcbd0952 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -93,3 +93,20 @@ jobs: - uses: arduino/arduino-lint-action@v1 with: library-manager: 'update' + +# Validate orthography + code-spell: + name: Check spelling + runs-on: ubuntu-latest + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - name: Run codespell + uses: codespell-project/actions-codespell@master + with: + skip: ./src/libmad,./src/libhelix-aac,./src/libopus + ignore_words_list: ESP8266,esp8266,esp,dout,DOUT,ser,ans,inout,numer,hist diff --git a/README.md b/README.md index 6ff31be9..3fd7101a 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,7 @@ AudioFileSourcePROGMEM: Reads a file from a PROGMEM array. Under UNIX you can AudioFileSourceHTTPStream: Simple implementation of a streaming HTTP reader for ShoutCast-type MP3 streaming. Not yet resilient, and at 44.1khz 128bit stutters due to CPU limitations, but it works more or less. ## AudioFileSourceBuffer - Double buffering, useful for HTTP streams -AudioFileSourceBuffer is an input source that simpy adds an additional RAM buffer of the output of any other AudioFileSource. This is particularly useful for web streaming where you need to have 1-2 packets in memory to ensure hiccup-free playback. +AudioFileSourceBuffer is an input source that simply adds an additional RAM buffer of the output of any other AudioFileSource. This is particularly useful for web streaming where you need to have 1-2 packets in memory to ensure hiccup-free playback. Create your standard input file source, create the buffer with the original source as its input, and pass this buffer object to the generator. ```cpp diff --git a/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino b/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino index 3c127883..50b0ade3 100644 --- a/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino +++ b/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino @@ -8,7 +8,7 @@ // Espressif Audio Development Framework at: // https://docs.espressif.com/projects/esp-adf/en/latest/design-guide/audio-samples.html // -// On ESP8266 you might need to reencode FLAC files with max '-2' compression level +// On ESP8266 you might need to re-encode FLAC files with max '-2' compression level // (i.e. 1152 maximum block size) or you will run out of memory. FLAC files will be // slightly bigger but you don't loose audio quality with reencoding (lossles codec). diff --git a/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino b/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino index fe0cc896..9af90e0d 100644 --- a/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino +++ b/examples/PlayWAVFromFunction/PlayWAVFromFunction.ino @@ -44,7 +44,7 @@ void setup() { // param : float (current time [sec] of the song) // return : float (the amplitude of sound which varies from -1.f to +1.f) // - // sound function can be registerd only one or the same number with channels + // sound function can be registered only one or the same number with channels // if the channels > 1 && the number of function == 1, // same function are used to generate the sound in every channel // diff --git a/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino b/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino index b082f7a1..ef542908 100644 --- a/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino +++ b/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino @@ -104,7 +104,7 @@ void setup() // Commented out for performance issues with high rate MP3 stream //buff->RegisterStatusCB(StatusCallback, (void*)"buffer"); - // Set SPDIF outout + // Set SPDIF output out = new AudioOutputSPDIF(); mp3 = new AudioGeneratorMP3(); diff --git a/src/AudioFileSourceFunction.cpp b/src/AudioFileSourceFunction.cpp index 9e86eff2..885defa4 100644 --- a/src/AudioFileSourceFunction.cpp +++ b/src/AudioFileSourceFunction.cpp @@ -1,6 +1,6 @@ /* AudioFileSourceFunction - Audio ouptut generator which can generate WAV file data from function + Audio output generator which can generate WAV file data from function Copyright (C) 2021 Hideaki Tai diff --git a/src/AudioFileSourceFunction.h b/src/AudioFileSourceFunction.h index 6c41229a..94b88d6f 100644 --- a/src/AudioFileSourceFunction.h +++ b/src/AudioFileSourceFunction.h @@ -1,6 +1,6 @@ /* AudioFileSourceFunction - Audio ouptut generator which can generate WAV file data from function + Audio output generator which can generate WAV file data from function Copyright (C) 2021 Hideaki Tai diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index a76e757c..5f1c5f3a 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -364,7 +364,7 @@ void AudioGeneratorMIDI::PrepareMIDI(AudioFileSource *src) int AudioGeneratorMIDI::PlayMIDI() { /* Continue processing all tracks, in an order based on the simulated time. - This is not unlike multiway merging used for tape sorting algoritms in the 50's! */ + This is not unlike multiway merging used for tape sorting algorithms in the 50's! */ do { /* while there are still track notes to process */ static struct track_status *trk; diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index 53483d4a..c1370d76 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -3,7 +3,7 @@ S/PDIF output via I2S - Needs transciever from CMOS level to either optical or coaxial interface + Needs transceiver from CMOS level to either optical or coaxial interface See: https://www.epanorama.net/documents/audio/spdif.html Original idea and sources: diff --git a/src/AudioOutputSPDIF.h b/src/AudioOutputSPDIF.h index 5da160b3..7cb194db 100644 --- a/src/AudioOutputSPDIF.h +++ b/src/AudioOutputSPDIF.h @@ -3,7 +3,7 @@ S/PDIF output via I2S - Needs transciever from CMOS level to either optical or coaxial interface + Needs transceiver from CMOS level to either optical or coaxial interface See: https://www.epanorama.net/documents/audio/spdif.html Original idea and sources: diff --git a/src/driver/SinglePinI2SDriver.cpp b/src/driver/SinglePinI2SDriver.cpp index 3d08efaf..c2d2280c 100644 --- a/src/driver/SinglePinI2SDriver.cpp +++ b/src/driver/SinglePinI2SDriver.cpp @@ -3,7 +3,7 @@ ESP8266Audio I2S Minimal driver Most of this code is taken and reworked from ESP8266 Arduino core, - which itsef is reworked from Espessif's I2S examples. + which itself is reworked from Espessif's I2S examples. Original code is licensed under LGPL 2.1 or above Reasons for rewrite: @@ -196,7 +196,7 @@ void SinglePinI2SDriver::setDividers(uint8_t div1, uint8_t div2) // Ensure dividers fit in bit fields div1 &= I2SBDM; div2 &= I2SCDM; - // trans master(active low), recv master(active_low), !bits mod(==16 bits/chanel), clear clock dividers + // trans master(active low), recv master(active_low), !bits mod(==16 bits/channel), clear clock dividers I2SC &= ~(I2STSM | I2SRSM | (I2SBMM << I2SBM) | (I2SBDM << I2SBD) | (I2SCDM << I2SCD)); // I2SRF = Send/recv right channel first // I2SMR = MSB recv/xmit first @@ -249,7 +249,7 @@ void SinglePinI2SDriver::startI2S() I2SFC |= I2SDE; // Enable DMA // I2STXCMM, I2SRXCMM=0 => Dual channel mode, RX/TX CHAN_MOD=0 I2SCC &= ~((I2STXCMM << I2STXCM) | (I2SRXCMM << I2SRXCM)); - // Set dividers to something resonable + // Set dividers to something reasonable currentRate = 0; setRate(44100); // Start I2S peripheral @@ -280,4 +280,4 @@ int SinglePinI2SDriver::getUnderflowCount() // Global instance SinglePinI2SDriver I2SDriver; -#endif // defined(ESP8266) \ No newline at end of file +#endif // defined(ESP8266) diff --git a/src/libflac/stream_decoder.c b/src/libflac/stream_decoder.c index ec172fe8..20ae399f 100644 --- a/src/libflac/stream_decoder.c +++ b/src/libflac/stream_decoder.c @@ -2199,14 +2199,14 @@ FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) * Three kinds of things can go wrong when reading the frame header: * 1) We may have sync'ed incorrectly and not landed on a frame header. * If we don't find a sync code, it can end up looking like we read - * a valid but unparseable header, until getting to the frame header + * a valid but unparsable header, until getting to the frame header * CRC. Even then we could get a false positive on the CRC. - * 2) We may have sync'ed correctly but on an unparseable frame (from a + * 2) We may have sync'ed correctly but on an unparsable frame (from a * future encoder). - * 3) We may be on a damaged frame which appears valid but unparseable. + * 3) We may be on a damaged frame which appears valid but unparsable. * * For all these reasons, we try and read a complete frame header as - * long as it seems valid, even if unparseable, up until the frame + * long as it seems valid, even if unparsable, up until the frame * header CRC. */ @@ -2839,7 +2839,7 @@ FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data) * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its * unparseable_frame_count. But there is a remote possibility * that it is properly synced at such a "future-codec frame", - * so to make sure, we wait to see many "unparseable" errors in + * so to make sure, we wait to see many "unparsable" errors in * a row before bailing out. */ if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) { @@ -3146,7 +3146,7 @@ FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 s return false; } /* Now we need to get a frame. First we need to reset our - * unparseable_frame_count; if we get too many unparseable + * unparseable_frame_count; if we get too many unparsable * frames in a row, the read callback will return * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing * FLAC__stream_decoder_process_single() to return false. diff --git a/src/libhelix-mp3/RPSL.txt b/src/libhelix-mp3/RPSL.txt index d040a452..94b44586 100644 --- a/src/libhelix-mp3/RPSL.txt +++ b/src/libhelix-mp3/RPSL.txt @@ -201,7 +201,7 @@ and 3, above. 4.2 Compatible Source Licenses. Software modules that have been independently developed without any use of Covered Code and which contain no portion of the Covered Code, Modifications or other Derivative Works, but are used or combined -in any way wtih the Covered Code or any Derivative Work to form a larger +in any way with the Covered Code or any Derivative Work to form a larger Derivative Work, are exempt from the conditions described in Section 4.1 but only to the extent that: the software module, including any software that is linked to, integrated with, or part of the same applications as, the software diff --git a/src/libhelix-mp3/assembly.h b/src/libhelix-mp3/assembly.h index b9e46c52..5ad0f30b 100644 --- a/src/libhelix-mp3/assembly.h +++ b/src/libhelix-mp3/assembly.h @@ -40,7 +40,7 @@ * * assembly.h - assembly language functions and prototypes for supported platforms * - * - inline rountines with access to 64-bit multiply results + * - inline routines with access to 64-bit multiply results * - x86 (_WIN32) and ARM (ARM_ADS, _WIN32_WCE) versions included * - some inline functions are mix of asm and C for speed * - some functions are in native asm files, so only the prototype is given here @@ -241,7 +241,7 @@ static __inline int MULSHIFT32(int x, int y) static __inline int FASTABS(int x) { - int t=0; /*Really is not necessary to initialiaze only to avoid warning*/ + int t=0; /*Really is not necessary to initialize only to avoid warning*/ __asm { eor t, x, x, asr #31 diff --git a/src/libhelix-mp3/scalfact.c b/src/libhelix-mp3/scalfact.c index 4937e453..d274b361 100644 --- a/src/libhelix-mp3/scalfact.c +++ b/src/libhelix-mp3/scalfact.c @@ -74,7 +74,7 @@ static const char SFLenTab[16][2] = { * Return: none * * Notes: set order of short blocks to s[band][window] instead of s[window][band] - * so that we index through consectutive memory locations when unpacking + * so that we index through consecutive memory locations when unpacking * (make sure dequantizer follows same convention) * Illegal Intensity Position = 7 (always) for MPEG1 scale factors **************************************************************************************/ diff --git a/src/libogg/README.md b/src/libogg/README.md index 63545e28..c3be0146 100644 --- a/src/libogg/README.md +++ b/src/libogg/README.md @@ -7,7 +7,7 @@ Ogg project codecs use the Ogg bitstream format to arrange the raw, compressed bitstream into a more robust, useful form. For example, the Ogg bitstream makes seeking, time stamping and error recovery -possible, as well as mixing several sepearate, concurrent media +possible, as well as mixing several separate, concurrent media streams into a single physical bitstream. ## What's here ## @@ -18,7 +18,7 @@ use with Ogg bitstreams. Directory: -- `src` The source for libogg, a BSD-license inplementation of the public domain Ogg bitstream format +- `src` The source for libogg, a BSD-license implementation of the public domain Ogg bitstream format - `include` Library API headers diff --git a/src/libtinysoundfont/README.ESP8266 b/src/libtinysoundfont/README.ESP8266 index e88104df..1009f36f 100644 --- a/src/libtinysoundfont/README.ESP8266 +++ b/src/libtinysoundfont/README.ESP8266 @@ -28,7 +28,7 @@ Even with the caching, it was found that SPIFFS, while having great functionality, was horrbly slow. So I wrote a new "faster" ROM filesystem called, surprisingly, FastROMFilesystem. https://github.com/earlephilhower/ESP8266FastROMFS -If you are getting choppy playback, try this new filesytem or using a SD +If you are getting choppy playback, try this new filesystem or using a SD card (not tested by myself, but it'd be hard top be slower than SPIFFS). Simply going from SPIFFS to FastROMFilesystem took my testing of FURELISE.MID and 1MGM.SF2 from 0.5x realtime to 2.5x (i.e. from unusable diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index 4ac232d1..bdaadae5 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -104,7 +104,7 @@ TSFDEF tsf* tsf_load(struct tsf_stream* stream); // Free the memory related to this tsf instance TSFDEF void tsf_close(tsf* f); -// Stop all playing notes immediatly and reset all channel parameters +// Stop all playing notes immediately and reset all channel parameters TSFDEF void tsf_reset(tsf* f); // Returns the preset index from a bank and preset number, or -1 if it does not exist in the loaded SoundFont @@ -201,7 +201,7 @@ TSFDEF void tsf_channel_set_tuning(tsf* f, int channel, float tuning); TSFDEF void tsf_channel_note_on(tsf* f, int channel, int key, float vel); TSFDEF void tsf_channel_note_off(tsf* f, int channel, int key); TSFDEF void tsf_channel_note_off_all(tsf* f, int channel); //end with sustain and release -TSFDEF void tsf_channel_sounds_off_all(tsf* f, int channel); //end immediatly +TSFDEF void tsf_channel_sounds_off_all(tsf* f, int channel); //end immediately // Apply a MIDI control change to the channel (not all controllers are supported!) TSFDEF void tsf_channel_midi_control(tsf* f, int channel, int controller, int control_value); diff --git a/src/opusfile/opusfile.h b/src/opusfile/opusfile.h index 7a645724..11cc07a1 100644 --- a/src/opusfile/opusfile.h +++ b/src/opusfile/opusfile.h @@ -729,7 +729,7 @@ struct OpusServerInfo{ /**The software used by the origin server (Server). This is NULL if there was no Server header.*/ char *server; - /**The media type of the entity sent to the recepient (Content-Type). + /**The media type of the entity sent to the recipient (Content-Type). This is NULL if there was no Content-Type header.*/ char *content_type; @@ -1436,7 +1436,7 @@ void op_free(OggOpusFile *_of); Some of these functions may be used successfully on the partially open streams returned by op_test_callbacks() or one of the associated convenience functions. - Their documention will indicate so explicitly.*/ + Their documentation will indicate so explicitly.*/ /*@{*/ /**Returns whether or not the stream being read is seekable. diff --git a/tests/common.sh b/tests/common.sh index cabad512..25c05cd6 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -58,7 +58,7 @@ function build_sketches() local sketchdirname=$(basename $sketchdir) local sketchname=$(basename $sketch) if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then - echo "Skipping $sketch, beacause it is not the main sketch file"; + echo "Skipping $sketch, because it is not the main sketch file"; continue fi; if [[ -f "$sketchdir/.test.skip" ]]; then From e254ad954310a76389b53c504648ee923eab6e7b Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 28 Nov 2021 16:20:05 -0800 Subject: [PATCH 073/150] Add MOD test, update DIVIDER name (#451) Fixes #449 --- src/AudioGeneratorMOD.cpp | 10 +++++----- src/AudioGeneratorMOD.h | 4 ++-- src/AudioOutputSTDIO.cpp | 5 +++++ tests/host/Makefile | 10 ++++++++-- tests/host/mod.cpp | 26 ++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 9 deletions(-) create mode 100644 tests/host/mod.cpp diff --git a/src/AudioGeneratorMOD.cpp b/src/AudioGeneratorMOD.cpp index f42154f8..b47b2839 100644 --- a/src/AudioGeneratorMOD.cpp +++ b/src/AudioGeneratorMOD.cpp @@ -124,7 +124,7 @@ bool AudioGeneratorMOD::begin(AudioFileSource *source, AudioOutput *out) UpdateAmiga(); for (int i = 0; i < CHANNELS; i++) { - FatBuffer.channels[i] = reinterpret_cast(malloc(fatBufferSize)); + FatBuffer.channels[i] = reinterpret_cast(calloc(fatBufferSize, 1)); if (!FatBuffer.channels[i]) { stop(); return false; @@ -565,7 +565,7 @@ bool AudioGeneratorMOD::ProcessRow() Mixer.channelFrequency[channel] = Player.amiga / Player.lastAmigaPeriod[channel]; if (note != NONOTE) - Mixer.channelSampleOffset[channel] = sampleOffset << DIVIDER; + Mixer.channelSampleOffset[channel] = sampleOffset << FIXED_DIVIDER; if (sampleNumber) Mixer.channelSampleNumber[channel] = Player.lastSampleNumber[channel]; @@ -757,12 +757,12 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) if (!Mixer.channelVolume[channel]) continue; samplePointer = Mixer.sampleBegin[Mixer.channelSampleNumber[channel]] + - (Mixer.channelSampleOffset[channel] >> DIVIDER); + (Mixer.channelSampleOffset[channel] >> FIXED_DIVIDER); if (Mixer.sampleLoopLength[Mixer.channelSampleNumber[channel]]) { if (samplePointer >= Mixer.sampleLoopEnd[Mixer.channelSampleNumber[channel]]) { - Mixer.channelSampleOffset[channel] -= Mixer.sampleLoopLength[Mixer.channelSampleNumber[channel]] << DIVIDER; + Mixer.channelSampleOffset[channel] -= Mixer.sampleLoopLength[Mixer.channelSampleNumber[channel]] << FIXED_DIVIDER; samplePointer -= Mixer.sampleLoopLength[Mixer.channelSampleNumber[channel]]; } @@ -801,7 +801,7 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) out = current; // Integer linear interpolation - out += (next - current) * (Mixer.channelSampleOffset[channel] & ((1 << DIVIDER) - 1)) >> DIVIDER; + out += (next - current) * (Mixer.channelSampleOffset[channel] & ((1 << FIXED_DIVIDER) - 1)) >> FIXED_DIVIDER; // Upscale to BITDEPTH out <<= BITDEPTH - 8; diff --git a/src/AudioGeneratorMOD.h b/src/AudioGeneratorMOD.h index 87fac18e..06003775 100644 --- a/src/AudioGeneratorMOD.h +++ b/src/AudioGeneratorMOD.h @@ -56,14 +56,14 @@ class AudioGeneratorMOD : public AudioGenerator enum {BITDEPTH = 15}; int sampleRate; int fatBufferSize; //(6*1024) // File system buffers per-CHANNEL (i.e. total mem required is 4 * FATBUFFERSIZE) - enum {DIVIDER = 10}; // Fixed-point mantissa used for integer arithmetic + enum {FIXED_DIVIDER = 10}; // Fixed-point mantissa used for integer arithmetic int stereoSeparation; //STEREOSEPARATION = 32; // 0 (max) to 64 (mono) bool usePAL; // Hz = 7093789 / (amigaPeriod * 2) for PAL // Hz = 7159091 / (amigaPeriod * 2) for NTSC int AMIGA; - void UpdateAmiga() { AMIGA = ((usePAL?7159091:7093789) / 2 / sampleRate << DIVIDER); } + void UpdateAmiga() { AMIGA = ((usePAL?7159091:7093789) / 2 / sampleRate << FIXED_DIVIDER); } enum {ROWS = 64, SAMPLES = 31, CHANNELS = 4, NONOTE = 0xFFFF, NONOTE8 = 0xff }; diff --git a/src/AudioOutputSTDIO.cpp b/src/AudioOutputSTDIO.cpp index 33bbd34f..f9032bb1 100644 --- a/src/AudioOutputSTDIO.cpp +++ b/src/AudioOutputSTDIO.cpp @@ -54,6 +54,11 @@ bool AudioOutputSTDIO::begin() bool AudioOutputSTDIO::ConsumeSample(int16_t sample[2]) { + static int avail = 100; + if (!(--avail)) { + avail = 100; + return false; + } for (int i=0; i +#include "AudioFileSourcePROGMEM.h" +#include "AudioOutputSTDIO.h" +#include "AudioGeneratorMOD.h" + +#include "../../examples/PlayMODFromPROGMEMToDAC/enigma.h" + +int main(int argc, char **argv) +{ + (void) argc; + (void) argv; + + AudioFileSourcePROGMEM *file = new AudioFileSourcePROGMEM(enigma_mod, sizeof(enigma_mod)); + AudioOutputSTDIO *out = new AudioOutputSTDIO(); + out->SetFilename("mod.wav"); + AudioGeneratorMOD *mod = new AudioGeneratorMOD(); + + mod->begin(file, out); + // The MOD plays forever, so only run for ~30 seconds worth + for (int i=0; i<10000; i++) mod->loop(); + mod->stop(); + + delete out; + delete mod; + delete file; +} From 617b06d09a6b4bda8ffe9d9c206fb7f041041688 Mon Sep 17 00:00:00 2001 From: Jesper Noer Date: Mon, 29 Nov 2021 15:11:57 -0500 Subject: [PATCH 074/150] Fixing I2S includes to work with ESP8266 Arduino version < 3.0.0 (#453) --- src/AudioOutputI2S.cpp | 4 +++- src/AudioOutputI2SNoDAC.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 5bc6cb00..1483cb32 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -21,8 +21,10 @@ #include #ifdef ESP32 #include "driver/i2s.h" -#elif defined(ARDUINO_ARCH_RP2040) || defined(ESP8266) +#elif defined(ARDUINO_ARCH_RP2040) || ARDUINO_ESP8266_MAJOR >= 3 #include +#elif ARDUINO_ESP8266_MAJOR < 3 + #include #endif #include "AudioOutputI2S.h" diff --git a/src/AudioOutputI2SNoDAC.cpp b/src/AudioOutputI2SNoDAC.cpp index 501634e6..976d73c7 100644 --- a/src/AudioOutputI2SNoDAC.cpp +++ b/src/AudioOutputI2SNoDAC.cpp @@ -21,8 +21,10 @@ #include #ifdef ESP32 #include "driver/i2s.h" -#elif defined(ARDUINO_ARCH_RP2040) || defined(ESP8266) +#elif defined(ARDUINO_ARCH_RP2040) || ARDUINO_ESP8266_MAJOR >= 3 #include +#elif ARDUINO_ESP8266_MAJOR < 3 + #include #endif #include "AudioOutputI2SNoDAC.h" From 2c1aeba4abc7c1b3aa7d2a0b1f5c78bc75af058a Mon Sep 17 00:00:00 2001 From: FedericoBusero <35894905+FedericoBusero@users.noreply.github.com> Date: Tue, 30 Nov 2021 21:25:30 +0100 Subject: [PATCH 075/150] ESP32-C3 Support (#454) * ESP32-C3 has no ULP coprocessor Only the ESP32, ESP32-S2 and ESP32-S3 chips have an ULP coprocessor, ESP32-C3 doesn't have it. So exclude this code from compiling, as it cannot compile in the C3 environment. * uint32_t and size_t is not the same on RISC-V This change is necessary to be able to compile it on ESP32-C3 * uint32_t and size_t is not the same on RISC-V The change is necessary to compile it on ESP32-C3 * ESP32-C3: I2S_MODE_DAC_BUILT_IN / I2S_MODE_PDM not available On some ESP32 chips (e.g. ESP32-C3), builtin DAC is not possible as it lacks the hardware module. In order to be able to compile the library on ESP32-C3 the defines cannot be used. --- src/AudioFileSourceSPIRAMBuffer.cpp | 2 +- src/AudioOutputI2S.cpp | 14 +++++++++++++- src/AudioOutputSPDIF.cpp | 2 +- src/AudioOutputULP.cpp | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/AudioFileSourceSPIRAMBuffer.cpp b/src/AudioFileSourceSPIRAMBuffer.cpp index 2c9eb3b9..475afa4d 100644 --- a/src/AudioFileSourceSPIRAMBuffer.cpp +++ b/src/AudioFileSourceSPIRAMBuffer.cpp @@ -105,7 +105,7 @@ uint32_t AudioFileSourceSPIRAMBuffer::read(void *data, uint32_t len) } // Read up to the entire buffer from RAM - uint32_t toReadFromBuffer = std::min(len, writePtr - readPtr); + uint32_t toReadFromBuffer = std::min(len, (uint32_t)(writePtr - readPtr)); uint8_t *ptr = reinterpret_cast(data); if (toReadFromBuffer > 0) { #ifdef FAKERAM diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 1483cb32..760ff1a2 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -168,11 +168,19 @@ bool AudioOutputI2S::begin(bool txDAC) i2s_mode_t mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); if (output_mode == INTERNAL_DAC) { +#ifdef I2S_MODE_DAC_BUILT_IN mode = (i2s_mode_t)(mode | I2S_MODE_DAC_BUILT_IN); +#else + return false; +#endif } - else if (output_mode == INTERNAL_PDM) + if (output_mode == INTERNAL_PDM) { +#ifdef I2S_MODE_PDM mode = (i2s_mode_t)(mode | I2S_MODE_PDM); +#else + return false; +#endif } i2s_comm_format_t comm_fmt = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); @@ -199,8 +207,12 @@ bool AudioOutputI2S::begin(bool txDAC) } if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) { +#ifdef I2S_DAC_CHANNEL_BOTH_EN i2s_set_pin((i2s_port_t)portNo, NULL); i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); +#else + return false; +#endif } else { diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index c1370d76..59923f99 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -265,7 +265,7 @@ bool AudioOutputSPDIF::ConsumeSample(int16_t sample[2]) #if defined(ESP32) // Assume DMA buffers are multiples of 16 bytes. Either we write all bytes or none. - uint32_t bytes_written; + size_t bytes_written; esp_err_t ret = i2s_write((i2s_port_t)portNo, (const char*)&buf, 8 * channels, &bytes_written, 0); // If we didn't write all bytes, return false early and do not increment frame_num if ((ret != ESP_OK) || (bytes_written != (8 * channels))) return false; diff --git a/src/AudioOutputULP.cpp b/src/AudioOutputULP.cpp index 63177e3a..d8f4e027 100644 --- a/src/AudioOutputULP.cpp +++ b/src/AudioOutputULP.cpp @@ -18,7 +18,7 @@ along with this program. If not, see . */ -#ifdef ESP32 +#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #include "AudioOutputULP.h" #include From de30f618997ecd47d142b78e39c59c97607250b8 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 30 Nov 2021 12:28:02 -0800 Subject: [PATCH 076/150] Update to Rel 1.9.4 for ESP-C3 support (#455) --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index bab90529..6fe48d26 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.3", + "version": "1.9.4", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ diff --git a/library.properties b/library.properties index 1f130374..06ce62e6 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.3 +version=1.9.4 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From 0d132c1391ae88931c5d3bdd7f33eb2261240393 Mon Sep 17 00:00:00 2001 From: Wojtek Kaniewski Date: Sat, 4 Dec 2021 03:47:01 +0100 Subject: [PATCH 077/150] Support LSB Justified DACs (e.g. PT8211) (#459) --- src/AudioOutputI2S.cpp | 19 +++++++++++++++++-- src/AudioOutputI2S.h | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 760ff1a2..01a8f92a 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -42,6 +42,7 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int //set defaults mono = false; + lsb_justified = false; bps = 16; channels = 2; hertz = 44100; @@ -148,6 +149,12 @@ bool AudioOutputI2S::SetOutputModeMono(bool mono) return true; } +bool AudioOutputI2S::SetLsbJustified(bool lsbJustified) +{ + this->lsb_justified = lsbJustified; + return true; +} + bool AudioOutputI2S::begin(bool txDAC) { #ifdef ESP32 @@ -183,10 +190,18 @@ bool AudioOutputI2S::begin(bool txDAC) #endif } - i2s_comm_format_t comm_fmt = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); + i2s_comm_format_t comm_fmt; if (output_mode == INTERNAL_DAC) { - comm_fmt = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB; + comm_fmt = (i2s_comm_format_t) I2S_COMM_FORMAT_I2S_MSB; + } + else if (lsb_justified) + { + comm_fmt = (i2s_comm_format_t) (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB); + } + else + { + comm_fmt = (i2s_comm_format_t) (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); } i2s_config_t i2s_config_dac = { diff --git a/src/AudioOutputI2S.h b/src/AudioOutputI2S.h index 90370dc2..b3f621d2 100644 --- a/src/AudioOutputI2S.h +++ b/src/AudioOutputI2S.h @@ -44,6 +44,7 @@ class AudioOutputI2S : public AudioOutput bool begin(bool txDAC); bool SetOutputModeMono(bool mono); // Force mono output no matter the input + bool SetLsbJustified(bool lsbJustified); // Allow supporting non-I2S chips, e.g. PT8211 protected: bool SetPinout(); @@ -51,6 +52,7 @@ class AudioOutputI2S : public AudioOutput uint8_t portNo; int output_mode; bool mono; + int lsb_justified; bool i2sOn; int dma_buf_count; int use_apll; From 933439fa3f8f35a8e166bf2e81e27bf1e2c99415 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 17 Dec 2021 11:42:16 -0800 Subject: [PATCH 078/150] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3fd7101a..0b3ab8d5 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ A neat MQTT-driven ESP8266 light-and-sound device (alarm? toy? who can say!) was A very interesting "linear clock" with a stepper motor, NTP time keeping, and configurable recorded chimes with schematics, 3D printer plans, and source code, is now available https://janderogee.com/projects/linear_clock/linear_clock.htm +Source and instructions for a gorgeous wooden MP3-playing clock, FM radio and a walkie-talkie using the ESP8266 and AVR microcontrollers is available https://github.com/zduka/mp3-player + ## Prerequisites First, make sure you are running the 2.6.3/later or GIT head version of the Arduino libraries for ESP8266, or the latest ESP32 SDK from Espressif. From 7ac86f015f4b3ed9c8d683186637e340eb546150 Mon Sep 17 00:00:00 2001 From: FedericoBusero <35894905+FedericoBusero@users.noreply.github.com> Date: Sat, 18 Dec 2021 04:31:49 +0100 Subject: [PATCH 079/150] I2S Fix Builtin DAC&PDM on ESP32 & compiling warning ESP32-C3 (#461) * Update AudioOutputI2S.cpp * Update AudioOutputSPDIF.cpp * Fix PDM & DAC mode ESP32 The code for enabling compatibility with ESP32C3 had broken DAC builtin and PDM mode on ESP32. This should fix it again * Update AudioOutputI2S.cpp --- src/AudioOutputI2S.cpp | 16 ++++++++++++---- src/AudioOutputSPDIF.cpp | 6 +++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 01a8f92a..98346f07 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -175,15 +175,15 @@ bool AudioOutputI2S::begin(bool txDAC) i2s_mode_t mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX); if (output_mode == INTERNAL_DAC) { -#ifdef I2S_MODE_DAC_BUILT_IN +#if CONFIG_IDF_TARGET_ESP32 mode = (i2s_mode_t)(mode | I2S_MODE_DAC_BUILT_IN); #else return false; #endif } - if (output_mode == INTERNAL_PDM) + else if (output_mode == INTERNAL_PDM) { -#ifdef I2S_MODE_PDM +#if CONFIG_IDF_TARGET_ESP32 mode = (i2s_mode_t)(mode | I2S_MODE_PDM); #else return false; @@ -193,7 +193,11 @@ bool AudioOutputI2S::begin(bool txDAC) i2s_comm_format_t comm_fmt; if (output_mode == INTERNAL_DAC) { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) + comm_fmt = (i2s_comm_format_t) I2S_COMM_FORMAT_STAND_MSB; +#else comm_fmt = (i2s_comm_format_t) I2S_COMM_FORMAT_I2S_MSB; +#endif } else if (lsb_justified) { @@ -201,7 +205,11 @@ bool AudioOutputI2S::begin(bool txDAC) } else { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) + comm_fmt = (i2s_comm_format_t) (I2S_COMM_FORMAT_STAND_I2S); +#else comm_fmt = (i2s_comm_format_t) (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB); +#endif } i2s_config_t i2s_config_dac = { @@ -222,7 +230,7 @@ bool AudioOutputI2S::begin(bool txDAC) } if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) { -#ifdef I2S_DAC_CHANNEL_BOTH_EN +#if CONFIG_IDF_TARGET_ESP32 i2s_set_pin((i2s_port_t)portNo, NULL); i2s_set_dac_mode(I2S_DAC_CHANNEL_BOTH_EN); #else diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index 59923f99..6e1cf197 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -94,7 +94,11 @@ AudioOutputSPDIF::AudioOutputSPDIF(int dout_pin, int port, int dma_buf_count) .sample_rate = 88200, // 2 x sampling_rate .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, // 32bit words .channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, // Right than left - .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_STAND_I2S), +#else + .communication_format = (i2s_comm_format_t)(I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB), +#endif .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // lowest interrupt priority .dma_buf_count = dma_buf_count, .dma_buf_len = DMA_BUF_SIZE_DEFAULT, // bigger buffers, reduces interrupts From faa8b094c9c8f8ed15cdf93d5874fcca802de01d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 17 Dec 2021 19:32:29 -0800 Subject: [PATCH 080/150] Update library.json --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index 6fe48d26..ddbb6d63 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.4", + "version": "1.9.5", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ From dca33f80c7d7b1c847402247e2263a832cc08579 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Fri, 17 Dec 2021 19:32:45 -0800 Subject: [PATCH 081/150] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index 06ce62e6..85a99c0e 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.4 +version=1.9.5 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From 29e5e016af57bcf5af77b0a958ceed81fcf2f42d Mon Sep 17 00:00:00 2001 From: FedericoBusero <35894905+FedericoBusero@users.noreply.github.com> Date: Sun, 19 Dec 2021 23:02:45 +0100 Subject: [PATCH 082/150] AAC playback on RISC-V processor (ESP32C3) (#466) The library produces white noise when playing AAC streams because of a little/big endian issue. --- src/libhelix-aac/assembly.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libhelix-aac/assembly.h b/src/libhelix-aac/assembly.h index 595a8fc9..0c17f0c4 100644 --- a/src/libhelix-aac/assembly.h +++ b/src/libhelix-aac/assembly.h @@ -558,7 +558,7 @@ static __inline int CLZ(int x) typedef union _U64 { Word64 w64; struct { -#ifdef __XTENSA__ +#if defined(__XTENSA__) || defined (__riscv) unsigned int lo32; signed int hi32; #else From 4971e5ce6847996b487e76866e1078b2686a62de Mon Sep 17 00:00:00 2001 From: FedericoBusero <35894905+FedericoBusero@users.noreply.github.com> Date: Sun, 26 Dec 2021 18:29:09 +0100 Subject: [PATCH 083/150] Increase I2S buffer size (#472) Increase I2S buffer size from 64 samples/ block to 128 samples/block. Thus fixes sound artifacts described in issue https://github.com/earlephilhower/ESP8266Audio/issues/442 Fixes #442 --- src/AudioOutputI2S.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 98346f07..0eb3c0da 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -220,7 +220,7 @@ bool AudioOutputI2S::begin(bool txDAC) .communication_format = comm_fmt, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // lowest interrupt priority .dma_buf_count = dma_buf_count, - .dma_buf_len = 64, + .dma_buf_len = 128, .use_apll = use_apll // Use audio PLL }; audioLogger->printf("+%d %p\n", portNo, &i2s_config_dac); @@ -324,7 +324,7 @@ void AudioOutputI2S::flush() { #ifdef ESP32 // makes sure that all stored DMA samples are consumed / played - int buffersize = 64 * this->dma_buf_count; + int buffersize = 128 * this->dma_buf_count; int16_t samples[2] = {0x0, 0x0}; for (int i = 0; i < buffersize; i++) { From fe7a1f7951236d660a11167a35e05ae495e60b04 Mon Sep 17 00:00:00 2001 From: FedericoBusero <35894905+FedericoBusero@users.noreply.github.com> Date: Mon, 27 Dec 2021 17:12:33 +0100 Subject: [PATCH 084/150] Fix RTTTL stop on ESP32 (#473) Fixes #327 Fixes #471 --- src/AudioGeneratorRTTTL.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/AudioGeneratorRTTTL.cpp b/src/AudioGeneratorRTTTL.cpp index 87825bd9..5eb18486 100644 --- a/src/AudioGeneratorRTTTL.cpp +++ b/src/AudioGeneratorRTTTL.cpp @@ -41,7 +41,10 @@ AudioGeneratorRTTTL::~AudioGeneratorRTTTL() bool AudioGeneratorRTTTL::stop() { - if (!running) return true; + if (!file || !output) + { + return false; + } running = false; output->stop(); return file->close(); From c55d240ade531898f8cb5f367f445db12472e51e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 5 Jan 2022 17:25:26 +0100 Subject: [PATCH 085/150] Fix for issue #474, and a few other bugs in MODGenerator (#478) Fixes #474 This bug was already present in stellaplayer. Obviously "effectNumber" must be checked, because "effectParameterX" just holds the "upper nibble" of effectParameter - do channel mixing in 32bit, to avoid noise from over/underflow - write audio output as "signed int" (not unsigned) - add int16 saturation check ("clipping") * avoid crash when MOD file has to many CHANNELS - avoid guru meditation, by logging an error and refusing playback in case MOD.numberOfChannels > CHANNELS --- src/AudioGeneratorMOD.cpp | 57 ++++++++++++++++++++++++++++----------- src/AudioOutputI2S.cpp | 2 +- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/AudioGeneratorMOD.cpp b/src/AudioGeneratorMOD.cpp index b47b2839..588ac51e 100644 --- a/src/AudioGeneratorMOD.cpp +++ b/src/AudioGeneratorMOD.cpp @@ -232,6 +232,11 @@ bool AudioGeneratorMOD::LoadHeader() Mod.numberOfChannels = (temp[0] - '0') * 10 + temp[1] - '0'; else Mod.numberOfChannels = 4; + + if (Mod.numberOfChannels > CHANNELS) { + audioLogger->printf("\nAudioGeneratorMOD::LoadHeader abort - too many channels (configured: %d, needed: %d)\n", CHANNELS, Mod.numberOfChannels); + return(false); + } return true; } @@ -417,7 +422,7 @@ bool AudioGeneratorMOD::ProcessRow() if (sampleNumber) { Player.lastSampleNumber[channel] = sampleNumber - 1; - if (!(effectParameter == 0xE && effectParameterX == NOTEDELAY)) + if (!(effectNumber == 0xE && effectParameterX == NOTEDELAY)) Player.volume[channel] = Mod.samples[Player.lastSampleNumber[channel]].volume; } @@ -735,13 +740,14 @@ bool AudioGeneratorMOD::RunPlayer() void AudioGeneratorMOD::GetSample(int16_t sample[2]) { - int16_t sumL; - int16_t sumR; + int32_t sumL; + int32_t sumR; uint8_t channel; uint32_t samplePointer; int8_t current; int8_t next; int16_t out; + int32_t out32; if (!running) return; @@ -779,7 +785,7 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) samplePointer >= FatBuffer.samplePointer[channel] + fatBufferSize - 1 || Mixer.channelSampleNumber[channel] != FatBuffer.channelSampleNumber[channel]) { - uint16_t toRead = Mixer.sampleEnd[Mixer.channelSampleNumber[channel]] - samplePointer + 1; + uint32_t toRead = Mixer.sampleEnd[Mixer.channelSampleNumber[channel]] - samplePointer + 1; if (toRead > fatBufferSize) toRead = fatBufferSize; if (!file->seek(samplePointer, SEEK_SET)) { @@ -800,27 +806,46 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) out = current; - // Integer linear interpolation + // Integer linear interpolation - only works correctly in 16bit out += (next - current) * (Mixer.channelSampleOffset[channel] & ((1 << FIXED_DIVIDER) - 1)) >> FIXED_DIVIDER; // Upscale to BITDEPTH - out <<= BITDEPTH - 8; + out32 = (int32_t)out << (BITDEPTH - 8); // Channel volume - out = out * Mixer.channelVolume[channel] >> 6; + out32 = out32 * Mixer.channelVolume[channel] >> 6; // Channel panning - sumL += out * min(128 - Mixer.channelPanning[channel], 64) >> 6; - sumR += out * min(Mixer.channelPanning[channel], 64) >> 6; + sumL += out32 * min(128 - Mixer.channelPanning[channel], 64) >> 6; + sumR += out32 * min(Mixer.channelPanning[channel], 64) >> 6; + } + + // Downscale to BITDEPTH - a bit faster because the compiler can replaced division by constants with proper "right shift" + correct handling of sign bit + if (Mod.numberOfChannels <= 4) { + // up to 4 channels + sumL /= 4; + sumR /= 4; + } else { + if (Mod.numberOfChannels <= 6) { + // 5 or 6 channels - pre-multiply be 1.5, then divide by 8 -> same as division by 6 + sumL = (sumL + (sumL/2)) / 8; + sumR = (sumR + (sumR/2)) / 8; + } else { + // 7,8, or more channels + sumL /= 8; + sumR /= 8; + } } - // Downscale to BITDEPTH - sumL /= Mod.numberOfChannels; - sumR /= Mod.numberOfChannels; - - // Fill the sound buffer with unsigned values - sample[AudioOutput::LEFTCHANNEL] = sumL + (1 << (BITDEPTH - 1)); - sample[AudioOutput::RIGHTCHANNEL] = sumR + (1 << (BITDEPTH - 1)); + // clip samples to 16bit (with saturation in case of overflow) + if(sumL <= INT16_MIN) sumL = INT16_MIN; + else if (sumL >= INT16_MAX) sumL = INT16_MAX; + if(sumR <= INT16_MIN) sumR = INT16_MIN; + else if (sumR >= INT16_MAX) sumR = INT16_MAX; + + // Fill the sound buffer with signed values + sample[AudioOutput::LEFTCHANNEL] = sumL; + sample[AudioOutput::RIGHTCHANNEL] = sumR; } bool AudioGeneratorMOD::LoadMOD() diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 0eb3c0da..941ffe06 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -300,7 +300,7 @@ bool AudioOutputI2S::ConsumeSample(int16_t sample[2]) { int16_t l = Amplify(ms[LEFTCHANNEL]) + 0x8000; int16_t r = Amplify(ms[RIGHTCHANNEL]) + 0x8000; - s32 = (r << 16) | (l & 0xffff); + s32 = ((r & 0xffff) << 16) | (l & 0xffff); } else { From 7a82ba2ab3401ddb6c350a0a26b9faa23a816468 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 9 Jan 2022 17:39:34 +0100 Subject: [PATCH 086/150] AudiogeneratorMOD: use full 16bit with slightly better accuracy (#479) * Fix a tricky bug that causes delays in playback ... this bug was already present in stellaplayer. Obviously "effectNumber" must be checked, because "effectParameterX" just holds the "upper nibble" of effectParameter * fix for issue #474 - do channel mixing in 32bit, to avoid noise from over/underflow - write audio output as "signed int" (not unsigned) - add int16 saturation check ("clipping") * avoid crash when MOD file has to many CHANNELS - avoid guru meditation, by logging an error and refusing playback in case MOD.numberOfChannels > CHANNELS - correct small typo * internal DAC: avoid possible overflow in conversion int16 -> uint16 * update constants .. we can do 16bit and 8 channels, so let's do it ;-) This adds some debugging code to better understand what is going on inside the mixer code (AudioGeneratorMOD::GetSample). And it also prints out some usefull information from the MOD file. Only active when do_MIXER_DEBUG is defined. * MOD generator: 12 bits of "real" resolution (instead of 10) With this change, we gain 2 additional bits of "real resolution" from the sample interpolation step. Still need some testing to be sure that nothing get "lost" at the same time. * limit to 4 channels on ESP8266 As discussed in https://github.com/earlephilhower/ESP8266Audio/pull/479#issuecomment-1007708703 --- src/AudioGeneratorMOD.cpp | 23 +++++++++++++++++------ src/AudioGeneratorMOD.h | 10 ++++++++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/AudioGeneratorMOD.cpp b/src/AudioGeneratorMOD.cpp index 588ac51e..6a3a07c3 100644 --- a/src/AudioGeneratorMOD.cpp +++ b/src/AudioGeneratorMOD.cpp @@ -69,6 +69,11 @@ bool AudioGeneratorMOD::stop() free(FatBuffer.channels[i]); FatBuffer.channels[i] = NULL; } + + if(running && (file != NULL) && (file->isOpen() == true)) { + output->flush(); //flush I2S output buffer, if the player was actually running before. + } + if (file) file->close(); running = false; output->stop(); @@ -803,14 +808,20 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) current = FatBuffer.channels[channel][(samplePointer - FatBuffer.samplePointer[channel]) /*& (FATBUFFERSIZE - 1)*/]; next = FatBuffer.channels[channel][(samplePointer + 1 - FatBuffer.samplePointer[channel]) /*& (FATBUFFERSIZE - 1)*/]; - - out = current; + + // preserve a few more bits from sample interpolation, by upscaling input values. + // This does (slightly) reduce quantization noise in higher frequencies, typically above 8kHz. + // Actually we could could even gain more bits, I was just not sure if more bits would cause overflows in other conputations. + int16_t current16 = (int16_t) current << 2; + int16_t next16 = (int16_t) next << 2; + + out = current16; // Integer linear interpolation - only works correctly in 16bit - out += (next - current) * (Mixer.channelSampleOffset[channel] & ((1 << FIXED_DIVIDER) - 1)) >> FIXED_DIVIDER; + out += (next16 - current16) * (Mixer.channelSampleOffset[channel] & ((1 << FIXED_DIVIDER) - 1)) >> FIXED_DIVIDER; - // Upscale to BITDEPTH - out32 = (int32_t)out << (BITDEPTH - 8); + // Upscale to BITDEPTH, considering the we already gained two bits in the previous step + out32 = (int32_t)out << (BITDEPTH - 10); // Channel volume out32 = out32 * Mixer.channelVolume[channel] >> 6; @@ -819,7 +830,7 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) sumL += out32 * min(128 - Mixer.channelPanning[channel], 64) >> 6; sumR += out32 * min(Mixer.channelPanning[channel], 64) >> 6; } - + // Downscale to BITDEPTH - a bit faster because the compiler can replaced division by constants with proper "right shift" + correct handling of sign bit if (Mod.numberOfChannels <= 4) { // up to 4 channels diff --git a/src/AudioGeneratorMOD.h b/src/AudioGeneratorMOD.h index 06003775..e2b5b27a 100644 --- a/src/AudioGeneratorMOD.h +++ b/src/AudioGeneratorMOD.h @@ -53,7 +53,7 @@ class AudioGeneratorMOD : public AudioGenerator protected: int mixerTick; - enum {BITDEPTH = 15}; + enum {BITDEPTH = 16}; int sampleRate; int fatBufferSize; //(6*1024) // File system buffers per-CHANNEL (i.e. total mem required is 4 * FATBUFFERSIZE) enum {FIXED_DIVIDER = 10}; // Fixed-point mantissa used for integer arithmetic @@ -64,8 +64,14 @@ class AudioGeneratorMOD : public AudioGenerator // Hz = 7159091 / (amigaPeriod * 2) for NTSC int AMIGA; void UpdateAmiga() { AMIGA = ((usePAL?7159091:7093789) / 2 / sampleRate << FIXED_DIVIDER); } - + +#ifdef ESP8266 // Not sure if C3/C2 have RAM constraints, maybe add them here? + // support max 4 channels enum {ROWS = 64, SAMPLES = 31, CHANNELS = 4, NONOTE = 0xFFFF, NONOTE8 = 0xff }; +#else + // support max 8 channels + enum {ROWS = 64, SAMPLES = 31, CHANNELS = 8, NONOTE = 0xFFFF, NONOTE8 = 0xff }; +#endif typedef struct Sample { uint16_t length; From d5dea4f20c2130f857f329abdb3847c87e7c19ef Mon Sep 17 00:00:00 2001 From: smischny <61064748+smischny@users.noreply.github.com> Date: Sun, 9 Jan 2022 11:57:54 -0500 Subject: [PATCH 087/150] AudioOutputI2SNoDAC not working for RP2040 due to constructor differences with AudioOutputI2S (parent class) (#477) Updated code to correctly call the parent classes constructor for the RP2040. Changed the code for the RP2040 to correctly call the parent classes constructor. --- src/AudioOutputI2SNoDAC.cpp | 22 ++++++++++++++++++++++ src/AudioOutputI2SNoDAC.h | 9 +++++++++ 2 files changed, 31 insertions(+) diff --git a/src/AudioOutputI2SNoDAC.cpp b/src/AudioOutputI2SNoDAC.cpp index 976d73c7..3e936a04 100644 --- a/src/AudioOutputI2SNoDAC.cpp +++ b/src/AudioOutputI2SNoDAC.cpp @@ -29,6 +29,25 @@ #include "AudioOutputI2SNoDAC.h" +#if defined(ARDUINO_ARCH_RP2040) +// +// Create an alternate constructor for the RP2040. The AudioOutputI2S has an alternate +// constructor for the RP2040, so the code was passing port to the sampleRate and false to sck. +// +// AudioOutputI2S(long sampleRate = 44100, pin_size_t sck = 26, pin_size_t data = 28); +// +// So this new constructor adds the ability to pass both port and sck to the underlying class, but +// uses the same defaults in the AudioOutputI2S constructor. +// +AudioOutputI2SNoDAC::AudioOutputI2SNoDAC(int port, int sck) : AudioOutputI2S(44100, sck, port) +{ + SetOversampling(32); + lastSamp = 0; + cumErr = 0; +} + +#else + AudioOutputI2SNoDAC::AudioOutputI2SNoDAC(int port) : AudioOutputI2S(port, false) { SetOversampling(32); @@ -38,7 +57,10 @@ AudioOutputI2SNoDAC::AudioOutputI2SNoDAC(int port) : AudioOutputI2S(port, false) WRITE_PERI_REG(PERIPHS_IO_MUX_MTDO_U, orig_bck); WRITE_PERI_REG(PERIPHS_IO_MUX_GPIO2_U, orig_ws); #endif + } +#endif + AudioOutputI2SNoDAC::~AudioOutputI2SNoDAC() { diff --git a/src/AudioOutputI2SNoDAC.h b/src/AudioOutputI2SNoDAC.h index 2a632252..de475957 100644 --- a/src/AudioOutputI2SNoDAC.h +++ b/src/AudioOutputI2SNoDAC.h @@ -25,7 +25,16 @@ class AudioOutputI2SNoDAC : public AudioOutputI2S { public: +// +// Define a different constructor for the RP2040, as this class calls the constructor +// of the AudioOutputI2S which has an alternate constructor for the RP2040 +// +#if defined(ARDUINO_ARCH_RP2040) + AudioOutputI2SNoDAC(int port = 28,int sck = 26); +#else AudioOutputI2SNoDAC(int port = 0); +#endif + virtual ~AudioOutputI2SNoDAC() override; virtual bool begin() override { return AudioOutputI2S::begin(false); } virtual bool ConsumeSample(int16_t sample[2]) override; From 73a1821aba9d41c70a05d59fbb11bfbf0316c866 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 10 Jan 2022 23:27:02 +0100 Subject: [PATCH 088/150] Flush MOD output after normal end of playback (#482) small oops in my previous PR - output->flush was not called after normal "end of song". --- src/AudioGeneratorMOD.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioGeneratorMOD.cpp b/src/AudioGeneratorMOD.cpp index 6a3a07c3..cb828b24 100644 --- a/src/AudioGeneratorMOD.cpp +++ b/src/AudioGeneratorMOD.cpp @@ -70,7 +70,7 @@ bool AudioGeneratorMOD::stop() FatBuffer.channels[i] = NULL; } - if(running && (file != NULL) && (file->isOpen() == true)) { + if(running || ((file != NULL) && (file->isOpen() == true))) { output->flush(); //flush I2S output buffer, if the player was actually running before. } From 20943870a9871dba0d77a0c37f0f9c2d0fa73623 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 9 Feb 2022 08:33:23 -0800 Subject: [PATCH 089/150] Fix #define protection macro name --- src/AudioFileSourceLittleFS.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AudioFileSourceLittleFS.h b/src/AudioFileSourceLittleFS.h index b57b89fa..6430e804 100644 --- a/src/AudioFileSourceLittleFS.h +++ b/src/AudioFileSourceLittleFS.h @@ -18,8 +18,8 @@ along with this program. If not, see . */ -#ifndef _AUDIOFILESOURCESPIFFS_H -#define _AUDIOFILESOURCESPIFFS_H +#ifndef _AUDIOFILESOURCELITTLEFS_H +#define _AUDIOFILESOURCELITTLEFS_H #include #include From 8b4010bf841408bd446cfd2f8020ee37c32bbe34 Mon Sep 17 00:00:00 2001 From: Maximilian Gerhardt Date: Fri, 18 Feb 2022 05:40:21 +0100 Subject: [PATCH 090/150] Fix PlatformIO library search mode (#500) * Set default library mode to "deep" * Increase version analog to library.json --- library.json | 7 +++++-- library.properties | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/library.json b/library.json index ddbb6d63..b389b847 100644 --- a/library.json +++ b/library.json @@ -14,10 +14,13 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.5", + "version": "1.9.6", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ "examples/*/*.ino" - ] + ], + "build": { + "libLDFMode": "deep" + } } diff --git a/library.properties b/library.properties index 85a99c0e..d8a29a39 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.5 +version=1.9.6 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From 9ffb8a503aa7eb94d88749a471bc05fc63acc3c4 Mon Sep 17 00:00:00 2001 From: Martin-Laclaustra Date: Thu, 10 Mar 2022 18:14:10 +0100 Subject: [PATCH 091/150] Do not compile AudioGeneratorMIDI if GCC is 8 (compiler bug) (#502) --- src/AudioGeneratorMIDI.cpp | 6 ++++++ src/AudioGeneratorMIDI.h | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index 5f1c5f3a..1bb1cd3f 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -58,6 +58,10 @@ #include "AudioGeneratorMIDI.h" +#if __GNUC__ == 8 +// Do not build, GCC8 has a compiler bug +#else // __GNUC__ == 8 + #pragma GCC optimize ("O3") #define TSF_NO_STDIO @@ -637,3 +641,5 @@ void AudioGeneratorMIDI::MakeStreamFromAFS(AudioFileSource *src, tsf_stream *afs afs->size = &afs_size; } +#endif //__GNUC__ == 8 + diff --git a/src/AudioGeneratorMIDI.h b/src/AudioGeneratorMIDI.h index 8a1ac3f9..96b2dd63 100644 --- a/src/AudioGeneratorMIDI.h +++ b/src/AudioGeneratorMIDI.h @@ -21,6 +21,10 @@ #ifndef _AUDIOGENERATORMIDI_H #define _AUDIOGENERATORMIDI_H +#if __GNUC__ == 8 +// Do not build, GCC8 has a compiler bug +#else // __GNUC__ == 8 + #include "AudioGenerator.h" #define TSF_NO_STDIO @@ -176,6 +180,7 @@ class AudioGeneratorMIDI : public AudioGenerator short samplesRendered[256]; }; +#endif //__GNUC__ == 8 #endif From c87b662cb6063c63546fd38c563d69e4f612d5a9 Mon Sep 17 00:00:00 2001 From: Wouter van der Put Date: Wed, 16 Mar 2022 01:59:40 +0100 Subject: [PATCH 092/150] Fix typo (#504) --- examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino b/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino index 50b0ade3..cf7e143b 100644 --- a/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino +++ b/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino @@ -61,7 +61,7 @@ void loop() { } } } else { - Serial.println(F("Playback form SD card done\n")); + Serial.println(F("Playback from SD card done\n")); delay(1000); } } From 76235d0e3f69b2ed5973b690d286cd81df4594ad Mon Sep 17 00:00:00 2001 From: Raphael Rott <78685408+rottifant@users.noreply.github.com> Date: Mon, 25 Apr 2022 18:02:45 +0200 Subject: [PATCH 093/150] fix typos in readme (#513) --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0b3ab8d5..229d45fa 100644 --- a/README.md +++ b/README.md @@ -181,7 +181,7 @@ I've used several versions of PCM5102 DAC boards purchased from eBay. They've a ### Others -There are many other variants out there, and they should all work reasonably well with this code and the ESP8266. Please be certain you've read the datasheet and are applying proper input voltages, and be sure to tie off any unused inputs to GND or VCC as appropriate. LEaving an input pin floating on any integrated circuit can cause unstable operation as it may pick up noise from the environment (very low input capacitance) and cause havoc with internal IC settings. +There are many other variants out there, and they should all work reasonably well with this code and the ESP8266. Please be certain you've read the datasheet and are applying proper input voltages, and be sure to tie off any unused inputs to GND or VCC as appropriate. Leaving an input pin floating on any integrated circuit can cause unstable operation as it may pick up noise from the environment (very low input capacitance) and cause havoc with internal IC settings. ## Software I2S Delta-Sigma DAC (i.e. playing music with a single transistor and speaker) For the best fidelity, and stereo to boot, spend the money on a real I2S DAC. Adafruit makes a great mono one with amplifier, and you can find stereo unamplified ones on eBay or elsewhere quite cheaply. However, thanks to the software delta-sigma DAC with 32x oversampling (up to 128x if the audio rate is low enough) you can still have pretty good sound! @@ -216,7 +216,7 @@ USB-5V -- Speaker + Terminal *NOTE*: A prior version of this schematic had a direct connection from the ESP8266 to the base of the transistor. While this does provide the maximum amplitude, it also can draw more current from the 8266 than is safe, and can also cause the transistor to overheat. -As of the latest ESP8266Audio release, with the software delta-sigma DAC the LRCLK and BCLK pins *can* be used by an application. Simply use normal `pinMode` and `dicitalWrite` or `digitalRead` as desired. +As of the latest ESP8266Audio release, with the software delta-sigma DAC the LRCLK and BCLK pins *can* be used by an application. Simply use normal `pinMode` and `digitalWrite` or `digitalRead` as desired. ### High pitched buzzing with the 1-T circuit The 1-T amp can _NOT_ drive any sort of amplified speaker. If there is a power or USB input to the speaker, or it has lights or Bluetooth or a battery, it can _NOT_ be used with this circuit. @@ -249,7 +249,7 @@ ESP Pin -------|____|--------+ | Ground ---------------------+ ``` -For ESP8266 with red LED (~1.9Vf drop) you need minimum 150Ohm resistor (12mA max per pin), and output pin is fixed (GPIO3/RX0).On ESP32 it is confgurable with `AudioOutputSPDIF(gpio_num)`. +For ESP8266 with red LED (~1.9Vf drop) you need minimum 150Ohm resistor (12mA max per pin), and output pin is fixed (GPIO3/RX0).On ESP32 it is configurable with `AudioOutputSPDIF(gpio_num)`. ## Using external SPI RAM to increase buffer A class allows you to use a 23lc1024 SPI RAM from Microchip as input buffer. This chip connects to ESP8266 HSPI port and provides a large buffer to help avoid hiccus in playback of web streams. From 9384bb0f3d030a709e978cb1fd401841e96180cb Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 18 May 2022 17:37:34 -0700 Subject: [PATCH 094/150] Update for RP2040 core v2.0 new I2S (#528) The I2S subsystem was rewritten in the RP2040 core V2.0, so update to use the new object and calls. Also clean up some code warnings and remove SPIFFS from the RP2040\ --- src/AudioFileSourceFunction.cpp | 8 ++-- src/AudioOutputI2S.cpp | 73 +++++++++++++++++---------------- src/AudioOutputI2S.h | 11 ++++- src/AudioOutputI2SNoDAC.cpp | 8 +--- src/AudioOutputSPIFFSWAV.cpp | 6 ++- src/AudioOutputSPIFFSWAV.h | 3 ++ tests/common.sh | 2 +- 7 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/AudioFileSourceFunction.cpp b/src/AudioFileSourceFunction.cpp index 885defa4..6536985b 100644 --- a/src/AudioFileSourceFunction.cpp +++ b/src/AudioFileSourceFunction.cpp @@ -25,14 +25,14 @@ AudioFileSourceFunction::AudioFileSourceFunction(float sec, uint16_t channels, u uint32_t len = uint32_t(sec * (float)bytes_per_sec); // RIFF chunk - strncpy(wav_header.riff.chunk_id, "RIFF", 4); + memcpy(wav_header.riff.chunk_id, "RIFF", 4); wav_header.riff.chunk_size = 4 // size of riff chunk w/o chunk_id and chunk_size + 8 + 16 // size of format chunk + 8 + len; // size of data chunk - strncpy(wav_header.riff.format, "WAVE", 4); + memcpy(wav_header.riff.format, "WAVE", 4); // format chunk - strncpy(wav_header.format.chunk_id, "fmt ", 4); + memcpy(wav_header.format.chunk_id, "fmt ", 4); wav_header.format.chunk_size = 16; wav_header.format.format_tag = 0x0001; // PCM wav_header.format.channels = channels; @@ -42,7 +42,7 @@ AudioFileSourceFunction::AudioFileSourceFunction(float sec, uint16_t channels, u wav_header.format.bits_per_sample = bits_per_sample; // data chunk - strncpy(wav_header.data.chunk_id, "data", 4); + memcpy(wav_header.data.chunk_id, "data", 4); wav_header.data.chunk_size = len; funcs.reserve(channels); diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 941ffe06..5894e294 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -52,6 +52,35 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int SetGain(1.0); } +#elif defined(ARDUINO_ARCH_RP2040) +AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) { + i2sOn = false; + mono = false; + bps = 16; + channels = 2; + hertz = sampleRate; + bclkPin = sck; + doutPin = data; + SetGain(1.0); +} +#endif + +AudioOutputI2S::~AudioOutputI2S() +{ + #ifdef ESP32 + if (i2sOn) { + audioLogger->printf("UNINSTALL I2S\n"); + i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver + } + #elif defined(ESP8266) + if (i2sOn) + i2s_end(); + #elif defined(ARDUINO_ARCH_RP2040) + stop(); + #endif + i2sOn = false; +} + bool AudioOutputI2S::SetPinout() { #ifdef ESP32 @@ -83,35 +112,6 @@ bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout) return true; } -#elif defined(ARDUINO_ARCH_RP2040) -AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) { - i2sOn = false; - mono = false; - bps = 16; - channels = 2; - hertz = sampleRate; - bclkPin = sck; - doutPin = data; - SetGain(1.0); -} -#endif - -AudioOutputI2S::~AudioOutputI2S() -{ - #ifdef ESP32 - if (i2sOn) { - audioLogger->printf("UNINSTALL I2S\n"); - i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver - } - #elif defined(ESP8266) - if (i2sOn) - i2s_end(); - #elif defined(ARDUINO_ARCH_RP2040) - stop(); - #endif - i2sOn = false; -} - bool AudioOutputI2S::SetRate(int hz) { // TODO - have a list of allowable rates from constructor, check them @@ -123,7 +123,7 @@ bool AudioOutputI2S::SetRate(int hz) #elif defined(ESP8266) i2s_set_rate(AdjustI2SRate(hz)); #elif defined(ARDUINO_ARCH_RP2040) - I2S.setFrequency(hz); + i2s.setFrequency(hz); #endif } return true; @@ -266,9 +266,9 @@ bool AudioOutputI2S::begin(bool txDAC) #elif defined(ARDUINO_ARCH_RP2040) (void)txDAC; if (!i2sOn) { - I2S.setBCLK(bclkPin); - I2S.setDOUT(doutPin); - I2S.begin(hertz); + i2s.setBCLK(bclkPin); + i2s.setDATA(doutPin); + i2s.begin(hertz); } #endif i2sOn = true; @@ -316,7 +316,8 @@ bool AudioOutputI2S::ConsumeSample(int16_t sample[2]) uint32_t s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); return i2s_write_sample_nb(s32); // If we can't store it, return false. OTW true #elif defined(ARDUINO_ARCH_RP2040) - return !!I2S.write((void*)ms, 4); + uint32_t s32 = ((Amplify(ms[RIGHTCHANNEL])) << 16) | (Amplify(ms[LEFTCHANNEL]) & 0xffff); + return !!i2s.write((int32_t)s32, false); #endif } @@ -334,7 +335,7 @@ void AudioOutputI2S::flush() } } #elif defined(ARDUINO_ARCH_RP2040) - I2S.flush(); + i2s.flush(); #endif } @@ -346,7 +347,7 @@ bool AudioOutputI2S::stop() #ifdef ESP32 i2s_zero_dma_buffer((i2s_port_t)portNo); #elif defined(ARDUINO_ARCH_RP2040) - I2S.end(); + i2s.end(); #endif i2sOn = false; return true; diff --git a/src/AudioOutputI2S.h b/src/AudioOutputI2S.h index b3f621d2..33e784bd 100644 --- a/src/AudioOutputI2S.h +++ b/src/AudioOutputI2S.h @@ -22,17 +22,22 @@ #include "AudioOutput.h" +#if defined(ARDUINO_ARCH_RP2040) +#include +#include +#endif + class AudioOutputI2S : public AudioOutput { public: #if defined(ESP32) || defined(ESP8266) AudioOutputI2S(int port=0, int output_mode=EXTERNAL_I2S, int dma_buf_count = 8, int use_apll=APLL_DISABLE); - bool SetPinout(int bclkPin, int wclkPin, int doutPin); enum : int { APLL_AUTO = -1, APLL_ENABLE = 1, APLL_DISABLE = 0 }; enum : int { EXTERNAL_I2S = 0, INTERNAL_DAC = 1, INTERNAL_PDM = 2 }; #elif defined(ARDUINO_ARCH_RP2040) AudioOutputI2S(long sampleRate = 44100, pin_size_t sck = 26, pin_size_t data = 28); #endif + bool SetPinout(int bclkPin, int wclkPin, int doutPin); virtual ~AudioOutputI2S() override; virtual bool SetRate(int hz) override; virtual bool SetBitsPerSample(int bits) override; @@ -63,4 +68,8 @@ class AudioOutputI2S : public AudioOutput uint8_t bclkPin; uint8_t wclkPin; uint8_t doutPin; + +#if defined(ARDUINO_ARCH_RP2040) + I2S i2s; +#endif }; diff --git a/src/AudioOutputI2SNoDAC.cpp b/src/AudioOutputI2SNoDAC.cpp index 3e936a04..a70e6721 100644 --- a/src/AudioOutputI2SNoDAC.cpp +++ b/src/AudioOutputI2SNoDAC.cpp @@ -119,9 +119,6 @@ bool AudioOutputI2SNoDAC::ConsumeSample(int16_t sample[2]) // Either send complete pulse stream or nothing #ifdef ESP32 -//"i2s_write_bytes" has been removed in the ESP32 Arduino 2.0.0, use "i2s_write" instead. -// if (!i2s_write_bytes((i2s_port_t)portNo, (const char *)dsBuff, sizeof(uint32_t) * (oversample/32), 0)) - size_t i2s_bytes_written; i2s_write((i2s_port_t)portNo, (const char *)dsBuff, sizeof(uint32_t) * (oversample/32), &i2s_bytes_written, 0); if (!i2s_bytes_written){ @@ -134,9 +131,8 @@ bool AudioOutputI2SNoDAC::ConsumeSample(int16_t sample[2]) for (int i = 32; i < oversample; i+=32) i2s_write_sample( dsBuff[i / 32]); #elif defined(ARDUINO_ARCH_RP2040) - int16_t *p = (int16_t *) dsBuff; - for (int i = 0; i < oversample / 16; i++) { - I2S.write(*(p++)); + for (int i = 0; i < oversample / 32; i++) { + i2s.write((int32_t)dsBuff[i], true); } #endif return true; diff --git a/src/AudioOutputSPIFFSWAV.cpp b/src/AudioOutputSPIFFSWAV.cpp index 44a5022c..331871fe 100644 --- a/src/AudioOutputSPIFFSWAV.cpp +++ b/src/AudioOutputSPIFFSWAV.cpp @@ -18,6 +18,8 @@ along with this program. If not, see . */ +#if !defined(ARDUINO_ARCH_RP2040) + #include #include #ifdef ESP32 @@ -110,4 +112,6 @@ bool AudioOutputSPIFFSWAV::stop() f.close(); return true; } - + + +#endif diff --git a/src/AudioOutputSPIFFSWAV.h b/src/AudioOutputSPIFFSWAV.h index 4a2afaf4..376a1df6 100644 --- a/src/AudioOutputSPIFFSWAV.h +++ b/src/AudioOutputSPIFFSWAV.h @@ -21,6 +21,8 @@ #ifndef _AUDIOOUTPUTSPIFFSWAV_H #define _AUDIOOUTPUTSPIFFSWAV_H +#if !defined(ARDUINO_ARCH_RP2040) + #include #include @@ -43,3 +45,4 @@ class AudioOutputSPIFFSWAV : public AudioOutput #endif +#endif diff --git a/tests/common.sh b/tests/common.sh index 25c05cd6..eaa9d6db 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -93,7 +93,7 @@ function install_libraries() function install_ide() { local ide_path=$1 - wget -q -O arduino.tar.xz https://www.arduino.cc/download.php?f=/arduino-nightly-linux64.tar.xz + wget -q -O arduino.tar.xz https://downloads.arduino.cc/arduino-nightly-linux64.tar.xz tar xf arduino.tar.xz mv arduino-nightly $ide_path export PATH="$ide_path:$PATH" From be8b8efbf22e7ce00f73f80219ebf12dd32dcf55 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 18 May 2022 18:43:50 -0700 Subject: [PATCH 095/150] Clean ESP32 build (#529) --- src/AudioOutputI2S.cpp | 4 ++++ src/spiram-fast.h | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 5894e294..0bfab14f 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -201,7 +201,11 @@ bool AudioOutputI2S::begin(bool txDAC) } else if (lsb_justified) { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) + comm_fmt = (i2s_comm_format_t) I2S_COMM_FORMAT_STAND_MSB; +#else comm_fmt = (i2s_comm_format_t) (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB); +#endif } else { diff --git a/src/spiram-fast.h b/src/spiram-fast.h index ce568873..cd75d2de 100644 --- a/src/spiram-fast.h +++ b/src/spiram-fast.h @@ -332,9 +332,9 @@ class ESP8266SPIRAM { } digitalWrite(csPin, HIGH); - pinMode(sck, SPECIAL); - pinMode(miso, SPECIAL); - pinMode(mosi, SPECIAL); + pinMode(sck, OUTPUT); + pinMode(miso, INPUT); + pinMode(mosi, OUTPUT); pinMode(csPin, OUTPUT); // Enable streaming read/write mode @@ -364,4 +364,4 @@ class ESP8266SPIRAM { #endif // ESP32 -#endif \ No newline at end of file +#endif From 206906057498caf34eaf61309a9c9868a361a75a Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 18 May 2022 21:03:37 -0700 Subject: [PATCH 096/150] Add RP2040 build (#530) Fix examples to build on RP2040 Clean up generator warnings No SPDIF on RP2040 (yet) Add back C sources for AAC on ARM No WiFi streaming on RP2040 No webradio on RP2040 No talking clock (NTP) on RP2040 either --- .github/workflows/pr-or-master-push.yml | 24 +++++++++++- README.md | 2 +- examples/MixerSample/MixerSample.ino | 7 +++- .../PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino | 6 +++ .../PlayMIDIFromLittleFS.ino | 9 ++++- .../PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino | 6 ++- .../PlayMODFromPROGMEMToDAC.ino | 6 ++- .../PlayMP3FromSPIFFS/PlayMP3FromSPIFFS.ino | 6 +++ examples/PlayMP3ToSPDIF/PlayMP3ToSPDIF.ino | 5 +++ .../PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino | 6 +++ .../StreamMP3FromHTTP/StreamMP3FromHTTP.ino | 9 ++++- .../StreamMP3FromHTTPToSPDIF.ino | 8 +++- .../StreamMP3FromHTTP_SPIRAM.ino | 8 +++- examples/StreamOnHost/StreamOnHost.ino | 8 +++- examples/TalkingClockI2S/TalkingClockI2S.ino | 10 ++++- examples/WebRadio/WebRadio.ino | 8 +++- examples/WebRadio/web.cpp | 8 ++-- src/AudioGeneratorMOD.cpp | 2 +- src/libflac/stream_decoder.c | 4 +- src/libhelix-aac/sbrqmf.c | 5 ++- src/libmad/layer3.c | 1 + src/opusfile/opusfile.c | 2 +- tests/common.sh | 38 +++++++++++++++---- 23 files changed, 154 insertions(+), 34 deletions(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index fcbd0952..3bbdbb99 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -13,6 +13,29 @@ on: jobs: + build-rp2040: + name: Build RP2040 + runs-on: ubuntu-latest + strategy: + matrix: + chunk: [0, 1, 2, 3, 4] + steps: + - uses: actions/checkout@v2 + with: + submodules: true + - uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Build Sketches + env: + TRAVIS_BUILD_DIR: ${{ github.workspace }} + TRAVIS_TAG: ${{ github.ref }} + BUILD_TYPE: build_rp2040 + BUILD_MOD: 5 + BUILD_REM: ${{ matrix.chunk }} + run: | + bash ./tests/common.sh + build-esp8266: name: Build ESP8266 runs-on: ubuntu-latest @@ -36,7 +59,6 @@ jobs: run: | bash ./tests/common.sh - build-esp32: name: Build ESP-32 runs-on: ubuntu-latest diff --git a/README.md b/README.md index 229d45fa..a6a29ee6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi RP2040[![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +# ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi RP2040 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTTL files and playing them on an I2S DAC or even using a software-simulated delta-sigma DAC with dynamic 32x-128x oversampling. ESP8266 is fully supported and most mature, but ESP32 is also mostly there with built-in DAC as well as external ones. diff --git a/examples/MixerSample/MixerSample.ino b/examples/MixerSample/MixerSample.ino index 7a9a1e20..ab02af0b 100644 --- a/examples/MixerSample/MixerSample.ino +++ b/examples/MixerSample/MixerSample.ino @@ -1,5 +1,10 @@ #include -#ifdef ESP32 + +#if defined(ARDUINO_ARCH_RP2040) + #define WIFI_OFF + class __x { public: __x() {}; void mode() {}; }; + __x WiFi; +#elif defined(ESP32) #include #else #include diff --git a/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino b/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino index cf7e143b..110b0460 100644 --- a/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino +++ b/examples/PlayFLAC-SD-SPDIF/PlayFLAC-SD-SPDIF.ino @@ -1,4 +1,8 @@ #include +#ifdef ARDUINO_ARCH_RP2040 +void setup() {} +void loop() {} +#else #include "AudioFileSourceSD.h" #include "AudioOutputSPDIF.h" #include "AudioGeneratorFLAC.h" @@ -66,3 +70,5 @@ void loop() { } } } +#endif + diff --git a/examples/PlayMIDIFromLittleFS/PlayMIDIFromLittleFS.ino b/examples/PlayMIDIFromLittleFS/PlayMIDIFromLittleFS.ino index b4f02e3c..ed075bce 100644 --- a/examples/PlayMIDIFromLittleFS/PlayMIDIFromLittleFS.ino +++ b/examples/PlayMIDIFromLittleFS/PlayMIDIFromLittleFS.ino @@ -6,7 +6,13 @@ } void loop() {} #else -#include +#if defined(ARDUINO_ARCH_RP2040) + #define WIFI_OFF + class __x { public: __x() {}; void mode() {}; }; + __x WiFi; +#else + #include +#endif #include #include #include @@ -42,7 +48,6 @@ void loop() { if (midi->isRunning()) { if (!midi->loop()) { - uint32_t e = millis(); midi->stop(); } } else { diff --git a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino index da9f685c..76e90bb0 100644 --- a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino +++ b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino @@ -1,4 +1,8 @@ #include +#ifdef ARDUINO_ARCH_RP2040 +void setup() {} +void loop() {} +#else #ifdef ESP32 #include #include "SPIFFS.h" @@ -53,4 +57,4 @@ void loop() } } - +#endif diff --git a/examples/PlayMODFromPROGMEMToDAC/PlayMODFromPROGMEMToDAC.ino b/examples/PlayMODFromPROGMEMToDAC/PlayMODFromPROGMEMToDAC.ino index 44aac59e..07ff11c4 100644 --- a/examples/PlayMODFromPROGMEMToDAC/PlayMODFromPROGMEMToDAC.ino +++ b/examples/PlayMODFromPROGMEMToDAC/PlayMODFromPROGMEMToDAC.ino @@ -2,7 +2,11 @@ #include "AudioFileSourcePROGMEM.h" #include "AudioGeneratorMOD.h" #include "AudioOutputI2S.h" -#ifdef ESP32 +#if defined(ARDUINO_ARCH_RP2040) + #define WIFI_OFF + class __x { public: __x() {}; void mode() {}; }; + __x WiFi; +#elif defined(ESP32) #include #else #include diff --git a/examples/PlayMP3FromSPIFFS/PlayMP3FromSPIFFS.ino b/examples/PlayMP3FromSPIFFS/PlayMP3FromSPIFFS.ino index 364a7a89..6d2ff65e 100644 --- a/examples/PlayMP3FromSPIFFS/PlayMP3FromSPIFFS.ino +++ b/examples/PlayMP3FromSPIFFS/PlayMP3FromSPIFFS.ino @@ -1,4 +1,9 @@ #include +#if defined(ARDUINO_ARCH_RP2040) +void setup() {} +void loop() {} +#else + #ifdef ESP32 #include #include "SPIFFS.h" @@ -70,3 +75,4 @@ void loop() delay(1000); } } +#endif diff --git a/examples/PlayMP3ToSPDIF/PlayMP3ToSPDIF.ino b/examples/PlayMP3ToSPDIF/PlayMP3ToSPDIF.ino index 02dfb98f..8e410361 100644 --- a/examples/PlayMP3ToSPDIF/PlayMP3ToSPDIF.ino +++ b/examples/PlayMP3ToSPDIF/PlayMP3ToSPDIF.ino @@ -1,4 +1,8 @@ #include +#ifdef ARDUINO_ARCH_RP2040 +void setup() {} +void loop() {} +#else #ifdef ESP32 #include "SPIFFS.h" #endif @@ -97,3 +101,4 @@ void loop() delay(1000); } } +#endif diff --git a/examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino b/examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino index 44db7c4a..5b96ec91 100644 --- a/examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino +++ b/examples/PlayOpusFromSPIFFS/PlayOpusFromSPIFFS.ino @@ -1,4 +1,8 @@ #include +#ifdef ARDUINO_ARCH_RP2040 +void setup() {} +void loop() {} +#else #ifdef ESP32 #include #include "SPIFFS.h" @@ -39,3 +43,5 @@ void loop() delay(1000); } } + +#endif diff --git a/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino b/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino index 84d7d5b3..3ac0ec0b 100644 --- a/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino +++ b/examples/StreamMP3FromHTTP/StreamMP3FromHTTP.ino @@ -1,6 +1,11 @@ #include -#ifdef ESP32 +#if defined(ARDUINO_ARCH_RP2040) +void setup() {} +void loop() {} + +#else +#if defined(ESP32) #include #else #include @@ -104,4 +109,4 @@ void loop() delay(1000); } } - +#endif diff --git a/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino b/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino index ef542908..23b8547a 100644 --- a/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino +++ b/examples/StreamMP3FromHTTPToSPDIF/StreamMP3FromHTTPToSPDIF.ino @@ -1,6 +1,10 @@ #include +#ifdef ARDUINO_ARCH_RP2040 +void setup() {} +void loop() {} +#else -#ifdef ESP32 +#if defined(ESP32) #include #else #include @@ -140,3 +144,5 @@ void loop() ESP.restart(); } } + +#endif diff --git a/examples/StreamMP3FromHTTP_SPIRAM/StreamMP3FromHTTP_SPIRAM.ino b/examples/StreamMP3FromHTTP_SPIRAM/StreamMP3FromHTTP_SPIRAM.ino index 0b9ab092..3a59b15e 100644 --- a/examples/StreamMP3FromHTTP_SPIRAM/StreamMP3FromHTTP_SPIRAM.ino +++ b/examples/StreamMP3FromHTTP_SPIRAM/StreamMP3FromHTTP_SPIRAM.ino @@ -1,5 +1,9 @@ #include -#ifdef ESP32 +#if defined(ARDUINO_ARCH_RP2040) +void setup() {} +void loop() {} +#else +#if defined(ESP32) #include #else #include @@ -101,4 +105,4 @@ void loop() delay(1000); } } - +#endif diff --git a/examples/StreamOnHost/StreamOnHost.ino b/examples/StreamOnHost/StreamOnHost.ino index 876562d1..4da0642b 100644 --- a/examples/StreamOnHost/StreamOnHost.ino +++ b/examples/StreamOnHost/StreamOnHost.ino @@ -1,6 +1,10 @@ #include -#ifdef ESP32 +#if defined(ARDUINO_ARCH_RP2040) +void setup() {} +void loop() {} +#else +#if defined(ESP32) #include #else #include @@ -115,4 +119,4 @@ void loop() delay(1000); } } - +#endif diff --git a/examples/TalkingClockI2S/TalkingClockI2S.ino b/examples/TalkingClockI2S/TalkingClockI2S.ino index 6a2f7312..61d735d2 100644 --- a/examples/TalkingClockI2S/TalkingClockI2S.ino +++ b/examples/TalkingClockI2S/TalkingClockI2S.ino @@ -2,7 +2,14 @@ // https://github.com/going-digital/Talkie/blob/master/Talkie/examples/Vocab_US_Clock/Vocab_US_Clock.ino // Released under GPL v2 -#ifdef ESP32 +#include + +#if defined(ARDUINO_ARCH_RP2040) +void setup() {} +void loop() {} +#else + +#if defined(ESP32) #include #else #include @@ -183,3 +190,4 @@ void loop() sayTime(tmstruct.tm_hour, tmstruct.tm_min, talkie); delay(1000); } +#endif diff --git a/examples/WebRadio/WebRadio.ino b/examples/WebRadio/WebRadio.ino index e8a03261..7c51ed09 100644 --- a/examples/WebRadio/WebRadio.ino +++ b/examples/WebRadio/WebRadio.ino @@ -19,7 +19,12 @@ */ #include -#ifdef ESP32 +#if defined(ARDUINO_ARCH_RP2040) +void setup() {} +void loop() {} +#else + +#if defined(ESP32) #include #else #include @@ -439,3 +444,4 @@ void loop() } } +#endif diff --git a/examples/WebRadio/web.cpp b/examples/WebRadio/web.cpp index 75e68739..505b309b 100644 --- a/examples/WebRadio/web.cpp +++ b/examples/WebRadio/web.cpp @@ -19,6 +19,9 @@ */ #include +#if defined(ARDUINO_ARCH_RP2040) +// Nothing here +#else #ifdef ESP32 #include #else @@ -308,7 +311,4 @@ void Read4Int(char *str, byte *p) str += ParseInt(str, &i); p[2] = i; if (*str) str++; str += ParseInt(str, &i); p[3] = i; } - - - - +#endif diff --git a/src/AudioGeneratorMOD.cpp b/src/AudioGeneratorMOD.cpp index cb828b24..2be98ca9 100644 --- a/src/AudioGeneratorMOD.cpp +++ b/src/AudioGeneratorMOD.cpp @@ -791,7 +791,7 @@ void AudioGeneratorMOD::GetSample(int16_t sample[2]) Mixer.channelSampleNumber[channel] != FatBuffer.channelSampleNumber[channel]) { uint32_t toRead = Mixer.sampleEnd[Mixer.channelSampleNumber[channel]] - samplePointer + 1; - if (toRead > fatBufferSize) toRead = fatBufferSize; + if (toRead > (uint32_t)fatBufferSize) toRead = fatBufferSize; if (!file->seek(samplePointer, SEEK_SET)) { stop(); diff --git a/src/libflac/stream_decoder.c b/src/libflac/stream_decoder.c index 20ae399f..bfbcc542 100644 --- a/src/libflac/stream_decoder.c +++ b/src/libflac/stream_decoder.c @@ -2783,7 +2783,7 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_ if(rice_parameter < pesc) { partitioned_rice_contents->raw_bits[partition] = 0; u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order; - if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)) + if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, (int *)(residual + sample), u, rice_parameter)) return false; /* read_callback_ sets the state for us */ sample += u; } @@ -2792,7 +2792,7 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_ return false; /* read_callback_ sets the state for us */ partitioned_rice_contents->raw_bits[partition] = rice_parameter; for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter)) + if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, (FLAC__int32 *)&i, rice_parameter)) return false; /* read_callback_ sets the state for us */ residual[sample] = i; } diff --git a/src/libhelix-aac/sbrqmf.c b/src/libhelix-aac/sbrqmf.c index 83cf14a4..e68bbad7 100644 --- a/src/libhelix-aac/sbrqmf.c +++ b/src/libhelix-aac/sbrqmf.c @@ -222,7 +222,8 @@ static void PostMultiply64(int *fft1, int nSampsOut) * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrqmfak.s when building for ARM! **************************************************************************************/ -#if (defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__)) + //TODO - ADD IN .S SOURCES SOMEHOW +#if 0 //(defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__)) #ifdef __cplusplus extern "C" #endif @@ -395,7 +396,7 @@ int QMFAnalysis(int *inbuf, int *delay, int *XBuf, int fBitsIn, int *delayIdx, i * Notes: this is carefully written to be efficient on ARM * use the assembly code version in sbrqmfsk.s when building for ARM! **************************************************************************************/ -#if (defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__)) +#if 0 //(defined (__arm) && defined (__ARMCC_VERSION)) || (defined (_WIN32) && defined (_WIN32_WCE) && defined (ARM)) || (defined(__GNUC__) && defined(__arm__)) #ifdef __cplusplus extern "C" #endif diff --git a/src/libmad/layer3.c b/src/libmad/layer3.c index 66ed7c2e..bc964334 100644 --- a/src/libmad/layer3.c +++ b/src/libmad/layer3.c @@ -20,6 +20,7 @@ */ #pragma GCC optimize ("O3") +#pragma GCC diagnostic ignored "-Wstrict-aliasing" #include # include "config.h" diff --git a/src/opusfile/opusfile.c b/src/opusfile/opusfile.c index 7ffe32f8..95aab481 100644 --- a/src/opusfile/opusfile.c +++ b/src/opusfile/opusfile.c @@ -1422,7 +1422,7 @@ static int op_open_seekable2_impl(OggOpusFile *_of){ _of->end=sr[0].offset+sr[0].size; if(OP_UNLIKELY(_of->endserialnos,&_of->nserialnos,&_of->cserialnos); free(sr); return ret; diff --git a/tests/common.sh b/tests/common.sh index eaa9d6db..275cf1df 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -118,7 +118,30 @@ function install_esp8266() python3 get.py export PATH="$ide_path/hardware/esp8266com/esp8266/tools/xtensa-lx106-elf/bin:$PATH" popd +} +function install_rp2040() +{ + local ide_path=$1 + mkdir -p $ide_path/hardware + cd $ide_path/hardware + mkdir pico + cd pico + git clone https://github.com/earlephilhower/arduino-pico rp2040 + pushd rp2040/tools + # Set custom warnings for all builds (i.e. could add -Wextra at some point) + echo "compiler.c.extra_flags=-Wall -Wextra -Werror $debug_flags" > ../platform.local.txt + echo "compiler.cpp.extra_flags=-Wall -Wextra -Werror $debug_flags" >> ../platform.local.txt + echo -e "\n----platform.local.txt----" + cat ../platform.local.txt + git submodule update --init + cd ../pico-sdk + git submodule update --init + cd ../tools + python3 get.py + export PATH="$ide_path/hardware/pico/rp2040/system/arm-none-eabi/bin:$PATH" + popd + cd rp2040 } function install_esp32() @@ -147,25 +170,19 @@ function install_esp32() function install_arduino() { # Install Arduino IDE and required libraries - echo -e "travis_fold:start:sketch_test_env_prepare" cd $TRAVIS_BUILD_DIR install_ide $HOME/arduino_ide $TRAVIS_BUILD_DIR which arduino cd $TRAVIS_BUILD_DIR install_libraries - echo -e "travis_fold:end:sketch_test_env_prepare" } function build_sketches_with_arduino() { # Compile sketches - echo -e "travis_fold:start:sketch_test" build_sketches $HOME/arduino_ide $HOME/Arduino/libraries "-l $HOME/Arduino/libraries" - echo -e "travis_fold:end:sketch_test" # Generate size report - echo -e "travis_fold:start:size_report" cat size.log - echo -e "travis_fold:end:size_report" } set -e @@ -184,11 +201,16 @@ elif [ "$BUILD_TYPE" = "build_esp32" ]; then install_arduino install_esp32 "$HOME/arduino_ide" export ide_path=$HOME/arduino_ide - export FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" + export FQBN="esp32:esp32:esp32:PSRAM=disabled,PartitionScheme=default,CPUFreq=240,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,LoopCore=1,EventsCore=1,DebugLevel=none" export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR" export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG" source $ide_path/hardware/espressif/esp32/.github/scripts/install-arduino-ide.sh source $ide_path/hardware/espressif/esp32/.github/scripts/install-arduino-core-esp32.sh build_sketches "$FQBN" "$HOME/Arduino/libraries" "$BUILD_REM" "$BUILD_MOD" +elif [ "$BUILD_TYPE" = "build_rp2040" ]; then + install_arduino + install_rp2040 "$HOME/arduino_ide" + export cache_dir=$(mktemp -d) + source "$HOME/arduino_ide/hardware/pico/rp2040/tests/common.sh" + build_sketches "$HOME/arduino_ide" "$TRAVIS_BUILD_DIR" "-l $HOME/Arduino/libraries" "$BUILD_MOD" "$BUILD_REM" fi - From a6f1eda9a20bdb481f6254a832be052c5c997082 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 18 May 2022 22:12:33 -0700 Subject: [PATCH 097/150] Get ESP8266 CI running again (#531) Add LWIP to ESP8266 builds New build step on ESP8266 Fix warnings, quiet get.py Ack SPIFFS deprecation Example fix Clean up overzealous pragmas Fix server.accept() deprecation --- examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino | 1 - examples/StreamOnHost/AudioOutputNullSlow.h | 1 + examples/StreamOnHost/StreamOnHost.ino | 4 ++-- examples/WebRadio/WebRadio.ino | 3 +++ src/AudioFileSourceICYStream.cpp | 3 +++ src/AudioFileSourceSPIFFS.h | 3 +++ src/AudioOutputSPIFFSWAV.cpp | 4 ++++ tests/common.sh | 12 +++++++----- 8 files changed, 23 insertions(+), 8 deletions(-) diff --git a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino index 76e90bb0..8fe3000d 100644 --- a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino +++ b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino @@ -48,7 +48,6 @@ void loop() { if (midi->isRunning()) { if (!midi->loop()) { - uint32_t e = millis(); midi->stop(); } } else { diff --git a/examples/StreamOnHost/AudioOutputNullSlow.h b/examples/StreamOnHost/AudioOutputNullSlow.h index e85cd9ee..3010862e 100644 --- a/examples/StreamOnHost/AudioOutputNullSlow.h +++ b/examples/StreamOnHost/AudioOutputNullSlow.h @@ -30,6 +30,7 @@ class AudioOutputNullSlow : public AudioOutput ~AudioOutputNullSlow() {}; virtual bool begin() { samples = 0; startms = millis(); return true; } virtual bool ConsumeSample(int16_t sample[2]) { + (void) sample; // return false (= output buffer full) // sometimes to let the main loop running constexpr int everylog2 = 10; diff --git a/examples/StreamOnHost/StreamOnHost.ino b/examples/StreamOnHost/StreamOnHost.ino index 4da0642b..90f525bd 100644 --- a/examples/StreamOnHost/StreamOnHost.ino +++ b/examples/StreamOnHost/StreamOnHost.ino @@ -13,10 +13,10 @@ void loop() {} #include "AudioFileSourceBuffer.h" #include "AudioGeneratorMP3.h" #if AUDIO -#pragma message("Outputting audio") +// #pragma message("Outputting audio") #include "AudioOutputLinuxDSP.h" #else -#pragma message("No audio") +// #pragma message("No audio") #include "AudioOutputNullSlow.h" #endif diff --git a/examples/WebRadio/WebRadio.ino b/examples/WebRadio/WebRadio.ino index 7c51ed09..13343ad2 100644 --- a/examples/WebRadio/WebRadio.ino +++ b/examples/WebRadio/WebRadio.ino @@ -24,6 +24,9 @@ void setup() {} void loop() {} #else +// ESP8266 server.available() is now server.accept() +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + #if defined(ESP32) #include #else diff --git a/src/AudioFileSourceICYStream.cpp b/src/AudioFileSourceICYStream.cpp index edeba761..5b1601b4 100644 --- a/src/AudioFileSourceICYStream.cpp +++ b/src/AudioFileSourceICYStream.cpp @@ -20,6 +20,9 @@ #if defined(ESP32) || defined(ESP8266) +#ifdef _GNU_SOURCE +#undef _GNU_SOURCE +#endif #define _GNU_SOURCE #include "AudioFileSourceICYStream.h" diff --git a/src/AudioFileSourceSPIFFS.h b/src/AudioFileSourceSPIFFS.h index 74efefa4..910ddc2c 100644 --- a/src/AudioFileSourceSPIFFS.h +++ b/src/AudioFileSourceSPIFFS.h @@ -27,6 +27,9 @@ #include "AudioFileSource.h" #include "AudioFileSourceFS.h" +// Yes, I know SPIFFS is deprecated +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + class AudioFileSourceSPIFFS : public AudioFileSourceFS { public: diff --git a/src/AudioOutputSPIFFSWAV.cpp b/src/AudioOutputSPIFFSWAV.cpp index 331871fe..075cb4c1 100644 --- a/src/AudioOutputSPIFFSWAV.cpp +++ b/src/AudioOutputSPIFFSWAV.cpp @@ -26,6 +26,10 @@ #include "SPIFFS.h" #endif +// Yes, I know SPIFFS is deprecated +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + + #include "AudioOutputSPIFFSWAV.h" static const uint8_t wavHeaderTemplate[] PROGMEM = { // Hardcoded simple WAV header with 0xffffffff lengths all around diff --git a/tests/common.sh b/tests/common.sh index 275cf1df..85ff3b50 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -111,13 +111,15 @@ function install_esp8266() # Set custom warnings for all builds (i.e. could add -Wextra at some point) echo "compiler.c.extra_flags=-Wall -Wextra -Werror $debug_flags" > ../platform.local.txt echo "compiler.cpp.extra_flags=-Wall -Wextra -Werror $debug_flags" >> ../platform.local.txt + echo "mkbuildoptglobals.extra_flags=--ci --cache_core" >> ../platform.local.txt echo -e "\n----platform.local.txt----" cat ../platform.local.txt git submodule init git submodule update - python3 get.py + python3 get.py -q export PATH="$ide_path/hardware/esp8266com/esp8266/tools/xtensa-lx106-elf/bin:$PATH" popd + cd esp8266 } function install_rp2040() @@ -138,7 +140,7 @@ function install_rp2040() cd ../pico-sdk git submodule update --init cd ../tools - python3 get.py + python3 get.py -q export PATH="$ide_path/hardware/pico/rp2040/system/arm-none-eabi/bin:$PATH" popd cd rp2040 @@ -192,11 +194,12 @@ if [ "$BUILD_MOD" == "" ]; then export BUILD_REM=0 fi +export cache_dir=$(mktemp -d) if [ "$BUILD_TYPE" = "build" ]; then - export BUILD_PY="hardware/esp8266com/esp8266/tools/build.py -b generic -s 4M1M -v -k " install_arduino install_esp8266 "$HOME/arduino_ide" - build_sketches_with_arduino + source "$HOME/arduino_ide/hardware/esp8266com/esp8266/tests/common.sh" + build_sketches "$HOME/arduino_ide" "$TRAVIS_BUILD_DIR" "-l $HOME/Arduino/libraries" "$BUILD_MOD" "$BUILD_REM" "lm2f" elif [ "$BUILD_TYPE" = "build_esp32" ]; then install_arduino install_esp32 "$HOME/arduino_ide" @@ -210,7 +213,6 @@ elif [ "$BUILD_TYPE" = "build_esp32" ]; then elif [ "$BUILD_TYPE" = "build_rp2040" ]; then install_arduino install_rp2040 "$HOME/arduino_ide" - export cache_dir=$(mktemp -d) source "$HOME/arduino_ide/hardware/pico/rp2040/tests/common.sh" build_sketches "$HOME/arduino_ide" "$TRAVIS_BUILD_DIR" "-l $HOME/Arduino/libraries" "$BUILD_MOD" "$BUILD_REM" fi From b9666d36520bd41e505897a5428860d97d73ea74 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 19 May 2022 10:48:24 -0700 Subject: [PATCH 098/150] Get ESP32 CI running again (#532) Get ESP32 CI running again ESP32 lacks separable CI stuff ESP32 has broken GCC 8, don't build MIDI examples --- .../PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino | 5 +- tests/common.sh | 125 +++--------------- 2 files changed, 20 insertions(+), 110 deletions(-) diff --git a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino index 8fe3000d..38e12d34 100644 --- a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino +++ b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino @@ -1,5 +1,8 @@ #include -#ifdef ARDUINO_ARCH_RP2040 + +// Do not build on GCC8, GCC8 has a compiler bug + +#if defined(ARDUINO_ARCH_RP2040) || (__GNUC__ == 8) void setup() {} void loop() {} #else diff --git a/tests/common.sh b/tests/common.sh index 85ff3b50..6b7181d1 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -2,91 +2,10 @@ set -ex -function print_size_info() -{ - elf_file=$1 - - if [ -z "$elf_file" ]; then - printf "sketch data rodata bss text irom0.text dram flash\n" - return 0 - fi - - elf_name=$(basename $elf_file) - sketch_name="${elf_name%.*}" - # echo $sketch_name - declare -A segments - while read -a tokens; do - seg=${tokens[0]} - seg=${seg//./} - size=${tokens[1]} - addr=${tokens[2]} - if [ "$addr" -eq "$addr" -a "$addr" -ne "0" ] 2>/dev/null; then - segments[$seg]=$size - fi - - - done < <(xtensa-lx106-elf-size --format=sysv $elf_file) - - total_ram=$((${segments[data]} + ${segments[rodata]} + ${segments[bss]})) - total_flash=$((${segments[data]} + ${segments[rodata]} + ${segments[text]} + ${segments[irom0text]})) - - printf "%-28s %-8d %-8d %-8d %-8d %-8d %-8d %-8d\n" $sketch_name ${segments[data]} ${segments[rodata]} ${segments[bss]} ${segments[text]} ${segments[irom0text]} $total_ram $total_flash - return 0 -} - -function build_sketches() -{ - set +e - local arduino=$1 - local srcpath=$2 - local build_arg=$3 - local build_dir=build.tmp - local build_mod=$BUILD_MOD - local build_rem=$BUILD_REM - mkdir -p $build_dir - local build_cmd="python3 $arduino/$BUILD_PY -p $PWD/$build_dir $build_arg " - local sketches=$(find $srcpath -name *.ino) - print_size_info >size.log - export ARDUINO_IDE_PATH=$arduino - for sketch in $sketches; do - testcnt=$(( ($testcnt + 1) % $build_mod )) - if [ $testcnt -ne $build_rem ]; then - continue # Not ours to do - fi - rm -rf $build_dir/* - local sketchdir=$(dirname $sketch) - local sketchdirname=$(basename $sketchdir) - local sketchname=$(basename $sketch) - if [[ "${sketchdirname}.ino" != "$sketchname" ]]; then - echo "Skipping $sketch, because it is not the main sketch file"; - continue - fi; - if [[ -f "$sketchdir/.test.skip" ]]; then - echo -e "\n ------------ Skipping $sketch ------------ \n"; - continue - fi - echo -e "\n ------------ Building $sketch ------------ \n"; - # $arduino --verify $sketch; - echo "$build_cmd $sketch" - time ($build_cmd $sketch >build.log) - local result=$? - if [ $result -ne 0 ]; then - echo "Build failed ($1)" - echo "Build log:" - cat build.log - set -e - return $result - fi - rm build.log - #print_size_info $build_dir/*.elf >>size.log - done - set -e -} - function install_libraries() { mkdir -p $HOME/Arduino/libraries - cp -a $TRAVIS_BUILD_DIR $HOME/Arduino/libraries/ESP8266Audio + cp -a $GITHUB_WORKSPACE $HOME/Arduino/libraries/ESP8266Audio git clone https://github.com/earlephilhower/ESP8266SAM $HOME/Arduino/libraries/ESP8266SAM } @@ -149,46 +68,37 @@ function install_rp2040() function install_esp32() { local ide_path=$1 - sudo pip install pyserial + pip install pyserial + pip3 install pyserial cd $ide_path/hardware mkdir espressif cd espressif git clone https://github.com/espressif/arduino-esp32.git esp32 pushd esp32 - # Set custom warnings for all builds (i.e. could add -Wextra at some point) - echo "compiler.c.extra_flags=-Wall -Wextra -Werror $debug_flags" > platform.local.txt - echo "compiler.cpp.extra_flags=-Wall -Wextra -Werror $debug_flags" >> platform.local.txt + # Set custom warnings for all builds + # No -Werror because the ESP32 core has issues itself and evey build will fail in the core files before touching the lib + echo "compiler.c.extra_flags=-Wall -Wextra $debug_flags" > platform.local.txt + echo "compiler.cpp.extra_flags=-Wall -Wextra $debug_flags" >> platform.local.txt echo -e "\n----platform.local.txt----" cat platform.local.txt - git submodule init - git submodule update + git submodule update --init cd tools python3 get.py export PATH="$ide_path/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/:$PATH" popd - + cd esp32 } function install_arduino() { # Install Arduino IDE and required libraries - cd $TRAVIS_BUILD_DIR - install_ide $HOME/arduino_ide $TRAVIS_BUILD_DIR + cd "$GITHUB_WORKSPACE" + install_ide "$HOME/arduino_ide" "$GITHUB_WORKSPACE" which arduino - cd $TRAVIS_BUILD_DIR + cd "$GITHUB_WORKSPACE" install_libraries } -function build_sketches_with_arduino() -{ - # Compile sketches - build_sketches $HOME/arduino_ide $HOME/Arduino/libraries "-l $HOME/Arduino/libraries" - # Generate size report - cat size.log -} - -set -e - if [ "$BUILD_MOD" == "" ]; then export BUILD_MOD=1 export BUILD_REM=0 @@ -203,13 +113,10 @@ if [ "$BUILD_TYPE" = "build" ]; then elif [ "$BUILD_TYPE" = "build_esp32" ]; then install_arduino install_esp32 "$HOME/arduino_ide" - export ide_path=$HOME/arduino_ide - export FQBN="esp32:esp32:esp32:PSRAM=disabled,PartitionScheme=default,CPUFreq=240,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,LoopCore=1,EventsCore=1,DebugLevel=none" - export GITHUB_WORKSPACE="$TRAVIS_BUILD_DIR" - export GITHUB_REPOSITORY="$TRAVIS_REPO_SLUG" - source $ide_path/hardware/espressif/esp32/.github/scripts/install-arduino-ide.sh - source $ide_path/hardware/espressif/esp32/.github/scripts/install-arduino-core-esp32.sh - build_sketches "$FQBN" "$HOME/Arduino/libraries" "$BUILD_REM" "$BUILD_MOD" + export FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" + mkdir -p "$GITHUB_WORKSPACE/hardware" + ln -s "$GITHUB_WORKSPACE/../" "$GITHUB_WORKSPACE/libraries" + source "$HOME/arduino_ide/hardware/espressif/esp32/.github/scripts/sketch_utils.sh" chunk_build "$HOME/arduino_ide" "$GITHUB_WORKSPACE" "$FQBN" esp32 "$GITHUB_WORKSPACE" $BUILD_REM $BUILD_MOD elif [ "$BUILD_TYPE" = "build_rp2040" ]; then install_arduino install_rp2040 "$HOME/arduino_ide" From 879fe48b787e5c9e06c92ab73840503ef215432f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 19 May 2022 13:17:07 -0700 Subject: [PATCH 099/150] Clean up ESP32 I2S interface undefineds (#533) --- src/AudioOutputI2S.cpp | 7 ++++++- src/AudioOutputSPDIF.cpp | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 0bfab14f..c4e0c3aa 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -88,6 +88,7 @@ bool AudioOutputI2S::SetPinout() return false; // Not allowed i2s_pin_config_t pins = { + .mck_io_num = 0, // Unused .bck_io_num = bclkPin, .ws_io_num = wclkPin, .data_out_num = doutPin, @@ -225,7 +226,11 @@ bool AudioOutputI2S::begin(bool txDAC) .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // lowest interrupt priority .dma_buf_count = dma_buf_count, .dma_buf_len = 128, - .use_apll = use_apll // Use audio PLL + .use_apll = use_apll, // Use audio PLL + .tx_desc_auto_clear = true, // Silence on underflow + .fixed_mclk = 0, // Unused + .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, // Unused + .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample }; audioLogger->printf("+%d %p\n", portNo, &i2s_config_dac); if (i2s_driver_install((i2s_port_t)portNo, &i2s_config_dac, 0, NULL) != ESP_OK) diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index 6e1cf197..1d1ec2f3 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -102,7 +102,11 @@ AudioOutputSPDIF::AudioOutputSPDIF(int dout_pin, int port, int dma_buf_count) .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, // lowest interrupt priority .dma_buf_count = dma_buf_count, .dma_buf_len = DMA_BUF_SIZE_DEFAULT, // bigger buffers, reduces interrupts - .use_apll = true // Audio PLL is needed for low clock jitter + .use_apll = true, // Audio PLL is needed for low clock jitter + .tx_desc_auto_clear = true, // Silence on underflow + .fixed_mclk = 0, // Unused + .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, // Unused + .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample }; if (i2s_driver_install((i2s_port_t)portNo, &i2s_config_spdif, 0, NULL) != ESP_OK) { audioLogger->println(F("ERROR: Unable to install I2S drivers")); @@ -147,6 +151,7 @@ bool AudioOutputSPDIF::SetPinout(int bclk, int wclk, int dout) { #if defined(ESP32) i2s_pin_config_t pins = { + .mck_io_num = 0, // unused .bck_io_num = bclk, .ws_io_num = wclk, .data_out_num = dout, From 9a9e030d906405108e9808716b634d67bcdf31a8 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 19 May 2022 17:17:21 -0700 Subject: [PATCH 100/150] Add more tests to host testing in CI (#534) Add more tests to host testing in CI Fix FLAC potential 1st sample output oddity --- .github/workflows/pr-or-master-push.yml | 4 ++++ src/AudioGeneratorFLAC.cpp | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index 3bbdbb99..c4dbbae8 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -106,7 +106,11 @@ jobs: valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./mp3 valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./aac valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./wav + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./flac + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./mod + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./wav valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./midi + valgrind --leak-check=full --track-origins=yes -v --error-limit=no --show-leak-kinds=all --error-exitcode=999 ./opus lint: runs-on: ubuntu-latest diff --git a/src/AudioGeneratorFLAC.cpp b/src/AudioGeneratorFLAC.cpp index bd6e801c..f315133c 100644 --- a/src/AudioGeneratorFLAC.cpp +++ b/src/AudioGeneratorFLAC.cpp @@ -62,6 +62,9 @@ bool AudioGeneratorFLAC::begin(AudioFileSource *source, AudioOutput *output) output->begin(); running = true; + lastSample[0] = 0; + lastSample[1] = 0; + channels = 0; return true; } @@ -71,7 +74,7 @@ bool AudioGeneratorFLAC::loop() if (!running) goto done; - if (!output->ConsumeSample(lastSample)) goto done; // Try and send last buffered sample + if (channels && !output->ConsumeSample(lastSample)) goto done; // Try and send last buffered sample do { if (buffPtr == buffLen) { From 19f802923d358dee6da6009a4fb5538203d463e3 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 31 May 2022 09:36:45 -0700 Subject: [PATCH 101/150] Update library.json --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index b389b847..c02e634a 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.6", + "version": "1.9.7", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ From b987ca3540a181174a529c8ec28b393991220746 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 31 May 2022 09:37:03 -0700 Subject: [PATCH 102/150] Update library.properties --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index d8a29a39..d594ee11 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.6 +version=1.9.7 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From c2adbdcf887fec65d25af0e5b8b47ae424df54e4 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 1 Jun 2022 02:44:13 -0700 Subject: [PATCH 103/150] Enable Werror for ESP32 (#536) The ESP32 core now builds without warnings, so at Werror back --- tests/common.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index 6b7181d1..e3e38574 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -76,9 +76,9 @@ function install_esp32() git clone https://github.com/espressif/arduino-esp32.git esp32 pushd esp32 # Set custom warnings for all builds - # No -Werror because the ESP32 core has issues itself and evey build will fail in the core files before touching the lib - echo "compiler.c.extra_flags=-Wall -Wextra $debug_flags" > platform.local.txt - echo "compiler.cpp.extra_flags=-Wall -Wextra $debug_flags" >> platform.local.txt + + echo "compiler.c.extra_flags=-Wall -Wextra -Werror $debug_flags" > platform.local.txt + echo "compiler.cpp.extra_flags=-Wall -Wextra -Werror $debug_flags" >> platform.local.txt echo -e "\n----platform.local.txt----" cat platform.local.txt git submodule update --init From 3b329b8201dc4b04075fb7e00c794d14df6021c2 Mon Sep 17 00:00:00 2001 From: Torrentero Date: Fri, 10 Jun 2022 20:57:53 -0400 Subject: [PATCH 104/150] fixed: tmpSourceSamplePositionF32P32 jumping to incorrect position causing distorted sound (#539) Co-authored-by: Edgar --- src/libtinysoundfont/tsf.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index bdaadae5..ac38e610 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -1440,6 +1440,7 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff //double tmpSampleEndDbl = (double)v->sampleEnd, tmpLoopEndDbl = (double)tmpLoopEnd + 1.0; //double tmpSourceSamplePosition = v->sourceSamplePosition; fixed32p32 tmpSampleEndF32P32 = ((fixed32p32)(region->end)) << 32; + fixed32p32 tmpLoopStartF32P32 = ((fixed32p32)(tmpLoopStart + 1)) << 32; fixed32p32 tmpLoopEndF32P32 = ((fixed32p32)(tmpLoopEnd + 1)) << 32; fixed32p32 tmpSourceSamplePositionF32P32 = v->sourceSamplePositionF32P32; struct tsf_voice_lowpass tmpLowpass = v->lowpass; @@ -1513,7 +1514,7 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff // Next sample. tmpSourceSamplePositionF32P32 += pitchRatioF32P32; if (tmpSourceSamplePositionF32P32 >= tmpLoopEndF32P32 && isLooping) - tmpSourceSamplePositionF32P32 -= (tmpLoopEndF32P32 - tmpLoopStart + (1LL<<32)); + tmpSourceSamplePositionF32P32 -= (tmpLoopEndF32P32 - tmpLoopStartF32P32 + (1LL<<32)); } if (tmpSourceSamplePositionF32P32 >= tmpSampleEndF32P32 || v->ampenv.segment == TSF_SEGMENT_DONE) From c4bf70bccf77ac9c1166f75c24b2d96b831d487c Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 13 Jun 2022 08:32:18 -0700 Subject: [PATCH 105/150] Fix typo in README (#541) Fixes #540 --- README.md | 40 ++++++++++++++++------------------------ 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index a6a29ee6..fb3085d4 100644 --- a/README.md +++ b/README.md @@ -6,34 +6,25 @@ ESP8266 is fully supported and most mature, but ESP32 is also mostly there with For real-time, autonomous speech synthesis, check out [ESP8266SAM](https://github.com/earlephilhower/ESP8266SAM), a library which uses this one and a port of an ancient format-based synthesis program to allow your ESP8266 to talk with low memory and no network required. ## Disclaimer -All this code is released under the GPL, and all of it is to be used at your own risk. If you find any bugs, please let me know via the GitHub issue tracker or drop me an email. The MOD and MP3 routines were taken from StellaPlayer and libMAD respectively. The software I2S delta-sigma 32x oversampling DAC was my own creation, and sounds quite good if I do say so myself. +All this code is released under the GPL, and all of it is to be used at your own risk. If you find any bugs, please let me know via the GitHub issue tracker or drop me an email. -The AAC decode code is from the Helix project and licensed under RealNetwork's RSPL license. For commercial use you're still going to need the usual AAC licensing from [Via Licensing](http://www.via-corp.com/us/en/licensing/aac/overview.html). - -On the ESP32, AAC-SBR is supported (many webradio stations use this to reduce bandwidth even further). The ESP8266, however, does not support it due to a lack of onboard RAM. - -MIDI decoding comes from a highly ported [MIDITONES](https://github.com/LenShustek/miditones) combined with a massively memory-optimized [TinySoundFont](https://github.com/schellingb/TinySoundFont), see the respective source files for more information. - -Opus, OGG, and OpusFile are from [Xiph.org](https://xiph.org) with the Xiph license and patent described in src/{opusfile,libggg,libopus}/COPYING.. **NOTE** Opus decoding currently only works on the ESP32 due to the large memory requirements of opusfile. PRs to rewrite it to be less memory intensive would be much appreciated. +* The MOD and MP3 routines were taken from StellarPlayer and libMAD respectively. +* The software I2S delta-sigma 32x oversampling DAC was my own creation, and sounds quite good if I do say so myself. +* The AAC decode code is from the Helix project and licensed under RealNetwork's RSPL license. For commercial use you're still going to need the usual AAC licensing from [Via Licensing](http://www.via-corp.com/us/en/licensing/aac/overview.html). On the ESP32, AAC-SBR is supported (many webradio stations use this to reduce bandwidth even further). The ESP8266, however, does not support it due to a lack of onboard RAM. +* MIDI decoding comes from a highly ported [MIDITONES](https://github.com/LenShustek/miditones) combined with a massively memory-optimized [TinySoundFont](https://github.com/schellingb/TinySoundFont), see the respective source files for more information. +* Opus, OGG, and OpusFile are from [Xiph.org](https://xiph.org) with the Xiph license and patent described in src/{opusfile,libggg,libopus}/COPYING.. **NOTE** Opus decoding currently only works on the ESP32 due to the large memory requirements of opusfile. PRs to rewrite it to be less memory intensive would be much appreciated. ## Neat Things People Have Done With ESP8266Audio If you have a neat use for this library, [I'd love to hear about it](mailto:earlephilhower@yahoo.com)! -My personal use of the ESP8266Audio library is only to drive a 3D-printed, network-time-setting alarm clock for my kids which can play an MP3 instead of a bell to wake them up, called [Psychoclock](https://github.com/earlephilhower/psychoclock). - -Harald Sattler has built a neat German [word clock with MP3 alarm](http://www.harald-sattler.de/html/mini-wecker.htm). Detailed discussion on the process and models are included. - -Erich Heinemann has developed a Stomper (instrument for playing samples in real-time during a live stage performance) that you can find more info about [here](https://github.com/ErichHeinemann/hman-stomper). - -Dagnall53 has integrated this into a really neat MQTT based model train controller to add sounds to his set. More info is available [here](https://github.com/dagnall53/ESPMQTTRocnetSound), including STL files for 3D printed components! - -JohannesMTC has built a similar project especially for model trains: https://github.com/JohannesMTC/ESP32_MAS - -A neat MQTT-driven ESP8266 light-and-sound device (alarm? toy? who can say!) was built by @CosmicMac, available at https://github.com/CosmicMac/ESParkle - -A very interesting "linear clock" with a stepper motor, NTP time keeping, and configurable recorded chimes with schematics, 3D printer plans, and source code, is now available https://janderogee.com/projects/linear_clock/linear_clock.htm - -Source and instructions for a gorgeous wooden MP3-playing clock, FM radio and a walkie-talkie using the ESP8266 and AVR microcontrollers is available https://github.com/zduka/mp3-player +* My personal use of the ESP8266Audio library is only to drive a 3D-printed, network-time-setting alarm clock for my kids which can play an MP3 instead of a bell to wake them up, called [Psychoclock](https://github.com/earlephilhower/psychoclock). +* Harald Sattler has built a neat German [word clock with MP3 alarm](http://www.harald-sattler.de/html/mini-wecker.htm). Detailed discussion on the process and models are included. +* Erich Heinemann has developed a Stomper (instrument for playing samples in real-time during a live stage performance) that you can find more info about [here](https://github.com/ErichHeinemann/hman-stomper). +* Dagnall53 has integrated this into a really neat MQTT based model train controller to add sounds to his set. More info is available [here](https://github.com/dagnall53/ESPMQTTRocnetSound), including STL files for 3D printed components! +* JohannesMTC has built a similar project especially for model trains: https://github.com/JohannesMTC/ESP32_MAS +* A neat MQTT-driven ESP8266 light-and-sound device (alarm? toy? who can say!) was built by @CosmicMac, available at https://github.com/CosmicMac/ESParkle +* A very interesting "linear clock" with a stepper motor, NTP time keeping, and configurable recorded chimes with schematics, 3D printer plans, and source code, is now available https://janderogee.com/projects/linear_clock/linear_clock.htm +* Source and instructions for a gorgeous wooden MP3-playing clock, FM radio and a walkie-talkie using the ESP8266 and AVR microcontrollers is available https://github.com/zduka/mp3-player ## Prerequisites First, make sure you are running the 2.6.3/later or GIT head version of the Arduino libraries for ESP8266, or the latest ESP32 SDK from Espressif. @@ -265,10 +256,11 @@ I've been told the Wemos SD card shield uses GPIO15 as the SD chip select. This There's no ESP8266-specific code in the AudioGenerator routines, so porting to other controllers should be relatively easy assuming they have the same endianness as the Xtensa core used. Drop me a line if you're doing this, I may be able to help point you in the right direction. ## Thanks -Thanks to the authors of StellaPlayer and libMAD for releasing their code freely, and to the maintainers and contributors to the ESP8266 Arduino port. +Thanks to the authors of StellarPlayer and libMAD for releasing their code freely, and to the maintainers and contributors to the ESP8266 Arduino port. Also, big thanks to @tueddy for getting the initial ESP32 porting into the tree! -Earle F. Philhower, III + earlephilhower@yahoo.com From 02225bcaa9e29ff1bace7afe04c976afc6b98cbf Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 14 Jun 2022 08:23:22 -0700 Subject: [PATCH 106/150] Fix overflow with x256 oversampling in I2SNoDAC (#543) Fixes #542 --- src/AudioOutputI2SNoDAC.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioOutputI2SNoDAC.h b/src/AudioOutputI2SNoDAC.h index de475957..ef29982b 100644 --- a/src/AudioOutputI2SNoDAC.h +++ b/src/AudioOutputI2SNoDAC.h @@ -43,7 +43,7 @@ class AudioOutputI2SNoDAC : public AudioOutputI2S protected: virtual int AdjustI2SRate(int hz) override { return hz * oversample/32; } - uint8_t oversample; + int oversample; void DeltaSigma(int16_t sample[2], uint32_t dsBuff[4]); typedef int32_t fixed24p8_t; enum {fixedPosValue=0x007fff00}; /* 24.8 of max-signed-int */ From 6d3b8665f4f7960263257a383dc2fb1e5428a45c Mon Sep 17 00:00:00 2001 From: Torrentero Date: Sat, 16 Jul 2022 21:05:28 -0400 Subject: [PATCH 107/150] sketch_utils.sh now uses flags and breaks current functionality (#555) Co-authored-by: Edgar --- tests/common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common.sh b/tests/common.sh index e3e38574..dfd9c4b0 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -116,7 +116,7 @@ elif [ "$BUILD_TYPE" = "build_esp32" ]; then export FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" mkdir -p "$GITHUB_WORKSPACE/hardware" ln -s "$GITHUB_WORKSPACE/../" "$GITHUB_WORKSPACE/libraries" - source "$HOME/arduino_ide/hardware/espressif/esp32/.github/scripts/sketch_utils.sh" chunk_build "$HOME/arduino_ide" "$GITHUB_WORKSPACE" "$FQBN" esp32 "$GITHUB_WORKSPACE" $BUILD_REM $BUILD_MOD + source "$HOME/arduino_ide/hardware/espressif/esp32/.github/scripts/sketch_utils.sh" chunk_build -ai "$HOME/arduino_ide" -au "$GITHUB_WORKSPACE" -fqbn "$FQBN" -t esp32 -p "$GITHUB_WORKSPACE" -i $BUILD_REM -m $BUILD_MOD elif [ "$BUILD_TYPE" = "build_rp2040" ]; then install_arduino install_rp2040 "$HOME/arduino_ide" From e24223e3d56fc34e4cd0b8820e0ba4fea58d1a65 Mon Sep 17 00:00:00 2001 From: FedericoBusero <35894905+FedericoBusero@users.noreply.github.com> Date: Wed, 24 Aug 2022 21:49:24 +0200 Subject: [PATCH 108/150] ESP32: Fix compilation of I2S in Arduino ESP32 core 1.0.6 (#565) --- src/AudioOutputI2S.cpp | 4 ++++ src/AudioOutputSPDIF.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index c4e0c3aa..621db592 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -88,7 +88,9 @@ bool AudioOutputI2S::SetPinout() return false; // Not allowed i2s_pin_config_t pins = { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) .mck_io_num = 0, // Unused +#endif .bck_io_num = bclkPin, .ws_io_num = wclkPin, .data_out_num = doutPin, @@ -229,8 +231,10 @@ bool AudioOutputI2S::begin(bool txDAC) .use_apll = use_apll, // Use audio PLL .tx_desc_auto_clear = true, // Silence on underflow .fixed_mclk = 0, // Unused +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, // Unused .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample +#endif }; audioLogger->printf("+%d %p\n", portNo, &i2s_config_dac); if (i2s_driver_install((i2s_port_t)portNo, &i2s_config_dac, 0, NULL) != ESP_OK) diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index 1d1ec2f3..1823b5d8 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -105,8 +105,10 @@ AudioOutputSPDIF::AudioOutputSPDIF(int dout_pin, int port, int dma_buf_count) .use_apll = true, // Audio PLL is needed for low clock jitter .tx_desc_auto_clear = true, // Silence on underflow .fixed_mclk = 0, // Unused +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, // Unused .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample +#endif }; if (i2s_driver_install((i2s_port_t)portNo, &i2s_config_spdif, 0, NULL) != ESP_OK) { audioLogger->println(F("ERROR: Unable to install I2S drivers")); @@ -151,7 +153,9 @@ bool AudioOutputSPDIF::SetPinout(int bclk, int wclk, int dout) { #if defined(ESP32) i2s_pin_config_t pins = { +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) .mck_io_num = 0, // unused +#endif .bck_io_num = bclk, .ws_io_num = wclk, .data_out_num = dout, From bf31f0f8be50199e60842cf9595387a2960ad5e5 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 31 Aug 2022 10:52:24 -0700 Subject: [PATCH 109/150] Update macros.h --- src/libflac/share/macros.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libflac/share/macros.h b/src/libflac/share/macros.h index 20b3ea56..514d633f 100644 --- a/src/libflac/share/macros.h +++ b/src/libflac/share/macros.h @@ -35,7 +35,7 @@ * print an error message if it fails (ie returns a value < 0). * * Ideally, a library should not print anything, but this macro is only used - * for things that extremely unlikely to fail, like `chown` to a previoulsy + * for things that extremely unlikely to fail, like `chown` to a previously * saved `uid`. */ From 93c4e3a15a28366d919d210d54c7a421dbadf444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E5=B8=85?= <770722922@qq.com> Date: Thu, 1 Sep 2022 01:54:19 +0800 Subject: [PATCH 110/150] Fix build support gcc8 for other arch (#567) --- examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino | 2 +- src/AudioGeneratorMIDI.cpp | 2 +- src/AudioGeneratorMIDI.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino index 38e12d34..aefb26b1 100644 --- a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino +++ b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino @@ -2,7 +2,7 @@ // Do not build on GCC8, GCC8 has a compiler bug -#if defined(ARDUINO_ARCH_RP2040) || (__GNUC__ == 8) +#if defined(ARDUINO_ARCH_RP2040) || ((__GNUC__ == 8) && (__XTENSA__)) void setup() {} void loop() {} #else diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index 1bb1cd3f..63dca2f4 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -58,7 +58,7 @@ #include "AudioGeneratorMIDI.h" -#if __GNUC__ == 8 +#if (__GNUC__ == 8) && (__XTENSA__) // Do not build, GCC8 has a compiler bug #else // __GNUC__ == 8 diff --git a/src/AudioGeneratorMIDI.h b/src/AudioGeneratorMIDI.h index 96b2dd63..62ede5e7 100644 --- a/src/AudioGeneratorMIDI.h +++ b/src/AudioGeneratorMIDI.h @@ -21,7 +21,7 @@ #ifndef _AUDIOGENERATORMIDI_H #define _AUDIOGENERATORMIDI_H -#if __GNUC__ == 8 +#if (__GNUC__ == 8) && (__XTENSA__) // Do not build, GCC8 has a compiler bug #else // __GNUC__ == 8 From a32362724380532812779810803f5eafc638b4ce Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 31 Aug 2022 10:54:49 -0700 Subject: [PATCH 111/150] Update pr-or-master-push.yml --- .github/workflows/pr-or-master-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index c4dbbae8..90ac5c10 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -134,5 +134,5 @@ jobs: - name: Run codespell uses: codespell-project/actions-codespell@master with: - skip: ./src/libmad,./src/libhelix-aac,./src/libopus + skip: ./src/libmad,./src/libhelix-aac,./src/libopus,./src/libflac/ ignore_words_list: ESP8266,esp8266,esp,dout,DOUT,ser,ans,inout,numer,hist From 72ed4f76ddb8a0078ce6d9a9efba1ccf094ba33e Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 1 Sep 2022 12:15:29 -0700 Subject: [PATCH 112/150] Update pr-or-master-push.yml --- .github/workflows/pr-or-master-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index 90ac5c10..db7453b8 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -134,5 +134,5 @@ jobs: - name: Run codespell uses: codespell-project/actions-codespell@master with: - skip: ./src/libmad,./src/libhelix-aac,./src/libopus,./src/libflac/ + skip: ./src/libmad,./src/libhelix-aac,./src/libopus,./src/libflac ignore_words_list: ESP8266,esp8266,esp,dout,DOUT,ser,ans,inout,numer,hist From f95f15fcb34e5fad061f0b657b8eac9bdd65a1a2 Mon Sep 17 00:00:00 2001 From: FedericoBusero <35894905+FedericoBusero@users.noreply.github.com> Date: Thu, 1 Sep 2022 21:16:14 +0200 Subject: [PATCH 113/150] I2S: register I2S object to platform failed (#568) ESP32: When calling destructor after stop, and then create a new object, then an error is shown "I2S: register I2S object to platform failed" because i2s_driver_uninstall had not been called. ESP8266 : i2s_end is not called when stopping, but i2sOn is false, resulting in new call i2s_rxtx_begin --- src/AudioOutputI2S.cpp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 621db592..919679d2 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -67,18 +67,7 @@ AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) AudioOutputI2S::~AudioOutputI2S() { - #ifdef ESP32 - if (i2sOn) { - audioLogger->printf("UNINSTALL I2S\n"); - i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver - } - #elif defined(ESP8266) - if (i2sOn) - i2s_end(); - #elif defined(ARDUINO_ARCH_RP2040) - stop(); - #endif - i2sOn = false; + stop(); } bool AudioOutputI2S::SetPinout() @@ -359,6 +348,10 @@ bool AudioOutputI2S::stop() #ifdef ESP32 i2s_zero_dma_buffer((i2s_port_t)portNo); + audioLogger->printf("UNINSTALL I2S\n"); + i2s_driver_uninstall((i2s_port_t)portNo); //stop & destroy i2s driver + #elif defined(ESP8266) + i2s_end(); #elif defined(ARDUINO_ARCH_RP2040) i2s.end(); #endif From 46b36574ed27544e1dd15daa204f1eb484e9a840 Mon Sep 17 00:00:00 2001 From: lovyan03 <42724151+lovyan03@users.noreply.github.com> Date: Mon, 5 Sep 2022 05:27:05 +0900 Subject: [PATCH 114/150] fix: Invalid data is assigned to the right channel when playing a mono MP3. (#559) --- src/AudioGeneratorMP3.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/AudioGeneratorMP3.cpp b/src/AudioGeneratorMP3.cpp index d962c9e0..8045d902 100644 --- a/src/AudioGeneratorMP3.cpp +++ b/src/AudioGeneratorMP3.cpp @@ -248,6 +248,10 @@ bool AudioGeneratorMP3::loop() running = false; goto done; } + if (lastChannels == 1) + { + lastSample[1] = lastSample[0]; + } } while (running && output->ConsumeSample(lastSample)); done: From 0b5da0e9ddc47808c3ace56dc6ef07b742023bd1 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 3 Jan 2023 17:08:56 -0800 Subject: [PATCH 115/150] Add PWMAudio support for the RP2040 (#597) Uses the RP2040 HW PWM generator to provide a stereo audio signal. --- examples/PlayMODFromPROGMEMToPWM/5steps.h | 11253 ++++++++++++++++ .../PlayMODFromPROGMEMToPWM.ino | 47 + keywords.txt | 1 + src/AudioGeneratorWAV.cpp | 4 +- src/AudioOutputPWM.cpp | 114 + src/AudioOutputPWM.h | 57 + src/ESP8266Audio.h | 1 + tests/common.sh | 6 +- 8 files changed, 11480 insertions(+), 3 deletions(-) create mode 100644 examples/PlayMODFromPROGMEMToPWM/5steps.h create mode 100644 examples/PlayMODFromPROGMEMToPWM/PlayMODFromPROGMEMToPWM.ino create mode 100644 src/AudioOutputPWM.cpp create mode 100644 src/AudioOutputPWM.h diff --git a/examples/PlayMODFromPROGMEMToPWM/5steps.h b/examples/PlayMODFromPROGMEMToPWM/5steps.h new file mode 100644 index 00000000..312e4efa --- /dev/null +++ b/examples/PlayMODFromPROGMEMToPWM/5steps.h @@ -0,0 +1,11253 @@ +const unsigned char steps_mod[] = { + 0x35, 0x5f, 0x73, 0x74, 0x65, 0x70, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x20, 0x76, 0x69, + 0x6e, 0x6e, 0x69, 0x65, 0x2f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x62, 0x61, + 0x6c, 0x6c, 0x73, 0x20, 0x20, 0x00, 0x03, 0xed, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0xd1, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe1, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x63, 0x74, 0x20, 0x6d, + 0x65, 0x3a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, + 0x05, 0xf4, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x20, 0x70, 0x61, 0x61, + 0x6c, 0x20, 0x67, 0x72, 0x61, 0x6e, 0x75, 0x6d, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x06, 0x6a, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x20, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x20, 0x73, 0x74, 0x61, + 0x6e, 0x67, 0x73, 0x20, 0x67, 0x74, 0x20, 0x36, 0x20, 0x20, 0x20, 0x00, + 0x03, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x20, 0x31, 0x37, 0x37, + 0x37, 0x20, 0x68, 0x61, 0x6c, 0x64, 0x65, 0x6e, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x06, 0x52, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x20, 0x6e, 0x6f, 0x72, 0x77, 0x61, 0x79, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, + 0x05, 0xef, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x30, 0x0c, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x01, 0x00, 0x40, 0x00, 0x01, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x50, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x61, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x93, 0x00, 0x40, 0x04, 0x08, + 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x70, 0x00, 0x40, 0x00, 0x63, 0x02, 0xf6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd0, 0x00, 0x40, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xcc, 0x00, 0x40, 0x00, 0xc2, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x20, 0x05, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x00, 0x00, 0x40, 0x0c, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x22, 0x7f, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x10, 0x00, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x1b, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4d, 0x2e, 0x4b, 0x2e, 0x00, 0xd6, 0x5c, 0x00, 0x00, 0x00, 0x0f, 0x0f, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x0e, 0x92, 0x00, 0xf0, 0x9c, 0x00, 0x00, 0x00, 0x0f, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x28, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x5c, 0x10, 0x00, 0xa0, 0x5c, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0xa0, 0x5c, 0x10, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x06, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x20, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xdc, 0x20, + 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0x00, 0x0c, 0x0a, + 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0xbc, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, + 0x00, 0xe2, 0x9c, 0x08, 0x01, 0x53, 0xac, 0x00, 0x10, 0xd6, 0x0c, 0x20, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0xd6, 0x03, 0x03, 0x00, 0x00, 0x0a, 0x10, + 0x01, 0xac, 0xfc, 0x11, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x04, 0xe2, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, 0x10, 0xd6, 0x0c, 0x10, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, + 0x01, 0xac, 0xec, 0x10, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x7f, 0x7c, 0x20, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0xd6, 0x0e, 0xc1, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x0e, 0xa2, 0x10, 0xd6, 0x0c, 0x20, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, + 0x10, 0xd6, 0x0c, 0x20, 0x00, 0xa0, 0x6c, 0x10, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, 0x10, 0xd6, 0x0c, 0x10, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0xf0, 0xdc, 0x20, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0xbc, 0x30, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0xf0, 0xec, 0x10, + 0x00, 0xa0, 0x1f, 0x08, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, + 0x10, 0xd6, 0x0a, 0x04, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0xd6, 0x0e, 0xc2, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, + 0x10, 0xd6, 0x0c, 0x20, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x5c, 0x10, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa2, 0x01, 0xe0, 0xfc, 0x10, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x02, 0x01, + 0x00, 0x00, 0x02, 0x01, 0x10, 0xd6, 0x0c, 0x20, 0x00, 0xa0, 0x1f, 0x08, + 0x00, 0xd6, 0x09, 0x05, 0x01, 0x53, 0x09, 0x05, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x10, 0xd6, 0x0c, 0x10, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0xd6, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x02, 0x00, 0x00, 0x0e, 0xb1, 0x01, 0xac, 0x03, 0xf0, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0xe2, 0x03, 0xf0, 0x01, 0x68, 0x03, 0xf9, + 0x01, 0x40, 0x01, 0x01, 0x00, 0xa0, 0x5c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x02, 0x01, 0x40, 0x03, 0x03, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x01, 0x53, 0xec, 0x11, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xfe, 0x99, 0x03, + 0x01, 0x7d, 0xac, 0x20, 0x10, 0xf0, 0x0c, 0x20, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0xf0, 0x03, 0xf0, 0x00, 0x00, 0x0e, 0x11, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xf0, 0xfc, 0x21, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0e, 0xb1, 0x10, 0xf0, 0x0c, 0x10, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0xf0, 0xdc, 0x10, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x5c, 0x20, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0e, 0xb1, 0x01, 0x68, 0xec, 0x10, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0e, 0xb1, + 0x10, 0xf0, 0x0c, 0x20, 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x20, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x0e, 0xb1, 0x10, 0xf0, 0x0c, 0x20, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0e, 0xb0, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x0c, 0x20, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x6c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xf0, 0x0c, 0x20, 0x00, 0xa0, 0x5c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xf0, 0x0c, 0x20, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x0c, 0x30, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0xd6, 0x50, 0x00, 0x00, 0x00, 0x0a, 0x02, + 0x00, 0x00, 0x0a, 0x02, 0x00, 0xf0, 0xfc, 0x20, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0xe2, 0x03, 0xd0, 0x01, 0x68, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x5c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xf0, 0x0c, 0x20, 0x00, 0x7f, 0x7c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x03, 0xf0, 0x00, 0xd6, 0x5c, 0x30, + 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xe2, 0x9c, 0x20, 0x01, 0x53, 0xac, 0x18, + 0x10, 0xd6, 0x0c, 0x30, 0x00, 0xa0, 0x60, 0x00, 0x00, 0xd6, 0x03, 0x00, + 0x00, 0x00, 0x0a, 0x01, 0x01, 0xac, 0xfc, 0x1f, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0xac, 0xec, 0x10, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0x03, 0xd0, 0x00, 0xa0, 0x8c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xec, 0x0f, + 0x00, 0x7f, 0x7c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x0a, 0x20, 0x00, 0xa0, 0x8c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x20, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0xac, 0xec, 0x30, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xec, 0x10, 0x00, 0xa0, 0x6c, 0x10, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0x0e, 0xc1, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x40, 0xdc, 0x30, 0x00, 0xa0, 0x8c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x2e, 0x03, 0x06, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xdc, 0x10, + 0x00, 0xa0, 0xbc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x10, 0xd6, 0x04, 0xe4, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x04, 0xe8, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xea, 0x0f, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xd6, 0xdc, 0x1f, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0xec, 0x10, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x20, + 0x00, 0xa0, 0x8c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xd6, 0x03, 0xf0, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0xd6, 0x03, 0x07, 0x01, 0x53, 0x03, 0x0f, + 0x00, 0xd6, 0xdc, 0x30, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0xda, 0x0f, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0xde, 0xc1, 0x00, 0xa0, 0x80, 0x00, 0x00, 0xe2, 0x03, 0xf0, + 0x01, 0x68, 0x03, 0x02, 0x00, 0xe2, 0xdc, 0x21, 0x00, 0xaa, 0x5c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0xaa, 0x5c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x04, 0xed, 0x00, 0xa0, 0x8c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x1f, 0x08, + 0x00, 0xfe, 0x09, 0x03, 0x01, 0x7d, 0xac, 0x20, 0x00, 0xf0, 0xec, 0x30, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0xf0, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xda, 0x0f, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x0c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x0c, 0x20, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0xdc, 0x10, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x02, 0x00, 0xa0, 0x8c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdc, 0x10, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0e, 0xc1, + 0x00, 0xd6, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0d, 0xec, 0x10, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xec, 0x10, 0x00, 0xa0, 0xbc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x30, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xec, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0x8c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x01, 0x40, 0xec, 0x10, 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x01, 0x0d, 0xec, 0x20, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xf0, 0xdc, 0x10, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x01, 0xe0, 0xec, 0x20, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xf0, 0xdc, 0x20, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xa0, 0x6c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0a, 0x50, 0x00, 0xa0, 0x8c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x78, 0x0a, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x0a, 0x02, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x87, 0xdc, 0x10, 0x00, 0xa0, 0x1f, 0x08, + 0x00, 0x00, 0x9c, 0x20, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x01, 0xe0, 0xfc, 0x2f, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x10, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0xb4, 0xac, 0x05, 0x00, 0xf0, 0xdc, 0x26, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0xe2, 0x03, 0xf0, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x5c, 0x09, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0xf0, 0xf0, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x10, 0x10, 0x87, 0x0c, 0x10, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x0a, 0x10, + 0x01, 0xc5, 0xfc, 0x20, 0x00, 0xa0, 0xcf, 0x08, 0x00, 0xe2, 0x9c, 0x20, + 0x00, 0xaa, 0xac, 0x30, 0x01, 0xac, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x03, 0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0xd6, 0x0c, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xf0, 0xdc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xfc, 0x30, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0a, 0x10, 0x10, 0xd6, 0x0c, 0x20, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0xd6, 0xec, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0a, 0x20, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x60, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0xdc, 0x20, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x1d, 0xdc, 0x1a, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0xac, 0x0e, 0xc1, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xdc, 0x30, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0x03, 0x36, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x68, 0xdc, 0x18, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xd6, 0x0c, 0x30, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x04, 0x03, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0xac, 0xea, 0x0f, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0xec, 0x10, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x0a, 0x20, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0x03, 0xf0, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xdc, 0x30, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0xda, 0x0f, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0xde, 0xc1, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0xe2, 0x03, 0xf0, 0x00, 0xb4, 0x03, 0xf2, 0x00, 0xe2, 0xdc, 0x21, + 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x04, 0xed, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xfe, 0x90, 0x00, 0x00, 0xbe, 0xac, 0x20, + 0x00, 0xf0, 0xec, 0x30, 0x00, 0xa0, 0xbc, 0x10, 0x00, 0xf0, 0x93, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x09, 0x10, 0x00, 0x7f, 0x7c, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xec, 0x10, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0d, 0xdc, 0x10, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdc, 0x10, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0xec, 0x10, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xec, 0x20, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xec, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xec, 0x10, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0xec, 0x20, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xdc, 0x10, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xec, 0x20, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdc, 0x20, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x0c, 0x10, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xa0, 0x5c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xfc, 0x10, 0x00, 0xa0, 0x0e, 0x93, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0xdc, 0x10, + 0x00, 0xa0, 0x1c, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0a, 0x0f, 0x00, 0xbe, 0x4c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x0c, 0x24, + 0x00, 0xaa, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0xbe, 0x40, 0x00, 0x00, 0xe2, 0x03, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xfc, 0x20, 0x00, 0xbe, 0xbc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xf0, 0x00, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xfc, 0x20, 0x00, 0xa0, 0xcd, 0x00, 0x00, 0xd6, 0x90, 0x00, + 0x00, 0xaa, 0xac, 0x30, 0x10, 0xd6, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x04, 0xea, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0a, 0x03, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xfc, 0x30, 0x00, 0x7f, 0x7c, 0x20, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xf0, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xd6, 0xfc, 0x10, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xea, 0x0f, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x20, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0xac, 0xfc, 0x30, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xe2, 0x0f, 0x00, 0xd6, 0x3c, 0x20, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0xdc, 0x30, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x1d, 0xdc, 0x10, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0x0e, 0xc1, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xdc, 0x30, + 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x40, 0x03, 0x06, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xdc, 0x10, 0x00, 0xbe, 0xbc, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xd6, 0x0c, 0x20, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x0c, 0x10, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xea, 0x0f, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xdc, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xf0, 0xec, 0x10, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x20, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0x03, 0xf0, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xdc, 0x30, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0xda, 0x0f, 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0xde, 0xc1, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0xe2, 0x03, 0xf0, 0x00, 0xb4, 0x0e, 0xb2, + 0x00, 0xe2, 0xdc, 0x21, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x04, 0xed, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xfe, 0x90, 0x00, + 0x00, 0xbe, 0xac, 0x20, 0x00, 0xf0, 0xec, 0x30, 0x00, 0xa0, 0xbc, 0x10, + 0x00, 0xf0, 0x93, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x09, 0x10, + 0x00, 0x7f, 0x7c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xec, 0x10, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0xdc, 0x10, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xdc, 0x10, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0d, 0xec, 0x10, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xec, 0x20, 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xec, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xec, 0x10, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x0d, 0xec, 0x20, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdc, 0x10, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0xec, 0x20, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xdc, 0x20, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x40, 0x00, 0xa0, 0x8c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0a, 0x0f, 0x00, 0xa0, 0x0e, 0x93, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x87, 0xdc, 0x10, 0x00, 0xa0, 0x1c, 0x24, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x20, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x78, 0x0a, 0x0f, + 0x00, 0xa0, 0x8c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x7d, 0xec, 0x10, 0x00, 0xbe, 0x4c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x00, 0xbe, 0x4c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xec, 0x40, + 0x00, 0xbe, 0x4c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x53, 0x03, 0x30, 0x00, 0x00, 0x0d, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xcf, 0x08, 0x00, 0xaa, 0x9c, 0x30, 0x00, 0xfe, 0xac, 0x30, + 0x01, 0x40, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x03, 0x03, + 0x00, 0x00, 0x0a, 0x01, 0x10, 0xa0, 0x0c, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xfc, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xa0, 0xdc, 0x20, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0xec, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x0a, 0x20, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x60, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xb4, 0xdc, 0x20, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xfc, 0x30, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x68, 0xfc, 0x40, 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xfa, 0x0f, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xdc, 0x20, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x40, 0xfc, 0x20, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xea, 0x0f, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x40, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xb4, 0xec, 0x10, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x20, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xa0, 0x03, 0xf0, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xa0, 0xdc, 0x30, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0xda, 0x0f, 0x00, 0xbe, 0x4c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0xde, 0xc1, 0x00, 0xbe, 0x40, 0x00, 0x00, 0xaa, 0x03, 0xf0, + 0x01, 0x0d, 0x03, 0xf2, 0x00, 0xaa, 0xdc, 0x21, 0x00, 0xbe, 0xbc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x04, 0xed, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x1f, 0x08, + 0x00, 0xbe, 0x9c, 0x29, 0x01, 0x1d, 0xac, 0x20, 0x00, 0xb4, 0xec, 0x30, + 0x00, 0xa0, 0xbc, 0x10, 0x00, 0xb4, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0x09, 0x10, 0x00, 0x7f, 0x7c, 0x30, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xec, 0x10, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x02, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xdc, 0x10, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xec, 0x10, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xec, 0x20, 0x00, 0xd6, 0x3c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xec, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xec, 0x10, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xec, 0x20, 0x00, 0xbe, 0xbc, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xdc, 0x10, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xec, 0x20, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xdc, 0x20, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xfc, 0x20, + 0x00, 0xa0, 0x0e, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xd0, 0x00, 0x00, 0xa0, 0x1c, 0x24, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xe2, 0x0f, + 0x00, 0xa0, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xac, 0xfc, 0x20, 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xec, 0x20, 0x00, 0xaa, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0x05, 0x02, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xb4, 0xdc, 0x22, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x53, 0xf0, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb4, 0x0c, 0x20, + 0x00, 0xa0, 0xcd, 0x00, 0x00, 0xaa, 0x9c, 0x30, 0x00, 0xfe, 0xac, 0x30, + 0x10, 0xa0, 0x04, 0xe4, 0x00, 0x00, 0x0f, 0x08, 0x00, 0xa0, 0x03, 0xf3, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x40, 0xf0, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0xfc, 0x30, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xa0, 0x0c, 0x20, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xa0, 0xec, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x20, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0a, 0x60, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xb4, 0xdc, 0x20, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xfc, 0x30, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xfc, 0x40, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xfa, 0x0f, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x10, 0xb4, 0x0c, 0x20, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xfc, 0x20, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x40, 0xea, 0x0f, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xfc, 0x2f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xec, 0x20, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xb4, 0xec, 0x30, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0x03, 0xf0, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0xdc, 0x20, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0xde, 0xc1, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0xaa, 0x03, 0xf0, 0x01, 0x0d, 0x03, 0xf2, 0x00, 0xaa, 0xdc, 0x21, + 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x04, 0xed, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb2, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xbe, 0x9c, 0x29, 0x01, 0x1d, 0xac, 0x20, + 0x00, 0xb4, 0xec, 0x30, 0x00, 0xa0, 0xbc, 0x10, 0x00, 0xb4, 0x03, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0x09, 0x10, 0x00, 0x7f, 0x7c, 0x30, + 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xec, 0x10, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xca, 0xdc, 0x10, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x02, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xdc, 0x10, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0xec, 0x10, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xec, 0x20, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x04, 0xe8, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x04, 0xec, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xf0, 0xec, 0x10, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xca, 0xec, 0x20, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0xb4, 0xdc, 0x10, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x01, 0x68, 0xec, 0x20, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xb4, 0xdc, 0x20, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x01, 0x68, 0xdc, 0x20, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xa0, 0x8c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x01, 0x68, 0xec, 0x20, 0x00, 0xa0, 0x0e, 0x93, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x01, 0x40, 0xdc, 0x10, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xa0, 0x03, 0x30, + 0x00, 0xa0, 0x1c, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x01, 0x53, 0xec, 0x17, 0x00, 0xa0, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xaa, 0x03, 0xf0, 0x00, 0xa0, 0x8c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x01, 0x68, 0xec, 0x20, + 0x00, 0xbe, 0x4c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0xb4, 0x03, 0xf0, 0x00, 0xbe, 0x4c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x01, 0x7d, 0xec, 0x1a, 0x00, 0xbe, 0x4c, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xbe, 0x03, 0xf0, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x01, 0x94, 0xec, 0x1a, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xca, 0x03, 0xf0, 0x00, 0xa0, 0xc0, 0x00, + 0x00, 0xd6, 0x9f, 0x08, 0x00, 0x00, 0x0a, 0x01, 0x10, 0xd6, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x04, 0x05, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x06, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x7c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x20, 0x00, 0xa0, 0x50, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, + 0x00, 0xa0, 0x8c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0xa0, 0x8c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x70, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xfc, 0x20, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x0c, 0x30, 0x00, 0xa0, 0x8c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xac, 0xfc, 0x20, 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x00, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x20, 0x00, 0xd6, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0x93, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x50, 0x00, + 0x00, 0xd6, 0x3c, 0x30, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x5c, 0x20, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x0a, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x07, 0x00, 0xd6, 0x3c, 0x08, + 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x10, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x5c, 0x20, 0x00, 0xd6, 0x3c, 0x28, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x5c, 0x08, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x20, + 0x00, 0xa0, 0xc0, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x15, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xec, 0x30, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0d, 0x00, 0xd6, 0x3c, 0x08, 0x00, 0x00, 0x9a, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0d, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x9a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x20, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x0c, 0x20, 0x00, 0x7f, 0x7c, 0x20, 0x00, 0x00, 0x9a, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xda, 0x0f, 0x00, 0x7f, 0x2c, 0x06, + 0x00, 0x00, 0x9a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xdc, 0x20, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xac, 0xec, 0x10, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe1, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe3, 0x30, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xec, 0x20, 0x00, 0xa0, 0xb0, 0x00, 0x00, 0x00, 0x9a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x9a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0xfc, 0x20, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x10, 0x00, 0xa0, 0xbc, 0x20, + 0x00, 0x00, 0x9a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xda, 0x0f, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x9a, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0xec, 0x20, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x0a, 0x20, 0x00, 0x00, 0x9a, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0xbe, 0x0e, 0x93, + 0x00, 0x00, 0x9a, 0x06, 0x11, 0x1d, 0x1c, 0x10, 0x01, 0x68, 0xda, 0x0f, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x06, 0x00, 0x00, 0x0c, 0x00, + 0x10, 0xa0, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x14, 0x00, 0x00, 0x9a, 0x06, + 0x10, 0xf0, 0x1c, 0x12, 0x10, 0xa0, 0x03, 0x02, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x9a, 0x06, 0x00, 0x00, 0x0c, 0x02, 0x10, 0xb4, 0x0c, 0x10, + 0x00, 0xbe, 0x4c, 0x30, 0x00, 0x00, 0x9a, 0x06, 0x10, 0xd6, 0x1c, 0x10, + 0x10, 0xa0, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x06, + 0x00, 0x00, 0x0c, 0x00, 0x10, 0xa0, 0x03, 0x02, 0x00, 0xa0, 0xc0, 0x00, + 0x00, 0xd6, 0x9f, 0x02, 0x10, 0xca, 0x1c, 0x1a, 0x10, 0xd6, 0x0c, 0x30, + 0x00, 0x00, 0x0f, 0x0a, 0x00, 0x00, 0x04, 0xe1, 0x10, 0xbe, 0x10, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x0f, 0x04, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x00, 0xd6, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x0c, 0x08, 0x10, 0xbe, 0x1c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x11, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x99, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0xd6, 0x99, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xf0, 0x1c, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x10, 0x00, + 0x10, 0xf0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0xb4, 0x0e, 0xd3, 0x00, 0xd6, 0x03, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x0f, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x0a, 0x01, 0x10, 0xb4, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0xaa, 0x0e, 0xd2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xaa, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0xd6, 0x9c, 0x20, 0x10, 0xaa, 0x1c, 0x15, 0x10, 0xd6, 0x0f, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x10, 0xa0, 0x1c, 0x20, + 0x00, 0x00, 0x0f, 0x06, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x06, 0x10, 0xa0, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x1d, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0f, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xaa, 0x1c, 0x0a, 0x10, 0xd6, 0x0c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x0f, 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xb4, 0x1c, 0x14, 0x10, 0xaa, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x00, 0xa0, 0x03, 0xd3, + 0x00, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x1c, 0x10, 0x00, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xca, 0x1c, 0x10, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xf0, 0x1c, 0x1a, + 0x00, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xfe, 0x1c, 0x10, 0x00, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xf0, 0x94, 0xe1, + 0x11, 0x0d, 0x10, 0x00, 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x7c, 0x07, 0x00, 0x00, 0x9a, 0x02, + 0x10, 0xb4, 0x1c, 0x10, 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x0c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, + 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x99, 0x19, 0x00, 0x00, 0x0e, 0x11, 0x10, 0xb4, 0x1c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0xf0, 0x99, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, 0x11, 0x0d, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb4, 0x0c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xb4, 0x1c, 0x07, 0x11, 0x0d, 0x1c, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xb4, 0x1c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x11, 0x0d, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe3, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0xf0, 0x9c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xfc, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xa0, 0x1c, 0x10, 0x01, 0x40, 0xfc, 0x1a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x97, 0x1e, 0xd3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0x8f, 0x10, 0x00, 0x10, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xa0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x10, 0x97, 0x1e, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x8f, 0x1c, 0x10, 0x10, 0x8f, 0x1e, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0x87, 0x1c, 0x10, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0x8f, 0x1c, 0x20, + 0x10, 0x87, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xb0, 0x00, + 0x00, 0x00, 0x94, 0xe1, 0x10, 0x97, 0x1c, 0x06, 0x01, 0x68, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x10, 0xa0, 0x1c, 0x10, 0x10, 0xb4, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x8f, 0x03, 0xd0, + 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xb4, 0x1c, 0x10, 0x01, 0x68, 0xec, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0xa0, 0x03, 0xf0, 0x10, 0xb4, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x1c, 0x10, + 0x10, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xf0, 0x1c, 0x08, 0x01, 0x1d, 0xde, 0xc2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xd6, 0x1c, 0x10, 0x00, 0xf0, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xca, 0x1c, 0x05, + 0x01, 0xac, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0xd6, 0x94, 0xe1, 0x10, 0xca, 0x1f, 0x01, 0x10, 0xd6, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, 0x10, 0xbe, 0x1f, 0x07, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x00, 0x0f, 0x04, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xac, 0xfc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xbe, 0x1c, 0x0a, + 0x00, 0x00, 0x9a, 0x02, 0x11, 0x1d, 0x1c, 0x10, 0x00, 0xd6, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9c, 0x10, + 0x00, 0x00, 0x0c, 0x06, 0x11, 0x1d, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x99, 0x19, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0xd6, 0x99, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x1c, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x0a, 0x30, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x30, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0xb4, 0x0e, 0xd3, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x0a, 0x03, + 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0xaa, 0x0e, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x02, 0x00, 0xd6, 0x9c, 0x20, + 0x10, 0xa0, 0x10, 0x00, 0x10, 0xd6, 0x04, 0xe2, 0x00, 0x00, 0x0f, 0x06, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xa0, 0x6f, 0x04, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x0e, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x0c, 0x0a, 0x10, 0xa0, 0x1c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xbe, 0x1c, 0x10, 0x00, 0xf0, 0xe4, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xca, 0x1c, 0x10, 0x00, 0xd6, 0xe3, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xd6, 0x1c, 0x10, 0x00, 0x00, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, 0x10, 0xf0, 0x1c, 0x0a, + 0x01, 0xac, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x02, + 0x00, 0x00, 0x04, 0xe4, 0x10, 0xca, 0x10, 0x00, 0x10, 0xf0, 0x1c, 0x0a, + 0x00, 0x00, 0x0f, 0x06, 0x00, 0x00, 0x04, 0xe8, 0x10, 0xbe, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x6f, 0x04, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x0e, 0x11, 0x10, 0xbe, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0x8f, 0x1c, 0x10, + 0x10, 0xf0, 0x1c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x1c, 0x10, 0x10, 0x8f, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xbe, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x11, 0x1d, 0x1c, 0x10, + 0x10, 0xd6, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xf0, 0x1c, 0x20, 0x11, 0x1d, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xe2, 0x1c, 0x14, 0x10, 0xf0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xf0, 0x94, 0xe1, 0x10, 0xd6, 0x10, 0x00, + 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x01, 0x40, 0xfc, 0x20, + 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x1c, 0x0a, 0x00, 0x00, 0x9a, 0x02, 0x11, 0x40, 0x1c, 0x10, + 0x10, 0xa0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x99, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xec, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0xf0, 0x99, 0x10, 0x10, 0xd6, 0x1c, 0x0a, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x11, 0x40, 0x1c, 0x0a, + 0x01, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0f, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x0c, 0x05, 0x01, 0x68, 0xdc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xd6, 0x1c, 0x06, + 0x01, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe3, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x03, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x11, 0x40, 0x1c, 0x10, 0x01, 0x68, 0xec, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xaa, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe3, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0xfe, 0x9c, 0x20, 0x11, 0x53, 0x10, 0x00, 0x00, 0x00, 0x04, 0xe5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x53, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xe2, 0x1c, 0x10, 0x01, 0x68, 0xec, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0xbe, 0x8c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x01, 0x0d, 0x9a, 0x04, 0x11, 0x68, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x0c, 0x14, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xf0, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x01, 0x1d, 0x9a, 0x04, 0x11, 0x7d, 0x1c, 0x13, 0x01, 0x7d, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbe, 0xc3, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xfe, 0x1c, 0x0a, + 0x10, 0xf0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc0, 0x00, + 0x10, 0xd6, 0x44, 0xe1, 0x10, 0xbe, 0x1c, 0x1a, 0x10, 0xd6, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x02, 0x00, 0xa0, 0x60, 0x00, 0x10, 0x00, 0x4c, 0x19, + 0x00, 0x00, 0x01, 0x01, 0x00, 0xd6, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x10, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x0c, 0x08, + 0x10, 0xbe, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, 0x00, 0xbe, 0x4c, 0x08, + 0x10, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x09, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x30, 0x10, 0x00, 0x44, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, 0x10, 0x00, 0x4a, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x10, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, + 0x10, 0x00, 0x4c, 0x20, 0x10, 0xd6, 0x1c, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0xbe, 0x40, 0x00, 0x10, 0x00, 0x4c, 0x1a, + 0x10, 0xbe, 0x10, 0x00, 0x10, 0xf0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x07, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x18, 0x10, 0x00, 0x4c, 0x15, 0x00, 0xb4, 0x0e, 0xd3, + 0x00, 0xd6, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0f, 0x00, 0x7f, 0x7c, 0x10, + 0x10, 0x00, 0x4c, 0x10, 0x00, 0x00, 0x0a, 0x01, 0x10, 0xb4, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x06, 0x00, 0xaa, 0x0e, 0xd2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0xd6, 0x9c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xaa, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0xd6, 0x9c, 0x20, 0x10, 0xaa, 0x1c, 0x15, + 0x10, 0xd6, 0x0f, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x10, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x0f, 0x06, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x10, 0xa0, 0x1c, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x1d, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x0c, 0x10, 0x10, 0xd6, 0x0c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x0f, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xaa, 0x1c, 0x0a, + 0x10, 0xd6, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0f, 0x00, 0xbe, 0x4c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xb4, 0x1c, 0x14, 0x10, 0xaa, 0x1c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0xa0, 0x03, 0xd3, 0x00, 0xb4, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x1c, 0x10, + 0x00, 0xa0, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xb4, 0x1c, 0x10, 0x00, 0xbe, 0x0c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xf0, 0x1c, 0x1a, 0x00, 0xb4, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xfe, 0x1c, 0x10, + 0x00, 0xf0, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0xf0, 0x94, 0xe1, 0x11, 0x0d, 0x1c, 0x1a, 0x10, 0xa0, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x7c, 0x07, + 0x00, 0x00, 0x9a, 0x02, 0x00, 0xb4, 0x0c, 0x10, 0x01, 0x40, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9c, 0x10, + 0x00, 0x00, 0x0c, 0x0a, 0x11, 0x0d, 0x1c, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x99, 0x19, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0xf0, 0x99, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x11, 0x0d, 0x1c, 0x0a, 0x10, 0xb4, 0x1c, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x0c, 0x0a, + 0x10, 0xa0, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfa, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xb4, 0x1c, 0x03, + 0x10, 0xa0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xa0, 0x1c, 0x10, + 0x01, 0x68, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x97, 0x1c, 0x0a, + 0x00, 0x00, 0x04, 0xe3, 0x00, 0xa0, 0x10, 0x00, 0x00, 0xf0, 0x9c, 0x20, + 0x10, 0x8f, 0x10, 0x00, 0x01, 0x68, 0xf4, 0xe5, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x10, 0x87, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0x87, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0x78, 0x1c, 0x0a, 0x01, 0x68, 0xec, 0x12, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0x7f, 0x1c, 0x10, 0x01, 0x40, 0xe3, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0x87, 0x1c, 0x20, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0xb0, 0x00, 0x00, 0x00, 0x94, 0xe1, 0x00, 0x78, 0x03, 0xf0, + 0x01, 0x68, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x04, 0xe4, 0x10, 0x8f, 0x10, 0x00, 0x01, 0x40, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x10, 0xb4, 0x1c, 0x10, 0x00, 0x00, 0x01, 0x02, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xe3, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xd6, 0x1c, 0x10, 0x01, 0x68, 0xec, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xa0, 0x1c, 0x10, 0x10, 0xd6, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x00, 0xbe, 0x0e, 0xd3, + 0x00, 0xd6, 0xde, 0xc2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x0c, 0x06, 0x10, 0xf0, 0x0c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0xf0, 0x0e, 0xd2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xe2, 0x0c, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xd6, 0x94, 0xe1, 0x10, 0xbe, 0x1c, 0x15, + 0x10, 0xd6, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x99, 0x19, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xbe, 0x1c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x05, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0xd6, 0x99, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x10, 0xca, 0x10, 0x00, 0x01, 0xac, 0xfc, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xca, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xd6, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xf0, 0x1c, 0x05, 0x10, 0xd6, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xd6, 0x1c, 0x0a, 0x01, 0x40, 0xef, 0x02, 0x00, 0x00, 0x0f, 0x06, + 0x00, 0x00, 0x0a, 0x04, 0x10, 0xca, 0x1c, 0x10, 0x00, 0x00, 0x01, 0x02, + 0x00, 0xbe, 0x4f, 0x04, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xd6, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xf0, 0x1c, 0x0a, 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x1c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x02, + 0x00, 0xd6, 0x9c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x04, 0xe2, + 0x00, 0x00, 0x0f, 0x06, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x6f, 0x04, 0x00, 0x00, 0x9a, 0x04, + 0x10, 0xca, 0x1c, 0x10, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xd6, 0x1c, 0x0a, + 0x10, 0xca, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xf0, 0x1c, 0x05, 0x00, 0xf0, 0xe4, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x97, 0x10, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x8f, 0x10, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0xe3, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x1c, 0x10, 0x00, 0x00, 0x02, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x1f, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x10, 0xd6, 0x10, 0x00, 0x01, 0xac, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x02, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x06, 0x00, 0x00, 0x04, 0xe5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x6f, 0x04, + 0x00, 0x00, 0x9a, 0x08, 0x10, 0xa0, 0x1c, 0x12, 0x10, 0xd6, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x02, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x0f, 0x06, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0xca, 0x0e, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4f, 0x04, + 0x00, 0x00, 0x9a, 0x04, 0x10, 0xbe, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x04, 0x10, 0xca, 0x1c, 0x10, + 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0xca, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xf0, 0x94, 0xe1, + 0x10, 0xd6, 0x10, 0x00, 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x7c, 0x07, 0x00, 0x00, 0x9a, 0x02, + 0x11, 0x40, 0x1c, 0x10, 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x99, 0x19, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0xf0, 0x99, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, 0x10, 0xd6, 0x1c, 0x06, + 0x11, 0x40, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x0c, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfa, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x11, 0x40, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x9a, 0x04, 0x11, 0x2e, 0x1c, 0x10, + 0x10, 0xb4, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x9c, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x0c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x9a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x03, 0xd0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xd6, 0x9c, 0x20, 0x11, 0x1d, 0x1c, 0x0a, + 0x10, 0x8f, 0x0c, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe3, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x0c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0a, + 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x97, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0x9c, 0x10, 0x01, 0x2e, 0x00, 0x00, 0x10, 0xa0, 0x0c, 0x20, + 0x00, 0xa0, 0x6f, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x01, 0x1d, 0x9c, 0x10, 0x01, 0x40, 0x00, 0x00, + 0x10, 0xb4, 0x0c, 0x10, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, + 0x01, 0x40, 0x9c, 0x10, 0x00, 0xfe, 0xac, 0x10, 0x10, 0xd6, 0x0c, 0x10, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xd6, 0x9c, 0x12, + 0x01, 0x53, 0xac, 0x12, 0x01, 0x1d, 0xec, 0x10, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x48, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x08, 0x01, 0x40, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x0c, 0x10, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x1d, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x11, 0x1d, 0x1c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xbe, 0x1c, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xca, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, + 0x00, 0xd6, 0x9c, 0x12, 0x10, 0xd6, 0x1c, 0x10, 0x01, 0x1d, 0xec, 0x10, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x14, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xf0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x11, 0x1d, 0x1c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x01, 0x40, 0x9c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x10, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x1d, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x02, 0x10, 0xca, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8e, 0xd6, 0x00, 0x00, 0x0f, 0x0e, + 0x10, 0xbe, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x0f, 0x08, 0x10, 0xb4, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xaa, 0x1c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xaa, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0xb4, 0x1c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x03, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xbe, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x11, 0x1d, 0x1c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xf0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x1d, 0x1c, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xd6, 0x9c, 0x12, 0x10, 0xd6, 0x1c, 0x10, + 0x01, 0x1d, 0xec, 0x10, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x1d, 0x1c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x40, 0x1c, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x40, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, 0x1d, 0x1c, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x0c, 0x02, 0x00, 0x00, 0x0c, 0x0a, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xaa, 0x5c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x0e, 0x93, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xaa, 0x5c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x5c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x6c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x5c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x5c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x5c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, + 0x01, 0x40, 0x9c, 0x10, 0x11, 0x40, 0x4c, 0x00, 0x10, 0xd6, 0x0c, 0x10, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x01, 0x2e, 0x0c, 0x12, + 0x10, 0xca, 0x4c, 0x0a, 0x10, 0xca, 0x0c, 0x10, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x01, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x05, + 0x01, 0x0d, 0xec, 0x10, 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x0e, 0xa1, + 0x10, 0xe2, 0x4c, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xbe, 0x4c, 0x0a, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0xbc, 0x10, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xa0, 0x1f, 0x08, 0x01, 0x2e, 0x9c, 0x17, 0x10, 0xe2, 0x4c, 0x08, + 0x00, 0xfe, 0xec, 0x24, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x53, 0xec, 0x10, + 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, + 0x01, 0x0d, 0x9c, 0x22, 0x10, 0xb4, 0x4c, 0x14, 0x01, 0x68, 0xec, 0x20, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x0a, 0x00, 0x00, 0x0c, 0x10, + 0x00, 0x00, 0x0c, 0x10, 0x01, 0x0d, 0xec, 0x20, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xfe, 0x9c, 0x18, + 0x11, 0x53, 0x4c, 0x16, 0x00, 0xfe, 0xec, 0x24, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xd6, 0x9c, 0x22, 0x11, 0x40, 0x4c, 0x0a, + 0x01, 0x68, 0xec, 0x20, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, + 0x00, 0xf0, 0x9c, 0x18, 0x10, 0xf0, 0x4c, 0x15, 0x01, 0x0d, 0xec, 0x24, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xec, 0x20, 0x00, 0xa0, 0x8c, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x7c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x0e, 0xc1, + 0x00, 0x00, 0x0e, 0x21, 0x00, 0x00, 0x0e, 0x22, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0xe2, 0x03, 0xd0, 0x00, 0xe2, 0x03, 0xf0, + 0x00, 0xe2, 0xec, 0x10, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0xbc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x08, 0x00, 0xd6, 0x9c, 0x22, + 0x10, 0xd6, 0x4c, 0x0a, 0x01, 0xac, 0xec, 0x20, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x8c, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x20, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x10, + 0x00, 0xa0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x0c, 0x20, 0x00, 0xa0, 0x8c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0c, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0xbe, 0x4c, 0x00, 0x10, 0xd6, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x0a, 0x20, 0x00, 0xa0, 0x7c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xbe, 0x0e, 0x93, + 0x00, 0xa0, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0xa0, 0x0e, 0xc1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0xbe, 0x4c, 0x30, 0x10, 0xd6, 0x0c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xb1, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x7f, 0x2c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc0, 0x00, + 0x00, 0xd6, 0x90, 0x00, 0x00, 0x00, 0x0e, 0xb1, 0x10, 0xd6, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x04, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x0f, 0x04, 0x00, 0x00, 0x04, 0xe3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe9, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xac, 0xfa, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xea, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xdc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe3, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0xd6, 0x9c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xe4, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0xe3, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x1f, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x01, 0xac, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xdc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2e, 0x03, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x1d, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xf0, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0xe2, 0x9c, 0x19, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xf0, 0x9c, 0x11, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9c, 0x11, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x7c, 0x07, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x78, 0x9c, 0x00, 0x00, 0xa0, 0xec, 0x1a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x20, + 0x03, 0x58, 0x03, 0x0a, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0a, 0x20, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x30, 0x00, 0x00, 0x05, 0x50, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x04, 0xf2, + 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x04, 0xf3, 0x00, 0x00, 0x05, 0x05, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x04, 0xf5, 0x10, 0xa0, 0x0c, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x04, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0a, 0x04, 0x01, 0x40, 0xea, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0a, 0x03, + 0x01, 0x68, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x9c, 0x18, 0x10, 0xa0, 0x0c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0c, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x9c, 0x2f, 0x01, 0x40, 0xec, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x0f, 0x00, 0x00, 0x01, 0x03, + 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x9c, 0x15, + 0x01, 0x40, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x9c, 0x06, 0x01, 0x68, 0xec, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x9c, 0x06, 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x07, 0x00, 0x00, 0x04, 0xe3, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0xf0, 0x9c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xec, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe3, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0xb0, 0x00, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe3, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xec, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xd6, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0xde, 0xc2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xe2, 0x0c, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xcf, 0x04, + 0x00, 0xd6, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x10, 0xd6, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, 0x10, 0xd6, 0x4c, 0x00, + 0x01, 0xac, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xd6, 0xea, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xd6, 0x0c, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x10, 0x7f, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x10, 0x78, 0x03, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x0a, 0x07, 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xb4, 0x03, 0xf3, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x10, 0xf0, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xe2, 0x0c, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0xd6, 0x9c, 0x20, + 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xd6, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0xac, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0xe4, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xe3, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x1f, + 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xa0, 0xec, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x97, 0xec, 0x33, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x8f, 0x03, 0x33, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x1d, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0xe1, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xa0, 0x05, 0x08, + 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xb4, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0x05, 0x20, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0x05, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xfe, 0x05, 0x20, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x1d, 0x05, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x2e, 0x05, 0x20, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xf0, 0x9c, 0x20, 0x10, 0xf0, 0x4c, 0x19, + 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x7c, 0x07, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xfc, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x38, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xaa, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xcc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xe4, 0xf2, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x0f, 0x04, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x1c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xec, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x03, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0xf0, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe3, 0x00, 0xa0, 0x10, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xec, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x2e, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x70, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x70, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0xd6, 0x94, 0xe1, + 0x10, 0xd6, 0x4c, 0x06, 0x10, 0x8f, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0x3a, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0c, 0x00, 0x00, 0xbe, 0x4c, 0x10, 0x00, 0x00, 0x06, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x8f, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0xbc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, + 0x00, 0xa0, 0xbe, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xb4, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc0, 0x00, + 0x10, 0xd6, 0x44, 0xe1, 0x00, 0xb4, 0xac, 0x23, 0x10, 0xd6, 0x0c, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0xaa, 0x03, 0x07, + 0x00, 0x00, 0x04, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe3, + 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x64, 0x00, 0x00, 0x04, 0xe1, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x20, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x06, 0x08, 0x00, 0x00, 0x04, 0xe3, 0x01, 0xac, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x09, 0x00, 0x00, 0x04, 0xe3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x4c, 0x19, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xd6, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x10, 0x00, 0x4a, 0x09, 0x00, 0x00, 0x04, 0xe3, + 0x00, 0xd6, 0xea, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x04, 0xe3, 0x00, 0x00, 0x02, 0x0f, 0x00, 0xbe, 0x4c, 0x08, + 0x10, 0x00, 0x4a, 0x09, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x06, 0x04, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x09, 0x19, + 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x06, 0x04, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xbe, 0xbc, 0x30, 0x10, 0x00, 0x44, 0xe1, 0x10, 0xd6, 0x4c, 0x00, + 0x01, 0xac, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, 0x10, 0x00, 0x4a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xd6, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x10, 0x00, 0x4a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xf0, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, + 0x10, 0x00, 0x4a, 0x08, 0x00, 0x00, 0x0e, 0xa1, 0x10, 0xd6, 0x0c, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x10, 0x00, 0x4a, 0x07, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x01, 0x03, + 0x00, 0xbe, 0xbc, 0x18, 0x10, 0x00, 0x4a, 0x06, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x40, 0xe3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, + 0x10, 0x00, 0x4a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x68, 0xec, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, 0x00, 0xd6, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x0e, 0xa1, + 0x10, 0xd6, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0xf0, 0xe4, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x04, 0xe6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xd6, 0xe3, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x02, 0x1f, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0xac, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x40, 0xdc, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, + 0x01, 0x2e, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0e, 0xa1, 0x01, 0x1d, 0x03, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xa1, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0e, 0xa1, 0x00, 0xf0, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0e, 0xbf, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0xe2, 0x9c, 0x19, 0x00, 0xe2, 0x03, 0xf0, + 0x01, 0x68, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0xbc, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0xf0, 0x9c, 0x20, 0x10, 0xf0, 0x4c, 0x10, 0x10, 0xa0, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x7c, 0x07, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xfc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, 0x10, 0xf0, 0x4c, 0x13, + 0x00, 0xa0, 0xec, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x10, 0xf0, 0x4c, 0x07, 0x03, 0x58, 0x03, 0x0a, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x50, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x50, 0x00, 0xbe, 0xbc, 0x30, 0x00, 0x00, 0x94, 0xe1, + 0x10, 0xf0, 0x4c, 0x17, 0x00, 0x00, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x04, 0xe3, 0x00, 0x00, 0x05, 0x05, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe8, 0x00, 0x00, 0x04, 0xe4, + 0x10, 0xa0, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x10, 0xf0, 0x4c, 0x05, 0x01, 0x40, 0xea, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0c, 0x07, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0c, 0x09, 0x01, 0x68, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0c, 0x0a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0c, 0x0b, + 0x10, 0xa0, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0c, 0x0d, 0x01, 0x40, 0xec, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0c, 0x0e, + 0x00, 0x00, 0x01, 0x03, 0x00, 0xbe, 0xbc, 0x18, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0c, 0x0f, 0x01, 0x40, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xbc, 0x10, + 0x00, 0xf0, 0x9c, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10, 0xa0, 0x04, 0xe2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe3, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe5, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x68, 0xec, 0x12, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0xbe, 0x4c, 0x08, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x01, 0x2e, 0xe3, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x05, 0x0f, 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0xa0, 0xc0, 0x00, 0x00, 0x00, 0x9c, 0x20, 0x00, 0x00, 0x0a, 0x01, + 0x01, 0x40, 0xdc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0c, 0x0a, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0xbe, 0x4c, 0x13, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0xbe, 0x4c, 0x13, + 0x00, 0xa0, 0x8c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0xb0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x01, 0x40, 0xfe, 0xc2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x5c, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xaa, 0x4c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xfc, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x7c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc0, 0x00, 0x10, 0xd6, 0x44, 0xe1, + 0x00, 0xb4, 0xac, 0x23, 0x10, 0xd6, 0x0c, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0xaa, 0x03, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xa0, 0x1f, 0x04, 0x00, 0xf0, 0x9c, 0x20, 0x10, 0xf0, 0x4c, 0x10, + 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe6, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x0f, 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0f, + 0x00, 0x7f, 0x7c, 0x07, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x78, 0x9c, 0x00, 0x00, 0xa0, 0xec, 0x1a, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x20, 0x03, 0x58, 0x03, 0x0a, + 0x00, 0x7f, 0x2c, 0x10, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0a, 0x20, + 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0a, 0x30, 0x00, 0x00, 0x05, 0x50, 0x00, 0xbe, 0xbc, 0x30, + 0x00, 0x00, 0x94, 0xe1, 0x00, 0x00, 0x04, 0xf2, 0x00, 0x00, 0x05, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe4, 0x00, 0x00, 0x04, 0xf3, + 0x00, 0x00, 0x05, 0x05, 0x00, 0xa0, 0x1f, 0x04, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x04, 0xf5, 0x10, 0xa0, 0x0c, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x04, 0xf7, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xd6, 0x3c, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0a, 0x04, + 0x01, 0x40, 0xea, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0a, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x2c, 0x20, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x0a, 0x03, 0x01, 0x68, 0xdc, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x3c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x9c, 0x18, 0x10, 0xa0, 0x0c, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x9c, 0x2f, + 0x01, 0x40, 0xec, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0a, 0x0f, 0x00, 0x00, 0x01, 0x03, 0x00, 0xbe, 0xbc, 0x18, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0x00, 0x9c, 0x15, 0x01, 0x40, 0x03, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x7c, 0x10, 0x00, 0x00, 0x9a, 0x09, + 0x00, 0x00, 0x9c, 0x06, 0x01, 0x68, 0xec, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0xbc, 0x10, 0x00, 0xf0, 0x9c, 0x10, 0x00, 0x00, 0x9c, 0x06, + 0x10, 0xa0, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x0a, 0x07, 0x00, 0x00, 0x04, 0xe3, 0x00, 0xa0, 0x1f, 0x04, + 0x00, 0x00, 0x9a, 0x09, 0x10, 0xf0, 0x4c, 0x10, 0x00, 0x00, 0x04, 0xe5, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xa0, 0x60, 0x00, 0x00, 0x00, 0x9a, 0x09, + 0x11, 0x1d, 0x1c, 0x02, 0x01, 0x40, 0xfc, 0x20, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x7f, 0x2c, 0x20, 0x00, 0x00, 0x9a, 0x09, 0x10, 0xd6, 0x1c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x9a, 0x09, 0x00, 0xb4, 0x03, 0xf0, 0x01, 0x68, 0xec, 0x12, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe4, 0x00, 0xbe, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xbe, 0x0c, 0x08, 0x00, 0x00, 0x04, 0xe6, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x00, 0xbe, 0x4c, 0x08, 0x00, 0x00, 0x9a, 0x09, 0x00, 0xb4, 0x03, 0xd0, + 0x01, 0x2e, 0xe3, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0x00, 0x7f, 0x2c, 0x10, + 0x00, 0x00, 0x9a, 0x09, 0x10, 0xf0, 0x1c, 0x0a, 0x10, 0x7f, 0x1c, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0xc0, 0x00, 0x00, 0xd6, 0x94, 0xe1, + 0x00, 0xd6, 0x03, 0xd0, 0x00, 0x78, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0f, 0x04, 0x00, 0x00, 0x04, 0xe4, 0x10, 0xfe, 0x1c, 0x10, + 0x00, 0x8f, 0x0c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xe8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0xb4, 0x1c, 0x08, 0x00, 0xf0, 0x03, 0xd0, 0x00, 0xa0, 0x03, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x03, 0xf0, + 0x01, 0x1d, 0x03, 0xf0, 0x00, 0xb4, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x05, 0x10, 0x00, 0xfe, 0x03, 0xf0, + 0x00, 0xd6, 0x05, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, + 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x1d, 0x05, 0x10, 0x01, 0x40, 0x03, 0xf0, 0x00, 0xf0, 0x05, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x10, 0x00, 0x00, 0x05, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x10, 0xf0, 0x1f, 0x08, 0x11, 0x2e, 0x10, 0x00, + 0x11, 0x68, 0x1c, 0x20, 0x10, 0xd6, 0x1c, 0x20, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x04, 0x00, 0x00, 0x0a, 0x04, + 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x0c, 0x03, + 0x00, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x0f, 0x1f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0xe3, + 0x01, 0x1d, 0x03, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0x0a, 0x01, + 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, 0xff, 0xf3, 0xf3, 0x05, 0x40, 0x3e, + 0x09, 0xc4, 0xa9, 0xfd, 0x3e, 0x68, 0x20, 0x03, 0xbd, 0x09, 0x0b, 0x0b, + 0x3c, 0x1b, 0x55, 0x3a, 0xe3, 0xc2, 0xa9, 0x05, 0x43, 0x53, 0x05, 0xbf, + 0xab, 0x13, 0x3a, 0x4b, 0xf5, 0x03, 0xc2, 0x0b, 0x20, 0x55, 0xf5, 0xef, + 0xe0, 0x0f, 0x0d, 0x4f, 0x4d, 0x0f, 0xda, 0x2e, 0xe7, 0xf7, 0x11, 0xd2, + 0xca, 0xc2, 0xfb, 0xe7, 0x1d, 0xf1, 0xe0, 0xf1, 0xe0, 0xfb, 0xeb, 0xb7, + 0xb9, 0xd6, 0xef, 0x13, 0xd8, 0xf7, 0xde, 0x09, 0xe0, 0x15, 0xc4, 0xb1, + 0xcc, 0x1d, 0xf7, 0xde, 0x0b, 0xc8, 0xaf, 0x9e, 0x88, 0x82, 0xd0, 0x15, + 0x1f, 0xc6, 0xc8, 0xe0, 0x09, 0xe9, 0xe5, 0xce, 0xbb, 0xbd, 0xb3, 0xd4, + 0xb1, 0xfd, 0x03, 0xc8, 0xe9, 0xbb, 0xfd, 0xd2, 0x20, 0xfb, 0xf9, 0xde, + 0x03, 0x1b, 0xdc, 0xf9, 0x0d, 0x0b, 0x0b, 0x26, 0xe1, 0x34, 0x38, 0x24, + 0xff, 0x22, 0x03, 0x26, 0x09, 0x4d, 0x09, 0x34, 0x28, 0x22, 0x11, 0x3a, + 0x20, 0x30, 0x1b, 0x30, 0x1d, 0x1d, 0x2e, 0x32, 0x4f, 0x57, 0x38, 0x68, + 0x20, 0x3c, 0xe1, 0x40, 0x2a, 0x40, 0x3c, 0x26, 0x2e, 0x40, 0x53, 0x61, + 0x1b, 0x45, 0x05, 0x49, 0x0b, 0x4b, 0x4b, 0x40, 0x49, 0x32, 0x30, 0x2e, + 0x59, 0x3a, 0x4d, 0xff, 0x1f, 0x4d, 0x22, 0x4b, 0x00, 0x05, 0x3e, 0x4b, + 0x1d, 0x03, 0x07, 0x45, 0x2e, 0x1d, 0x34, 0x01, 0x20, 0x11, 0x0b, 0xfb, + 0x30, 0x0b, 0xe5, 0x09, 0x13, 0x1b, 0x0d, 0xff, 0xc8, 0x0b, 0xd4, 0x26, + 0x11, 0xe3, 0xc0, 0xd2, 0x0d, 0xfb, 0xc2, 0xda, 0xcc, 0xef, 0xd6, 0xfb, + 0xd2, 0xed, 0xb1, 0xca, 0xe5, 0xc0, 0xd4, 0xbb, 0xb9, 0xbd, 0xd6, 0xcc, + 0xb3, 0xd6, 0xb5, 0xc0, 0xce, 0xce, 0xbb, 0xbd, 0xb3, 0xd0, 0xbf, 0xb5, + 0xb3, 0xbd, 0xbd, 0xc4, 0xc4, 0xc4, 0xa7, 0xc2, 0xab, 0xd8, 0xb7, 0xc6, + 0xc2, 0xb1, 0xbd, 0xd6, 0xca, 0xc4, 0xbb, 0xc4, 0xe3, 0xb5, 0xe1, 0xbb, + 0xd6, 0xdc, 0xde, 0xc0, 0xca, 0xd4, 0xeb, 0xd8, 0xd6, 0xcc, 0xcc, 0xed, + 0xde, 0xe9, 0xe1, 0xe1, 0xf5, 0xdc, 0xda, 0xed, 0xf1, 0xf1, 0xe3, 0xda, + 0xe9, 0xf5, 0xf7, 0xf3, 0xff, 0x03, 0x0f, 0x07, 0xff, 0xff, 0x03, 0x07, + 0x1b, 0x07, 0x07, 0x05, 0x24, 0x13, 0x19, 0x0f, 0x1f, 0x0d, 0x1f, 0x20, + 0x11, 0x20, 0x1f, 0x32, 0x28, 0x3a, 0x20, 0x2e, 0x1b, 0x30, 0x2c, 0x3c, + 0x2e, 0x2a, 0x30, 0x3e, 0x38, 0x34, 0x24, 0x2e, 0x22, 0x2e, 0x32, 0x47, + 0x30, 0x34, 0x38, 0x2c, 0x3a, 0x41, 0x38, 0x2c, 0x45, 0x2c, 0x26, 0x38, + 0x24, 0x22, 0x3e, 0x36, 0x3e, 0x28, 0x24, 0x20, 0x2e, 0x28, 0x3a, 0x32, + 0x32, 0x2c, 0x34, 0x17, 0x2e, 0x1d, 0x2e, 0x2e, 0x32, 0x30, 0x2a, 0x26, + 0x28, 0x19, 0x28, 0x24, 0x26, 0x32, 0x1d, 0x1f, 0x26, 0x20, 0x24, 0x22, + 0x1b, 0x17, 0x17, 0x1f, 0x24, 0x24, 0x17, 0x1b, 0x17, 0x19, 0x13, 0x1d, + 0x0f, 0x11, 0x0f, 0x0f, 0x0d, 0x0f, 0x09, 0x11, 0x00, 0x0b, 0x05, 0x0d, + 0x00, 0x0d, 0x01, 0x03, 0x03, 0xf7, 0x01, 0xfd, 0x03, 0x07, 0xfb, 0x01, + 0xf9, 0xf7, 0xf5, 0xfd, 0xf7, 0xf5, 0xf7, 0xe9, 0xf1, 0x00, 0xf7, 0xeb, + 0xde, 0xe1, 0xde, 0xe9, 0xf1, 0xef, 0xed, 0xe3, 0xd4, 0xde, 0xe3, 0xe3, + 0xe0, 0xe0, 0xdc, 0xde, 0xd8, 0xda, 0xd8, 0xd8, 0xd4, 0xd2, 0xcc, 0xd0, + 0xcc, 0xc8, 0xce, 0xd6, 0xcc, 0xca, 0xc8, 0xc8, 0xc6, 0xcc, 0xc4, 0xca, + 0xc4, 0xc6, 0xc6, 0xc6, 0xc6, 0xcc, 0xc2, 0xc0, 0xc4, 0xc8, 0xca, 0xcc, + 0xca, 0xc4, 0xc8, 0xc6, 0xce, 0xc4, 0xce, 0xc8, 0xc6, 0xce, 0xce, 0xd0, + 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd8, 0xd8, 0xd4, 0xd8, 0xde, 0xde, 0xde, + 0xe0, 0xe1, 0xde, 0xe1, 0xe1, 0xe5, 0xe7, 0xeb, 0xed, 0xed, 0xe9, 0xeb, + 0xef, 0xf1, 0xf3, 0xef, 0xf7, 0xfd, 0xfb, 0xf7, 0xf5, 0xf9, 0xff, 0xfd, + 0xff, 0xff, 0x03, 0x07, 0x05, 0x00, 0x09, 0x07, 0x0d, 0x09, 0x0d, 0x09, + 0x11, 0x15, 0x1b, 0x15, 0x0f, 0x0d, 0x13, 0x13, 0x15, 0x17, 0x1d, 0x17, + 0x17, 0x17, 0x1d, 0x1d, 0x24, 0x24, 0x22, 0x1d, 0x1d, 0x22, 0x26, 0x26, + 0x26, 0x20, 0x22, 0x22, 0x22, 0x24, 0x26, 0x26, 0x28, 0x2a, 0x28, 0x20, + 0x22, 0x26, 0x26, 0x2a, 0x2a, 0x2a, 0x28, 0x2a, 0x26, 0x24, 0x22, 0x28, + 0x2a, 0x2a, 0x28, 0x2a, 0x2c, 0x2e, 0x2c, 0x28, 0x26, 0x26, 0x26, 0x26, + 0x2a, 0x28, 0x26, 0x26, 0x26, 0x22, 0x1f, 0x24, 0x28, 0x2a, 0x2a, 0x22, + 0x24, 0x26, 0x24, 0x20, 0x1f, 0x20, 0x1f, 0x1d, 0x1d, 0x19, 0x1b, 0x1b, + 0x1f, 0x1f, 0x1b, 0x15, 0x17, 0x1b, 0x1f, 0x1b, 0x15, 0x13, 0x13, 0x11, + 0x11, 0x13, 0x15, 0x13, 0x11, 0x0d, 0x0b, 0x0d, 0x0d, 0x0b, 0x0d, 0x0b, + 0x05, 0x03, 0x03, 0x03, 0x05, 0x09, 0x09, 0x05, 0xff, 0xf9, 0xf7, 0xfd, + 0x01, 0x01, 0x00, 0xff, 0xfb, 0xf9, 0xf9, 0xf9, 0xf5, 0xf5, 0xf9, 0xf9, + 0xf5, 0xef, 0xef, 0xed, 0xf1, 0xf3, 0xf1, 0xef, 0xeb, 0xe9, 0xe9, 0xeb, + 0xeb, 0xeb, 0xe7, 0xe7, 0xe5, 0xe7, 0xed, 0xeb, 0xe3, 0xe0, 0xe1, 0xe3, + 0xe3, 0xe1, 0xe3, 0xe5, 0xe7, 0xe7, 0xe1, 0xe0, 0xde, 0xe0, 0xe0, 0xe0, + 0xe1, 0xe1, 0xe3, 0xe3, 0xe5, 0xe7, 0xe3, 0xde, 0xde, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe0, 0xdc, 0xe1, 0xe3, 0xe1, 0xe3, 0xe1, 0xe1, 0xe0, 0xe0, 0xe1, + 0xe0, 0xe1, 0xe3, 0xe7, 0xeb, 0xe7, 0xe3, 0xe0, 0xe0, 0xe3, 0xe5, 0xe7, + 0xe3, 0xe1, 0xe3, 0xe7, 0xed, 0xed, 0xeb, 0xe9, 0xed, 0xed, 0xef, 0xed, + 0xef, 0xed, 0xeb, 0xed, 0xf1, 0xf3, 0xf3, 0xf5, 0xf5, 0xf3, 0xf1, 0xef, + 0xef, 0xf1, 0xf5, 0xf5, 0xf3, 0xf1, 0xed, 0xf1, 0xf5, 0xf9, 0xfd, 0xfd, + 0xf7, 0xf3, 0xf3, 0xf7, 0xf9, 0xfb, 0xfb, 0xfb, 0xf9, 0xf9, 0xf9, 0xf9, + 0xfb, 0xfd, 0xff, 0xfd, 0xff, 0xfd, 0xfd, 0xfd, 0x00, 0xff, 0xfd, 0xfd, + 0xfd, 0x00, 0x01, 0x01, 0xff, 0xfd, 0xfd, 0x00, 0x01, 0x03, 0x03, 0x03, + 0x01, 0x00, 0xff, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00, 0x01, 0x05, 0x05, + 0x05, 0x03, 0x03, 0x05, 0x03, 0x01, 0x03, 0x07, 0x09, 0x07, 0x03, 0x01, + 0x05, 0x07, 0x09, 0x07, 0x05, 0x05, 0x07, 0x0b, 0x09, 0x05, 0x03, 0x01, + 0x03, 0x07, 0x09, 0x0b, 0x09, 0x09, 0x0b, 0x0b, 0x0b, 0x0d, 0x0b, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0b, 0x07, 0x09, 0x0b, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x13, 0x13, 0x11, 0x0f, 0x0d, 0x0d, 0x0f, 0x11, 0x11, 0x0f, 0x0d, 0x0f, + 0x0f, 0x11, 0x0f, 0x11, 0x13, 0x0f, 0x0f, 0x0f, 0x13, 0x13, 0x15, 0x13, + 0x11, 0x11, 0x11, 0x0f, 0x0f, 0x0d, 0x13, 0x17, 0x13, 0x11, 0x11, 0x13, + 0x15, 0x13, 0x13, 0x15, 0x15, 0x17, 0x15, 0x11, 0x11, 0x15, 0x17, 0x15, + 0x13, 0x15, 0x19, 0x19, 0x19, 0x15, 0x13, 0x13, 0x15, 0x15, 0x15, 0x17, + 0x17, 0x15, 0x13, 0x13, 0x13, 0x13, 0x11, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x17, 0x17, 0x15, 0x15, 0x13, 0x0f, 0x0f, 0x17, 0x1d, 0x1b, 0x17, 0x15, + 0x13, 0x15, 0x1b, 0x1b, 0x17, 0x17, 0x17, 0x17, 0x15, 0x15, 0x13, 0x11, + 0x11, 0x13, 0x15, 0x17, 0x11, 0x0d, 0x0d, 0x0f, 0x0f, 0x0f, 0x0d, 0x0b, + 0x09, 0x0b, 0x0f, 0x0d, 0x09, 0x09, 0x07, 0x09, 0x0b, 0x0b, 0x09, 0x01, + 0x00, 0x01, 0x03, 0x03, 0x03, 0x00, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xfb, + 0xfb, 0xfb, 0xf9, 0xf9, 0xf7, 0xf3, 0xf3, 0xf5, 0xf7, 0xf5, 0xf1, 0xf1, + 0xf3, 0xf3, 0xf1, 0xed, 0xeb, 0xe9, 0xed, 0xed, 0xed, 0xeb, 0xe9, 0xe7, + 0xe7, 0xe5, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe5, 0xe3, 0xe0, + 0xe0, 0xe0, 0xe0, 0xde, 0xdc, 0xde, 0xe0, 0xe0, 0xdc, 0xd8, 0xd8, 0xdc, + 0xde, 0xda, 0xd8, 0xd8, 0xde, 0xe0, 0xdc, 0xda, 0xda, 0xdc, 0xde, 0xe0, + 0xde, 0xdc, 0xdc, 0xde, 0xde, 0xdc, 0xdc, 0xde, 0xde, 0xdc, 0xdc, 0xdc, + 0xde, 0xe1, 0xe3, 0xe1, 0xe0, 0xe0, 0xde, 0xe0, 0xe0, 0xe1, 0xe3, 0xe5, + 0xe1, 0xe0, 0xe1, 0xe3, 0xe7, 0xe9, 0xe9, 0xe9, 0xeb, 0xeb, 0xe9, 0xe7, + 0xe5, 0xe9, 0xed, 0xed, 0xe9, 0xe5, 0xe3, 0xe7, 0xeb, 0xed, 0xeb, 0xeb, + 0xeb, 0xe9, 0xeb, 0xed, 0xf1, 0xf1, 0xf1, 0xef, 0xed, 0xeb, 0xed, 0xf1, + 0xf3, 0xf1, 0xed, 0xed, 0xef, 0xf1, 0xf5, 0xf3, 0xf3, 0xf5, 0xf5, 0xf5, + 0xf7, 0xf7, 0xf9, 0xf9, 0xf9, 0xf9, 0xfb, 0xfd, 0xfd, 0xff, 0xfd, 0xfb, + 0xf9, 0xfd, 0xfd, 0xff, 0xfd, 0xfd, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x05, 0x07, 0x07, + 0x09, 0x09, 0x05, 0x05, 0x01, 0x03, 0x05, 0x07, 0x05, 0x05, 0x05, 0x07, + 0x0b, 0x0d, 0x07, 0x05, 0x05, 0x07, 0x0d, 0x0d, 0x0b, 0x09, 0x0d, 0x0f, + 0x0f, 0x0d, 0x0d, 0x0f, 0x0f, 0x0f, 0x0d, 0x0d, 0x0f, 0x0f, 0x13, 0x17, + 0x15, 0x11, 0x0f, 0x11, 0x13, 0x15, 0x15, 0x17, 0x17, 0x19, 0x19, 0x19, + 0x15, 0x11, 0x11, 0x15, 0x1b, 0x1f, 0x1b, 0x17, 0x11, 0x15, 0x19, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1b, 0x19, 0x19, 0x19, 0x1b, 0x1f, 0x1f, 0x1d, + 0x1d, 0x1d, 0x1b, 0x19, 0x1b, 0x1d, 0x1d, 0x1b, 0x1d, 0x1f, 0x1f, 0x1f, + 0x1d, 0x1b, 0x19, 0x19, 0x1b, 0x1b, 0x1d, 0x1d, 0x1b, 0x1d, 0x1d, 0x1f, + 0x1f, 0x19, 0x15, 0x17, 0x1b, 0x20, 0x22, 0x1f, 0x1b, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x1b, 0x1b, 0x19, 0x17, 0x17, 0x19, 0x19, 0x17, 0x15, 0x15, + 0x17, 0x19, 0x17, 0x13, 0x11, 0x11, 0x13, 0x15, 0x13, 0x0f, 0x0f, 0x0d, + 0x09, 0x07, 0x09, 0x0d, 0x0f, 0x0f, 0x0d, 0x07, 0x07, 0x07, 0x09, 0x09, + 0x09, 0x05, 0x05, 0x03, 0x05, 0x07, 0x07, 0x03, 0x01, 0x00, 0x01, 0x03, + 0x05, 0x05, 0x03, 0x00, 0xff, 0xff, 0x00, 0x01, 0x01, 0xff, 0xff, 0xfd, + 0xfb, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfb, 0xfb, 0xfb, 0xf9, + 0xf9, 0xfb, 0xfd, 0xfd, 0xfd, 0xfd, 0xf9, 0xf7, 0xf9, 0xfb, 0xfd, 0xfb, + 0xf9, 0xf9, 0xf9, 0xf7, 0xf5, 0xf1, 0xf1, 0xf3, 0xf7, 0xf9, 0xf5, 0xf1, + 0xf1, 0xf3, 0xf5, 0xf5, 0xf1, 0xef, 0xef, 0xf1, 0xf1, 0xf1, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xf1, 0xf3, 0xf1, 0xef, 0xed, 0xeb, 0xeb, 0xeb, + 0xef, 0xef, 0xed, 0xeb, 0xe7, 0xe9, 0xe9, 0xeb, 0xed, 0xed, 0xeb, 0xe9, + 0xeb, 0xeb, 0xe5, 0xe3, 0xe5, 0xe9, 0xed, 0xed, 0xe7, 0xe1, 0xe1, 0xe5, + 0xe7, 0xe7, 0xe7, 0xeb, 0xe9, 0xe5, 0xe3, 0xe1, 0xe3, 0xe9, 0xeb, 0xe9, + 0xe3, 0xe1, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe5, 0xe3, 0xe1, 0xe3, 0xe7, + 0xe9, 0xe7, 0xe3, 0xe1, 0xe1, 0xe3, 0xe5, 0xe5, 0xe3, 0xe5, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe3, 0xe3, 0xe7, 0xe9, 0xed, 0xeb, 0xe9, 0xeb, 0xe9, 0xe7, + 0xe5, 0xe5, 0xe9, 0xeb, 0xeb, 0xe9, 0xeb, 0xed, 0xed, 0xed, 0xeb, 0xeb, + 0xeb, 0xe7, 0xe9, 0xe9, 0xf1, 0xf7, 0xf7, 0xf1, 0xeb, 0xeb, 0xf3, 0xf7, + 0xf5, 0xf1, 0xef, 0xf1, 0xf3, 0xf3, 0xf3, 0xf3, 0xf5, 0xf7, 0xf7, 0xf3, + 0xf3, 0xf5, 0xf9, 0xf9, 0xf7, 0xf7, 0xfb, 0xfb, 0xfb, 0xfb, 0xf9, 0xf9, + 0xf7, 0xf7, 0xf7, 0xfb, 0xfd, 0x00, 0x01, 0x00, 0xfd, 0xf9, 0xfb, 0xff, + 0x01, 0x07, 0x09, 0x07, 0x03, 0xfd, 0xf9, 0xfb, 0x03, 0x09, 0x07, 0x03, + 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, 0x09, 0x07, 0x05, 0x05, 0x05, 0x0b, + 0x0d, 0x0b, 0x07, 0x07, 0x0b, 0x0d, 0x0f, 0x0d, 0x09, 0x09, 0x07, 0x07, + 0x0b, 0x0f, 0x11, 0x11, 0x0d, 0x0b, 0x0b, 0x0d, 0x0d, 0x0f, 0x0f, 0x0f, + 0x0d, 0x0f, 0x15, 0x17, 0x15, 0x0f, 0x0b, 0x0f, 0x11, 0x13, 0x13, 0x15, + 0x15, 0x15, 0x13, 0x11, 0x13, 0x19, 0x1d, 0x19, 0x13, 0x0d, 0x11, 0x17, + 0x19, 0x17, 0x13, 0x11, 0x17, 0x1d, 0x1f, 0x19, 0x17, 0x15, 0x15, 0x17, + 0x1d, 0x1f, 0x1f, 0x1b, 0x17, 0x15, 0x17, 0x19, 0x1d, 0x1d, 0x1b, 0x19, + 0x1b, 0x1d, 0x1f, 0x1d, 0x1b, 0x19, 0x19, 0x17, 0x1b, 0x1d, 0x1f, 0x1f, + 0x1d, 0x1b, 0x19, 0x19, 0x1b, 0x1f, 0x22, 0x1f, 0x1b, 0x19, 0x19, 0x1b, + 0x1f, 0x22, 0x1f, 0x19, 0x15, 0x17, 0x19, 0x1f, 0x22, 0x20, 0x1d, 0x19, + 0x19, 0x1b, 0x1b, 0x1b, 0x19, 0x17, 0x17, 0x17, 0x19, 0x17, 0x17, 0x17, + 0x15, 0x13, 0x13, 0x15, 0x17, 0x17, 0x11, 0x0b, 0x09, 0x0b, 0x0d, 0x0f, + 0x0f, 0x0f, 0x0b, 0x05, 0x03, 0x05, 0x07, 0x09, 0x09, 0x05, 0x01, 0x00, + 0x00, 0x05, 0x07, 0x05, 0x00, 0xfd, 0xfd, 0xfd, 0xff, 0x00, 0xff, 0x00, + 0x00, 0xfd, 0xf9, 0xf9, 0xf9, 0xfb, 0xfb, 0xf7, 0xf3, 0xf3, 0xf7, 0xf7, + 0xf7, 0xf3, 0xf1, 0xef, 0xf3, 0xf3, 0xf3, 0xf3, 0xf3, 0xef, 0xeb, 0xe9, + 0xeb, 0xf1, 0xf1, 0xed, 0xe9, 0xe7, 0xe7, 0xe5, 0xe9, 0xeb, 0xeb, 0xe9, + 0xe9, 0xe7, 0xe7, 0xe9, 0xeb, 0xe9, 0xe3, 0xe1, 0xe3, 0xe5, 0xe9, 0xeb, + 0xeb, 0xe5, 0xe3, 0xe3, 0xe1, 0xe1, 0xe5, 0xe7, 0xe7, 0xe5, 0xe3, 0xe3, + 0xe7, 0xeb, 0xeb, 0xe7, 0xe3, 0xe1, 0xe3, 0xe7, 0xe9, 0xeb, 0xe9, 0xe7, + 0xe5, 0xe5, 0xe5, 0xe9, 0xeb, 0xeb, 0xe9, 0xe7, 0xe7, 0xe9, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe9, 0xe7, 0xe9, 0xeb, 0xed, 0xeb, 0xe7, 0xe7, 0xeb, + 0xed, 0xeb, 0xeb, 0xe9, 0xed, 0xef, 0xf1, 0xef, 0xed, 0xeb, 0xef, 0xf1, + 0xf3, 0xf5, 0xf3, 0xed, 0xeb, 0xed, 0xf3, 0xf3, 0xf3, 0xf7, 0xf9, 0xfb, + 0xfb, 0xf9, 0xf7, 0xf5, 0xf9, 0xfb, 0xfb, 0xf9, 0xf7, 0xf7, 0xfb, 0xfd, + 0xfd, 0xfb, 0xfb, 0xff, 0x03, 0x01, 0xfd, 0xf7, 0xf9, 0xfd, 0x03, 0x03, + 0x00, 0xff, 0xff, 0x00, 0x03, 0x03, 0x01, 0x03, 0x05, 0x07, 0x05, 0x03, + 0x01, 0x03, 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, + 0x00, 0x00, 0x03, 0x07, 0x09, 0x07, 0x05, 0x05, 0x05, 0x07, 0x05, 0x05, + 0x05, 0x05, 0x07, 0x09, 0x07, 0x05, 0x03, 0x07, 0x07, 0x05, 0x03, 0x03, + 0x07, 0x0b, 0x0b, 0x09, 0x03, 0x01, 0x03, 0x07, 0x05, 0x05, 0x01, 0x03, + 0x05, 0x07, 0x03, 0x00, 0x00, 0x01, 0x03, 0x03, 0x00, 0xff, 0x00, 0x03, + 0x09, 0x0b, 0x0b, 0x05, 0xff, 0xfb, 0x00, 0x03, 0x05, 0x03, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x01, 0xff, 0xff, 0x00, 0x03, + 0x05, 0x05, 0x03, 0x00, 0x00, 0x01, 0x01, 0x03, 0x03, 0x01, 0x00, 0x00, + 0x01, 0x05, 0x09, 0x07, 0x01, 0xff, 0x00, 0x01, 0x03, 0x03, 0x01, 0x00, + 0x01, 0x05, 0x07, 0x07, 0x03, 0x00, 0xff, 0xff, 0x00, 0x01, 0x03, 0x01, + 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0xfb, 0xf9, 0x00, 0x00, 0x00, + 0x00, 0xf3, 0x05, 0x01, 0x00, 0xf7, 0x05, 0xf3, 0x11, 0x00, 0xeb, 0x09, + 0x05, 0xfb, 0xfb, 0x05, 0xf3, 0x15, 0xff, 0xd3, 0x2d, 0xf7, 0xf3, 0xef, + 0x21, 0xef, 0xf7, 0x0d, 0xfb, 0x00, 0xff, 0x00, 0x01, 0xef, 0x01, 0x0d, + 0xf3, 0xe7, 0x2d, 0xf3, 0xdb, 0x29, 0xf7, 0xfb, 0xef, 0x19, 0xfb, 0xf7, + 0xf3, 0x15, 0xff, 0x09, 0xd3, 0x25, 0x00, 0xeb, 0xff, 0x19, 0xff, 0xdf, + 0x1d, 0xff, 0xe7, 0x19, 0x00, 0xe7, 0x01, 0x09, 0xff, 0xf3, 0x0d, 0xfb, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x05, 0xef, + 0x15, 0x01, 0xcf, 0x21, 0x00, 0xe3, 0x11, 0x01, 0xff, 0xdf, 0x2d, 0xef, + 0xe3, 0x1d, 0xf3, 0x09, 0xff, 0xff, 0x01, 0x05, 0xdb, 0x1d, 0xfb, 0x00, + 0x01, 0xf7, 0x00, 0x0d, 0xe7, 0x05, 0x09, 0x05, 0xeb, 0xf3, 0x21, 0xf7, + 0xe7, 0x15, 0x05, 0xef, 0xff, 0x0d, 0xf3, 0x0d, 0x01, 0xe3, 0x0d, 0xfb, + 0x15, 0xef, 0xef, 0x1d, 0xf7, 0x09, 0xeb, 0x05, 0x05, 0x05, 0xe7, 0xff, + 0x1d, 0xfb, 0xe3, 0x19, 0x00, 0xff, 0xf3, 0x05, 0x09, 0x00, 0xdb, 0x25, + 0xfb, 0xf3, 0x09, 0x09, 0xf3, 0xf7, 0x05, 0x00, 0x0d, 0xeb, 0xff, 0x19, + 0xdf, 0x0d, 0x09, 0xf7, 0xeb, 0x1d, 0x00, 0xe7, 0x00, 0x15, 0xf3, 0x00, + 0x00, 0x00, 0xff, 0xfb, 0x05, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfb, 0x00, + 0x01, 0x05, 0xf3, 0xeb, 0x21, 0xff, 0xf7, 0xeb, 0x21, 0x00, 0xe3, 0x01, + 0x0d, 0x00, 0xdf, 0x1d, 0xfb, 0xfb, 0x00, 0x0d, 0xef, 0xf7, 0x11, 0x00, + 0xf3, 0x05, 0x0d, 0xeb, 0xf3, 0x19, 0xf3, 0x09, 0xef, 0x00, 0x05, 0x01, + 0x00, 0xf7, 0x01, 0x09, 0xe3, 0x05, 0x09, 0x00, 0xdf, 0x1d, 0x00, 0xef, + 0xff, 0x11, 0xf7, 0x01, 0x09, 0xdb, 0x11, 0x09, 0xf7, 0xf3, 0x11, 0xff, + 0xf7, 0xff, 0x09, 0xfb, 0xf7, 0x19, 0xe7, 0xfb, 0x11, 0x01, 0xdf, 0x11, + 0x00, 0x09, 0xeb, 0xff, 0x15, 0xfb, 0xef, 0x0d, 0xf7, 0x01, 0x05, 0xf7, + 0x01, 0x05, 0xf3, 0x00, 0x09, 0xeb, 0x05, 0x01, 0x01, 0xe3, 0x1d, 0x00, + 0xe7, 0x11, 0xf3, 0x15, 0xfb, 0xe7, 0x1d, 0xf3, 0xf7, 0x05, 0x09, 0xf7, + 0xeb, 0x1d, 0xff, 0xef, 0x00, 0x0d, 0xf7, 0x09, 0x00, 0xd7, 0x29, 0xfb, + 0xef, 0x00, 0x0d, 0x00, 0xdb, 0x29, 0xef, 0xeb, 0x19, 0x00, 0xe7, 0x0d, + 0x01, 0x09, 0xdf, 0x09, 0x09, 0x01, 0xdb, 0x15, 0x01, 0xfb, 0xf3, 0x15, + 0xf3, 0xef, 0x0d, 0x01, 0xff, 0xeb, 0x15, 0xff, 0xfb, 0xf7, 0x09, 0x01, + 0xfb, 0xef, 0x19, 0xff, 0xe3, 0x15, 0x00, 0xeb, 0x11, 0xef, 0x05, 0x0d, + 0xe7, 0x00, 0x09, 0x00, 0xfb, 0x00, 0xff, 0x01, 0x05, 0xe7, 0x00, 0x11, + 0x01, 0xdf, 0x11, 0x05, 0x00, 0xeb, 0x11, 0xff, 0x09, 0xeb, 0x01, 0x00, + 0x0d, 0xeb, 0xff, 0x09, 0x01, 0xf7, 0xf7, 0x0d, 0xfb, 0x0d, 0xf7, 0xe3, + 0x25, 0xfb, 0xe7, 0x05, 0x0d, 0x00, 0xdb, 0x21, 0xfb, 0xfb, 0xf7, 0x11, + 0xfb, 0xfb, 0x05, 0x00, 0xfb, 0xff, 0x05, 0x05, 0xef, 0xf7, 0x15, 0xe7, + 0x09, 0x0d, 0xef, 0xf3, 0x25, 0xdb, 0x01, 0x09, 0x01, 0xdf, 0x15, 0x00, + 0xff, 0xf7, 0x09, 0xfb, 0x00, 0xff, 0xff, 0x00, 0xff, 0x05, 0x00, 0xe7, + 0x19, 0x01, 0xe3, 0x11, 0x05, 0x00, 0xe3, 0x15, 0xf7, 0x11, 0xf7, 0xe7, + 0x19, 0xff, 0x01, 0xdf, 0x25, 0xef, 0xf7, 0x09, 0x00, 0xfb, 0xfb, 0x09, + 0xfb, 0xf7, 0x09, 0xff, 0xfb, 0x00, 0x09, 0x00, 0xdb, 0x1d, 0xf7, 0x05, + 0xf3, 0x09, 0x09, 0xdf, 0x09, 0x09, 0x00, 0xe3, 0x1d, 0xeb, 0x09, 0x01, + 0xef, 0x05, 0x05, 0x00, 0xe3, 0x19, 0xf7, 0xff, 0x0d, 0xff, 0xdb, 0x25, + 0xff, 0xef, 0xff, 0x19, 0xeb, 0xff, 0x0d, 0x01, 0xef, 0x00, 0x15, 0xe3, + 0x09, 0x05, 0x00, 0xe7, 0x11, 0xff, 0x00, 0xfb, 0x09, 0xfb, 0xf3, 0x11, + 0x01, 0xdb, 0x1d, 0x00, 0xff, 0xf3, 0x15, 0xfb, 0xf3, 0x09, 0x05, 0xe7, + 0x01, 0x0d, 0xff, 0xeb, 0x0d, 0x01, 0xfb, 0xfb, 0x05, 0x00, 0xfb, 0x01, + 0x01, 0xf3, 0x05, 0x05, 0xff, 0xef, 0x15, 0xfb, 0xef, 0x0d, 0x00, 0xfb, + 0x0d, 0xf3, 0xf3, 0x19, 0xff, 0xe7, 0x0d, 0x01, 0xff, 0xf7, 0x09, 0xf7, + 0x05, 0x05, 0xef, 0x01, 0x00, 0x09, 0xf7, 0xf7, 0x15, 0xe7, 0x15, 0xf7, + 0xeb, 0x15, 0xff, 0xf7, 0x00, 0x01, 0x00, 0x00, 0x00, 0xeb, 0x15, 0xfb, + 0xfb, 0x01, 0xff, 0x05, 0x01, 0xeb, 0x19, 0x00, 0xf3, 0xff, 0x11, 0xf3, + 0xfb, 0x09, 0x09, 0xe3, 0x11, 0xf7, 0x00, 0x00, 0x09, 0xf7, 0xf3, 0x11, + 0x01, 0xe3, 0x0d, 0x00, 0x01, 0x01, 0xe3, 0x11, 0x01, 0xfb, 0xf7, 0x0d, + 0xff, 0xfb, 0xff, 0x00, 0x01, 0x05, 0xe7, 0x0d, 0xf7, 0x09, 0xf7, 0x01, + 0x01, 0xeb, 0x11, 0x01, 0xe7, 0x01, 0x0d, 0xff, 0xe7, 0x21, 0xfb, 0xe7, + 0x11, 0x00, 0xfb, 0xff, 0x0d, 0xef, 0xfb, 0x09, 0x00, 0x05, 0xef, 0x0d, + 0x01, 0xe7, 0x0d, 0xfb, 0x00, 0x05, 0xf7, 0xff, 0x0d, 0xfb, 0xf3, 0x11, + 0x05, 0xeb, 0x01, 0x05, 0x00, 0x01, 0xe7, 0x09, 0x01, 0x01, 0xfb, 0xeb, + 0x15, 0xff, 0x01, 0xef, 0x11, 0x00, 0xf7, 0xff, 0x05, 0x09, 0xeb, 0x05, + 0xff, 0x00, 0x05, 0xf7, 0xfb, 0x09, 0x05, 0xf3, 0xf3, 0x15, 0x00, 0xe7, + 0x09, 0x01, 0xff, 0xf3, 0x0d, 0x00, 0xfb, 0x00, 0x01, 0xff, 0x01, 0x09, + 0xe7, 0xff, 0x11, 0xf3, 0x05, 0x00, 0xfb, 0x00, 0xff, 0x01, 0x05, 0xf3, + 0x00, 0x05, 0xf7, 0x05, 0xff, 0xf7, 0x01, 0x09, 0xef, 0xf7, 0x15, 0xf7, + 0xff, 0x0d, 0xf7, 0xeb, 0x21, 0xfb, 0xeb, 0x05, 0x01, 0x05, 0xe3, 0x11, + 0x01, 0xff, 0xeb, 0x21, 0xe3, 0x00, 0x0d, 0x00, 0xe7, 0x0d, 0x01, 0x01, + 0xe3, 0x19, 0x00, 0xf7, 0xff, 0x05, 0xfb, 0x05, 0xf7, 0x00, 0x00, 0xfb, + 0x00, 0x0d, 0xf7, 0xef, 0x15, 0xfb, 0xfb, 0x09, 0x01, 0xe3, 0x11, 0x01, + 0xff, 0xef, 0x15, 0xff, 0xf7, 0x01, 0x00, 0xff, 0x09, 0xfb, 0xeb, 0x15, + 0xff, 0xef, 0x01, 0x01, 0x00, 0x09, 0xe3, 0x09, 0x05, 0x01, 0xe3, 0x19, + 0x00, 0xf7, 0xfb, 0x05, 0xf7, 0x09, 0x00, 0xe7, 0x11, 0xfb, 0x05, 0xf7, + 0x01, 0x01, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0xe3, 0x15, 0x00, 0x00, + 0xeb, 0x19, 0xff, 0xeb, 0x0d, 0x09, 0xef, 0x00, 0x09, 0x01, 0xe3, 0x11, + 0x01, 0xf7, 0xf3, 0x1d, 0xe3, 0x01, 0x09, 0x01, 0xe7, 0x11, 0xf7, 0x09, + 0xfb, 0x01, 0x09, 0xe3, 0x09, 0x05, 0xff, 0xe7, 0x15, 0x00, 0x00, 0xe7, + 0x1d, 0xff, 0xef, 0x01, 0x09, 0xfb, 0xfb, 0x00, 0xff, 0x09, 0xfb, 0xf7, + 0x09, 0x00, 0xff, 0xff, 0x01, 0xf3, 0x0d, 0x01, 0xef, 0xff, 0x0d, 0x00, + 0xe7, 0x11, 0x01, 0xe7, 0x11, 0x01, 0xfb, 0xfb, 0x0d, 0xfb, 0xfb, 0x05, + 0x00, 0xfb, 0xff, 0x01, 0x05, 0xfb, 0xef, 0x15, 0xef, 0x01, 0x0d, 0xfb, + 0xeb, 0x21, 0xeb, 0xfb, 0x0d, 0x01, 0xeb, 0x09, 0x05, 0xff, 0xf3, 0x09, + 0xff, 0x00, 0x01, 0xfb, 0xf3, 0x15, 0xfb, 0xf3, 0x09, 0x00, 0x05, 0xeb, + 0x0d, 0x00, 0xfb, 0x05, 0xfb, 0x01, 0xff, 0x00, 0xff, 0xff, 0x01, 0x05, + 0xef, 0xff, 0x0d, 0x00, 0xeb, 0x19, 0xff, 0xeb, 0x0d, 0x00, 0xf7, 0xff, + 0x09, 0xff, 0xf3, 0x11, 0x00, 0xe7, 0x11, 0x00, 0x05, 0xe7, 0x11, 0x01, + 0xf3, 0x05, 0x00, 0x09, 0xe3, 0x11, 0x01, 0xeb, 0x0d, 0xfb, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0xff, 0x05, 0x05, 0xdf, 0x15, 0x00, 0xf7, 0xff, + 0x0d, 0xfb, 0xf7, 0x05, 0x00, 0x00, 0xfb, 0x01, 0xfb, 0x00, 0x01, 0x05, + 0xef, 0x09, 0xfb, 0x09, 0x00, 0xeb, 0x0d, 0xfb, 0x09, 0xeb, 0x09, 0x00, + 0x09, 0xe7, 0x05, 0x01, 0x01, 0xe3, 0x15, 0x00, 0xff, 0xf7, 0x0d, 0xf7, + 0x00, 0x09, 0xef, 0x01, 0x11, 0xef, 0xf7, 0x11, 0xff, 0xef, 0x09, 0xfb, + 0x01, 0x01, 0x00, 0xeb, 0x15, 0xff, 0xf7, 0x01, 0x00, 0x09, 0xf7, 0xf3, + 0x0d, 0x01, 0xf3, 0xfb, 0x11, 0x00, 0xeb, 0x0d, 0xfb, 0x00, 0x01, 0x00, + 0xf7, 0x00, 0x05, 0x01, 0xef, 0x09, 0x00, 0xff, 0xff, 0x09, 0xeb, 0x00, + 0x11, 0xfb, 0xe7, 0x19, 0xff, 0xfb, 0xfb, 0x11, 0xfb, 0xfb, 0x01, 0xfb, + 0x01, 0x05, 0xff, 0xf7, 0x0d, 0xff, 0xfb, 0x01, 0x00, 0xf7, 0x05, 0x05, + 0xf7, 0xff, 0x09, 0xf7, 0x00, 0x01, 0x05, 0xeb, 0x05, 0x09, 0xff, 0xeb, + 0x15, 0xfb, 0x05, 0xf7, 0xf3, 0x19, 0xff, 0xeb, 0x0d, 0x00, 0xff, 0xf3, + 0x09, 0xfb, 0x09, 0xef, 0x00, 0x01, 0xff, 0x00, 0xff, 0x09, 0xe7, 0x09, + 0x05, 0xf3, 0xff, 0x0d, 0x00, 0xe7, 0x11, 0x00, 0xf3, 0xfb, 0x0d, 0x00, + 0xeb, 0x0d, 0x01, 0xff, 0xf7, 0x09, 0xfb, 0x00, 0x01, 0x01, 0xef, 0x05, + 0x00, 0xff, 0x00, 0x09, 0xeb, 0x05, 0x09, 0xef, 0x01, 0x05, 0x00, 0xeb, + 0x0d, 0x00, 0xfb, 0xf3, 0x11, 0xfb, 0x00, 0x00, 0xfb, 0x05, 0xff, 0xff, + 0x00, 0x00, 0xff, 0x01, 0xef, 0x05, 0x09, 0xfb, 0xf3, 0x0d, 0xfb, 0x01, + 0xff, 0x00, 0xff, 0x01, 0x05, 0xef, 0x00, 0x0d, 0xfb, 0xf3, 0x09, 0x00, + 0xfb, 0xff, 0x01, 0x05, 0xf3, 0xff, 0x09, 0x00, 0xfb, 0xf7, 0x09, 0x01, + 0xf3, 0x01, 0x05, 0xf3, 0xff, 0x01, 0xfb, 0x05, 0x00, 0xf7, 0x05, 0xfb, + 0x01, 0x00, 0xf7, 0x05, 0x00, 0xf7, 0x09, 0x00, 0xeb, 0x0d, 0x01, 0xff, + 0xeb, 0x1d, 0xf7, 0xff, 0xf3, 0x11, 0xfb, 0xf7, 0x05, 0x00, 0xfb, 0xff, + 0x01, 0xfb, 0x00, 0x01, 0x01, 0xe7, 0x0d, 0xff, 0x05, 0xe7, 0x09, 0x01, + 0xff, 0xf3, 0x09, 0xfb, 0x09, 0xf7, 0xfb, 0x09, 0x00, 0xeb, 0x0d, 0x00, + 0xff, 0xef, 0x15, 0xff, 0xef, 0x09, 0x05, 0xef, 0x00, 0x09, 0xf3, 0xfb, + 0x09, 0x00, 0xf3, 0x05, 0xff, 0x09, 0xf3, 0xfb, 0x09, 0x01, 0xeb, 0x09, + 0x01, 0xeb, 0x0d, 0x00, 0xeb, 0x11, 0xff, 0xf7, 0x01, 0x05, 0xef, 0x01, + 0x05, 0xf3, 0x05, 0x00, 0x00, 0xff, 0xef, 0x11, 0x00, 0xf3, 0x09, 0xff, + 0x01, 0xff, 0xef, 0x09, 0x00, 0x01, 0xef, 0x09, 0x00, 0xfb, 0xff, 0x09, + 0xf3, 0x01, 0x05, 0xf7, 0xff, 0x01, 0x09, 0xef, 0xfb, 0x11, 0x00, 0xe7, + 0x11, 0x00, 0xef, 0x09, 0x00, 0x00, 0xef, 0x0d, 0xff, 0x00, 0x00, 0x05, + 0xe7, 0x05, 0x09, 0xff, 0xef, 0x0d, 0xff, 0x05, 0xe7, 0x0d, 0x01, 0x00, + 0xeb, 0x11, 0xfb, 0x00, 0x00, 0xf3, 0x09, 0x01, 0xff, 0xf3, 0x0d, 0xfb, + 0xff, 0x05, 0xff, 0xfb, 0x05, 0x01, 0xeb, 0x09, 0x01, 0xfb, 0xf7, 0x0d, + 0x00, 0xe7, 0x11, 0x00, 0x01, 0xeb, 0x15, 0xff, 0xf7, 0xff, 0x0d, 0xfb, + 0xef, 0x11, 0x00, 0xef, 0x01, 0x0d, 0xeb, 0x09, 0x01, 0x00, 0xef, 0x0d, + 0xf7, 0x09, 0xff, 0xf3, 0x09, 0xff, 0xfb, 0xff, 0x05, 0xfb, 0x00, 0x05, + 0x01, 0xdf, 0x1d, 0xfb, 0xfb, 0xfb, 0x0d, 0xfb, 0xf3, 0x09, 0xfb, 0x01, + 0x01, 0xef, 0x05, 0x01, 0x05, 0xeb, 0x09, 0x00, 0x05, 0xf7, 0xf7, 0x15, + 0xff, 0xef, 0x09, 0x05, 0xef, 0x09, 0x00, 0x00, 0xf3, 0x05, 0x00, 0xfb, + 0x00, 0x05, 0xfb, 0xeb, 0x19, 0xf7, 0x01, 0xef, 0x0d, 0x00, 0xfb, 0xfb, + 0x05, 0x00, 0x01, 0xf3, 0x00, 0x09, 0xfb, 0xf7, 0x09, 0x01, 0xf3, 0x01, + 0x05, 0xfb, 0xff, 0x0d, 0xf3, 0xf7, 0x11, 0x00, 0xef, 0x05, 0x00, 0x05, + 0xf3, 0xff, 0x05, 0xff, 0xff, 0x05, 0xef, 0x05, 0x05, 0xf3, 0xfb, 0x0d, + 0xff, 0x01, 0xef, 0x09, 0x01, 0xff, 0xf7, 0x05, 0x01, 0xf7, 0x05, 0x01, + 0xf7, 0xfb, 0x0d, 0xfb, 0xf7, 0x05, 0x00, 0xff, 0xff, 0x01, 0x05, 0xf7, + 0xf7, 0x11, 0xf7, 0xf7, 0x05, 0x05, 0xf7, 0xfb, 0x09, 0x00, 0xff, 0xfb, + 0x09, 0xf7, 0xfb, 0x0d, 0x00, 0xf3, 0x00, 0x0d, 0xf3, 0xf7, 0x11, 0xfb, + 0xff, 0x01, 0xff, 0xff, 0x09, 0xf3, 0xff, 0x09, 0x00, 0xf3, 0x01, 0x00, + 0x05, 0xfb, 0xff, 0x05, 0xfb, 0xf7, 0x09, 0x01, 0xe7, 0x11, 0x00, 0xff, + 0xef, 0x11, 0xff, 0xf3, 0x09, 0x00, 0xff, 0x00, 0xff, 0x00, 0x01, 0x00, + 0xf3, 0x09, 0x01, 0xfb, 0xf3, 0x15, 0xff, 0xeb, 0x11, 0x00, 0xef, 0x05, + 0xfb, 0x09, 0xf7, 0x01, 0x01, 0xf7, 0xff, 0x09, 0xfb, 0xfb, 0x01, 0x01, + 0x01, 0xe3, 0x15, 0xff, 0xff, 0xef, 0x11, 0xff, 0xf3, 0x00, 0x00, 0x05, + 0xfb, 0xf3, 0x11, 0xf3, 0x09, 0xfb, 0xf7, 0x0d, 0xfb, 0x00, 0xff, 0x05, + 0xff, 0xe7, 0x21, 0xef, 0x05, 0xfb, 0xff, 0x01, 0x01, 0xfb, 0xff, 0x01, + 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x05, 0xeb, 0x11, 0xff, 0xf3, 0x09, + 0x00, 0x01, 0xeb, 0x11, 0xfb, 0xf7, 0x09, 0xf7, 0x01, 0x01, 0xff, 0xfb, + 0x01, 0x00, 0xfb, 0x01, 0x01, 0xfb, 0xef, 0x19, 0xff, 0xeb, 0x09, 0x00, + 0x01, 0xfb, 0xf3, 0x11, 0x00, 0xf3, 0x00, 0x01, 0x01, 0x00, 0xf3, 0x09, + 0xfb, 0x09, 0xfb, 0xef, 0x15, 0xf7, 0x00, 0x00, 0xf7, 0x01, 0x01, 0xf7, + 0x05, 0x00, 0xff, 0xfb, 0xff, 0x09, 0x00, 0xeb, 0x0d, 0xff, 0x05, 0xf3, + 0xff, 0x0d, 0xfb, 0xf3, 0x09, 0x01, 0xf7, 0xff, 0x05, 0xf7, 0x01, 0xfb, + 0x00, 0x05, 0xf3, 0x01, 0x01, 0xf7, 0xff, 0x01, 0x01, 0xfb, 0xf3, 0x15, + 0xff, 0xf3, 0x05, 0x00, 0xfb, 0xff, 0x05, 0xf3, 0x05, 0x00, 0xfb, 0xff, + 0x01, 0x01, 0xfb, 0x01, 0xfb, 0x01, 0x01, 0xeb, 0x05, 0x01, 0xff, 0xfb, + 0x05, 0xff, 0x09, 0xef, 0x00, 0x09, 0x00, 0xef, 0x0d, 0x00, 0xf3, 0x05, + 0x00, 0x00, 0xf3, 0x15, 0xf3, 0xf3, 0x15, 0xf3, 0xfb, 0x09, 0x01, 0xef, + 0x05, 0xff, 0x01, 0x00, 0xf7, 0x01, 0x05, 0xf7, 0x00, 0x09, 0xe7, 0x0d, + 0x01, 0xfb, 0xf7, 0x09, 0x00, 0xef, 0x05, 0x01, 0xff, 0xf7, 0x05, 0xfb, + 0x05, 0xfb, 0xfb, 0x05, 0xfb, 0x01, 0x00, 0x00, 0xff, 0xff, 0x05, 0xff, + 0xfb, 0x01, 0x00, 0xff, 0xff, 0x01, 0x00, 0xf7, 0x09, 0xff, 0x01, 0xef, + 0x09, 0xfb, 0x09, 0xef, 0x00, 0x01, 0x01, 0xfb, 0xf7, 0x0d, 0xff, 0xf3, + 0x05, 0xff, 0x01, 0x00, 0xef, 0x0d, 0xff, 0x05, 0xff, 0xf3, 0x0d, 0x00, + 0xf7, 0xff, 0x05, 0xff, 0x05, 0xf7, 0xfb, 0x09, 0x01, 0xef, 0x01, 0x05, + 0x00, 0xef, 0x09, 0x00, 0x01, 0xeb, 0x0d, 0x00, 0xf3, 0x01, 0x05, 0x00, + 0xf3, 0x11, 0xff, 0xef, 0x11, 0xff, 0xff, 0xf7, 0x0d, 0xff, 0xef, 0x0d, + 0xff, 0x01, 0xeb, 0x0d, 0xff, 0x00, 0xfb, 0xff, 0x01, 0xfb, 0x00, 0x01, + 0x00, 0xe7, 0x19, 0xf7, 0xfb, 0x05, 0x00, 0x00, 0xf7, 0x01, 0x00, 0x00, + 0x00, 0xff, 0xfb, 0x05, 0xff, 0xff, 0x00, 0x00, 0x01, 0x05, 0xe7, 0x15, + 0x00, 0xfb, 0xfb, 0x01, 0x05, 0xf7, 0xfb, 0x09, 0x00, 0xff, 0x00, 0x01, + 0xf3, 0x0d, 0xff, 0xf3, 0x0d, 0x00, 0xff, 0xf3, 0x11, 0xff, 0xf7, 0x00, + 0x05, 0xff, 0xfb, 0xff, 0x05, 0x01, 0xf7, 0xf7, 0x11, 0x00, 0xf3, 0xff, + 0x09, 0xff, 0xff, 0x00, 0xff, 0x00, 0x01, 0xfb, 0xf7, 0x0d, 0x00, 0xf7, + 0x00, 0x00, 0x01, 0xff, 0xf7, 0x09, 0x00, 0xf3, 0x00, 0x05, 0xff, 0xef, + 0x11, 0xff, 0xf3, 0x05, 0x01, 0x00, 0xef, 0x11, 0xff, 0xf3, 0x05, 0x01, + 0xf7, 0xf7, 0x11, 0xff, 0xef, 0x0d, 0x00, 0xfb, 0xf7, 0x0d, 0xff, 0xef, + 0x0d, 0x00, 0x00, 0xf7, 0x09, 0x01, 0xf3, 0x01, 0x00, 0x05, 0xef, 0x01, + 0x05, 0x00, 0xef, 0x0d, 0xff, 0xff, 0xff, 0x05, 0xfb, 0x00, 0x01, 0x05, + 0xe3, 0x11, 0xff, 0x01, 0xff, 0xf3, 0x11, 0x00, 0xef, 0x09, 0x00, 0x00, + 0xef, 0x0d, 0xff, 0xfb, 0x01, 0x01, 0xf3, 0x00, 0x09, 0xfb, 0xfb, 0x00, + 0x00, 0x05, 0xf3, 0x05, 0x01, 0xf7, 0x00, 0x05, 0xfb, 0xfb, 0x05, 0x00, + 0xfb, 0xfb, 0x0d, 0xef, 0xfb, 0x0d, 0xff, 0xef, 0x09, 0x01, 0xfb, 0xf7, + 0x09, 0x01, 0xf7, 0xfb, 0x0d, 0xf7, 0xfb, 0x09, 0x00, 0xf3, 0x01, 0x09, + 0xfb, 0xf3, 0x11, 0xff, 0xef, 0x09, 0xff, 0x01, 0xef, 0x09, 0xff, 0x01, + 0xff, 0xff, 0xff, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x05, 0xef, 0xff, + 0x0d, 0xfb, 0xff, 0x01, 0xff, 0xfb, 0x00, 0x00, 0x01, 0xfb, 0xff, 0x0d, + 0xeb, 0x05, 0x01, 0x05, 0xeb, 0x09, 0x01, 0xfb, 0xf7, 0x0d, 0xf7, 0xff, + 0x09, 0x00, 0xf7, 0x00, 0x01, 0x01, 0xff, 0xf3, 0x11, 0xfb, 0xfb, 0xff, + 0x09, 0xf7, 0xf7, 0x11, 0xff, 0xef, 0x09, 0x00, 0x01, 0xef, 0x0d, 0xff, + 0x01, 0xf3, 0x05, 0x01, 0x00, 0xf3, 0x09, 0x00, 0xff, 0xff, 0x05, 0xff, + 0x00, 0x05, 0xfb, 0xef, 0x15, 0xff, 0xf3, 0x05, 0x05, 0xfb, 0xf3, 0x0d, + 0x00, 0xff, 0xf7, 0x09, 0xfb, 0xf7, 0x11, 0xf7, 0xfb, 0x05, 0x01, 0xfb, + 0xf7, 0x15, 0xf7, 0xef, 0x11, 0xff, 0xff, 0xfb, 0x01, 0x01, 0xff, 0xf7, + 0x09, 0xff, 0x00, 0xfb, 0x00, 0x01, 0xff, 0x05, 0xff, 0xf3, 0x11, 0xff, + 0xf3, 0x05, 0x00, 0x01, 0xef, 0x05, 0xff, 0x01, 0xfb, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0xe7, 0x0d, 0x00, 0xff, 0xf7, + 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x01, + 0xf3, 0x00, 0x01, 0x01, 0xef, 0x09, 0x00, 0xf7, 0x00, 0xff, 0x09, 0xf3, + 0xff, 0x05, 0x01, 0xef, 0x05, 0x01, 0x00, 0xef, 0x0d, 0xff, 0xfb, 0x01, + 0x05, 0xeb, 0x09, 0x00, 0xff, 0xf3, 0x0d, 0x00, 0xf7, 0x00, 0x01, 0x00, + 0xff, 0x01, 0xff, 0x00, 0x01, 0xff, 0xef, 0x0d, 0xfb, 0x01, 0xff, 0xfb, + 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xf7, 0x09, 0x00, 0xff, 0xfb, + 0x09, 0xf3, 0x05, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfb, 0x01, 0x01, 0xfb, + 0xfb, 0x09, 0x00, 0xfb, 0xff, 0x05, 0x01, 0xf3, 0x00, 0x09, 0xf7, 0x01, + 0xff, 0x00, 0x00, 0x00, 0x01, 0xf7, 0xff, 0x09, 0xff, 0xfb, 0x01, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, 0xf3, 0x05, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x05, 0xeb, 0x05, 0x01, 0xff, 0xf3, 0x09, 0xff, 0xf7, 0x05, + 0xfb, 0x05, 0xfb, 0xff, 0x05, 0xf7, 0x01, 0x01, 0x01, 0xef, 0x11, 0xff, + 0xf3, 0x05, 0x01, 0x00, 0xef, 0x11, 0xff, 0xf3, 0x05, 0xfb, 0x09, 0xf3, + 0x00, 0x05, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x01, 0x00, 0xfb, 0xfb, + 0x0d, 0xf7, 0xff, 0x05, 0x00, 0xf7, 0x00, 0x01, 0x01, 0xf7, 0x00, 0x00, + 0x01, 0x00, 0xfb, 0x01, 0x00, 0x00, 0x01, 0x00, 0xeb, 0x11, 0xfb, 0x05, + 0xf3, 0x05, 0x01, 0xf3, 0x01, 0x00, 0x00, 0xef, 0x11, 0xfb, 0xf7, 0x09, + 0xfb, 0xff, 0x01, 0x01, 0xf3, 0x01, 0x05, 0x00, 0xf7, 0x05, 0x00, 0xff, + 0xff, 0x00, 0x05, 0xfb, 0xfb, 0x05, 0x01, 0xfb, 0xf7, 0x11, 0xfb, 0xfb, + 0x05, 0x00, 0xf7, 0x00, 0x09, 0xf3, 0xff, 0x09, 0x00, 0xf3, 0x01, 0x05, + 0xff, 0xf7, 0x11, 0xfb, 0xf3, 0x11, 0xf3, 0x01, 0x00, 0x00, 0x01, 0xfb, + 0xf3, 0x11, 0xf7, 0x01, 0xfb, 0x00, 0x05, 0x00, 0xfb, 0xff, 0x01, 0x01, + 0xff, 0xf7, 0x05, 0x00, 0x01, 0xf3, 0x09, 0x01, 0xf7, 0x00, 0x01, 0x01, + 0xf7, 0xfb, 0x09, 0x01, 0xef, 0x01, 0x01, 0x01, 0xef, 0x05, 0x01, 0xf7, + 0x00, 0x05, 0x00, 0xf3, 0x0d, 0xff, 0xf3, 0x09, 0x01, 0xfb, 0xf7, 0x09, + 0x01, 0xf3, 0x05, 0xff, 0x05, 0xff, 0xef, 0x11, 0xfb, 0xff, 0xff, 0x05, + 0xfb, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0x00, + 0xeb, 0x19, 0xf7, 0xfb, 0x05, 0x00, 0xef, 0x0d, 0x00, 0x00, 0xef, 0x15, + 0xfb, 0xf3, 0x09, 0xff, 0xff, 0xf7, 0x0d, 0xfb, 0xf3, 0x09, 0xff, 0x01, + 0xef, 0x0d, 0x00, 0xf7, 0x05, 0x01, 0xfb, 0xfb, 0x09, 0x00, 0xef, 0x09, + 0xff, 0x01, 0xef, 0x09, 0xff, 0x01, 0xf7, 0xff, 0x05, 0xff, 0x00, 0xf3, + 0x0d, 0xff, 0xff, 0x00, 0x01, 0xff, 0x00, 0x01, 0xef, 0x05, 0x00, 0xff, + 0xfb, 0x00, 0x01, 0xfb, 0x00, 0x01, 0x01, 0xf3, 0x01, 0x05, 0xf3, 0x01, + 0x01, 0x00, 0xf3, 0x11, 0xfb, 0xf3, 0x09, 0xff, 0xff, 0xfb, 0x0d, 0xff, + 0xf3, 0x09, 0xff, 0x05, 0xef, 0x05, 0x01, 0xff, 0xf3, 0x09, 0x00, 0xf7, + 0x00, 0x09, 0xef, 0x01, 0x00, 0x05, 0xef, 0x05, 0x00, 0x01, 0xef, 0x09, + 0xff, 0x00, 0xef, 0x11, 0xfb, 0xff, 0xff, 0x01, 0xff, 0xff, 0x01, 0x05, + 0xeb, 0x09, 0x01, 0xfb, 0xfb, 0x09, 0xfb, 0xf3, 0x09, 0xff, 0x00, 0xff, + 0x00, 0x01, 0x00, 0xef, 0x09, 0xff, 0x01, 0x00, 0x00, 0xfb, 0x05, 0xff, + 0xef, 0x11, 0xff, 0xff, 0xfb, 0x05, 0xff, 0x05, 0xf7, 0xfb, 0x09, 0x00, + 0xfb, 0xf7, 0x0d, 0xfb, 0xff, 0x01, 0xff, 0xfb, 0x05, 0x01, 0xf3, 0x05, + 0x01, 0x01, 0xef, 0x09, 0x00, 0xfb, 0xff, 0x01, 0x00, 0xf7, 0x09, 0x00, + 0xf3, 0x09, 0x00, 0x01, 0xef, 0x09, 0xff, 0x01, 0xf3, 0x05, 0x00, 0x00, + 0xfb, 0xff, 0x01, 0xff, 0xff, 0x05, 0xf7, 0xff, 0x05, 0xff, 0xff, 0xff, + 0x05, 0xef, 0x05, 0x05, 0xfb, 0xf3, 0x09, 0x01, 0xfb, 0xf7, 0x09, 0x00, + 0xff, 0xf7, 0x0d, 0xff, 0xf7, 0x00, 0x05, 0xfb, 0xff, 0x09, 0xef, 0x00, + 0x05, 0x00, 0xef, 0x0d, 0x00, 0xfb, 0xfb, 0x09, 0x00, 0xf3, 0x01, 0x01, + 0xff, 0xf7, 0x05, 0xff, 0xff, 0xff, 0x01, 0xff, 0x00, 0xff, 0xff, 0x00, + 0xff, 0xff, 0x00, 0x01, 0xef, 0x01, 0x05, 0x00, 0xf7, 0x09, 0xf3, 0x05, + 0x00, 0x01, 0xf7, 0x00, 0x05, 0x00, 0xff, 0xf7, 0x0d, 0xfb, 0xff, 0x01, + 0x01, 0xf7, 0xfb, 0x0d, 0xfb, 0xf3, 0x11, 0xf7, 0x00, 0x01, 0xff, 0xff, + 0x00, 0x01, 0xff, 0xef, 0x19, 0xf7, 0xf7, 0x09, 0x00, 0xff, 0xfb, 0x05, + 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x09, 0x00, + 0xf3, 0x05, 0x00, 0x00, 0xf3, 0x0d, 0xff, 0xf7, 0x05, 0xff, 0x05, 0xf3, + 0x05, 0x05, 0xf7, 0x00, 0x05, 0xff, 0xfb, 0x05, 0x01, 0xf3, 0x01, 0x01, + 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xfb, 0x0d, 0xff, 0xf3, 0x0d, 0xfb, + 0x01, 0x00, 0xef, 0x0d, 0xfb, 0x01, 0xf7, 0xff, 0x01, 0xff, 0x00, 0xff, + 0x01, 0x01, 0xfb, 0xff, 0x01, 0x01, 0xff, 0xfb, 0x09, 0xf3, 0x01, 0x00, + 0x01, 0xf3, 0x01, 0x05, 0xf7, 0x00, 0x05, 0x01, 0xef, 0x09, 0x00, 0x00, + 0xf7, 0x05, 0x00, 0x00, 0xf7, 0x09, 0xfb, 0xfb, 0x01, 0x00, 0xfb, 0x00, + 0x05, 0xff, 0xf3, 0x11, 0xfb, 0xfb, 0x00, 0x01, 0x00, 0x05, 0xef, 0x09, + 0x01, 0xfb, 0xff, 0x05, 0x00, 0xff, 0xfb, 0x05, 0xff, 0x00, 0x00, 0xf3, + 0x05, 0x01, 0xf7, 0x00, 0x01, 0x01, 0xf3, 0x01, 0x00, 0x01, 0xf7, 0x09, + 0xfb, 0xff, 0x01, 0x01, 0xf3, 0x01, 0x00, 0x01, 0xf3, 0x00, 0x05, 0x00, + 0xef, 0x0d, 0xff, 0xff, 0xff, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, + 0xfb, 0x05, 0xff, 0xff, 0x01, 0xff, 0x00, 0xff, 0x00, 0x01, 0xf3, 0x09, + 0x00, 0x00, 0xf7, 0x09, 0x00, 0xf8, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xfc, 0xf0, 0x10, 0xfc, 0xf8, 0x04, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0c, 0xfc, 0x00, 0x00, 0x04, + 0xfc, 0xf8, 0x0b, 0x00, 0xf8, 0x00, 0x04, 0x00, 0xf8, 0x00, 0x00, 0x00, + 0xfc, 0x04, 0x00, 0xf5, 0x00, 0x00, 0x00, 0xf2, 0x07, 0x00, 0xf9, 0x00, + 0x04, 0x00, 0xf9, 0x04, 0x00, 0x00, 0xfc, 0x04, 0x00, 0x00, 0xf6, 0x07, + 0x00, 0x00, 0xf6, 0x07, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xfd, 0x00, + 0x00, 0x00, 0xfd, 0xfd, 0x00, 0xfd, 0x03, 0x00, 0xf7, 0x06, 0x00, 0xfd, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xf7, 0x03, 0x00, 0xfa, 0x00, 0x00, 0x00, + 0xf7, 0x03, 0x00, 0x00, 0xf7, 0x06, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xf5, + 0x09, 0x00, 0xfa, 0x00, 0x00, 0x00, 0xfa, 0x08, 0xfd, 0xfa, 0x06, 0xfd, + 0x05, 0xfb, 0x00, 0x03, 0x00, 0xfd, 0xfd, 0x08, 0x00, 0xfb, 0x03, 0x00, + 0xfb, 0x00, 0x00, 0x00, 0xfd, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, + 0x00, 0xf7, 0x07, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xfc, 0x00, 0x04, 0x00, 0xf8, 0x04, 0x00, 0x00, 0xfa, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x09, 0xfc, 0xfe, 0x02, 0x00, 0xfe, + 0xfe, 0x04, 0x00, 0xfb, 0x03, 0x00, 0xfe, 0x00, 0x03, 0x00, 0xfd, 0x03, + 0x00, 0xfe, 0xfe, 0x05, 0x00, 0xfb, 0x03, 0x00, 0xfd, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xfc, + 0x04, 0xff, 0xff, 0x01, 0x00, 0x00, 0xfd, 0x01, 0x00, 0x00, 0xfc, 0x02, + 0x00, 0x00, 0xff, 0x02, 0xff, 0x00, 0x01, 0x00, 0xfd, 0x02, 0x00, 0x00, + 0xfa, 0x03, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xfe, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x01, 0x00, 0x00, 0xfd, 0x01, + 0x00, 0xff, 0x00, 0x01, 0x00, 0xfe, 0x02, 0x00, 0xff, 0x01, 0x00, 0x00, + 0xff, 0x02, 0x00, 0xfe, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, + 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0x01, 0xf8, 0xf9, 0xf6, 0xee, 0xff, + 0xfb, 0xf7, 0xf5, 0xf5, 0x09, 0xea, 0x0f, 0x27, 0x48, 0x00, 0x25, 0xd5, + 0xe7, 0x23, 0x1c, 0xe7, 0x02, 0xc2, 0xab, 0xb6, 0xaf, 0xb5, 0xc8, 0xa1, + 0x07, 0x1a, 0xce, 0xeb, 0x0a, 0x33, 0x5f, 0x73, 0x63, 0x7f, 0x7f, 0x7d, + 0x7c, 0x52, 0x5b, 0x73, 0x64, 0xf2, 0xc9, 0xdf, 0xf8, 0xdb, 0xef, 0xd0, + 0xa4, 0x80, 0x8b, 0x80, 0x80, 0x80, 0x80, 0x89, 0xb2, 0xd3, 0xf7, 0xff, + 0xf1, 0xfe, 0x3f, 0x74, 0x77, 0x7f, 0x79, 0x68, 0x42, 0x10, 0xf7, 0xf1, + 0xf9, 0xf8, 0xdc, 0xa2, 0x9d, 0xc7, 0xb0, 0x80, 0x80, 0x97, 0xa2, 0xbf, + 0x17, 0x4d, 0x5f, 0x51, 0x5e, 0x7f, 0x7f, 0x7f, 0x7f, 0x72, 0x5a, 0x54, + 0x4d, 0x30, 0x16, 0xfc, 0xe8, 0xcf, 0xc0, 0xa0, 0x8d, 0x80, 0x80, 0x80, + 0x8d, 0xb3, 0xc3, 0xa0, 0xa3, 0xca, 0xdd, 0xe7, 0xf7, 0x03, 0x0a, 0x0b, + 0x1d, 0x30, 0x3d, 0x4f, 0x5d, 0x54, 0x51, 0x5a, 0x55, 0x46, 0x30, 0x2d, + 0x28, 0x04, 0xe6, 0xc7, 0xc3, 0xcf, 0xc7, 0xb5, 0xa8, 0xb0, 0xc7, 0xec, + 0xea, 0xf2, 0xfb, 0x09, 0x0a, 0x29, 0x49, 0x4b, 0x51, 0x36, 0x45, 0x5a, + 0x30, 0x00, 0xcc, 0xd2, 0xd1, 0xbe, 0xbc, 0xa8, 0x94, 0xa9, 0xd5, 0xe7, + 0xd6, 0xdf, 0xf7, 0x09, 0x19, 0x0d, 0x25, 0x3f, 0x49, 0x44, 0x3c, 0x39, + 0x2e, 0x30, 0x19, 0x08, 0x02, 0xf9, 0xff, 0x0c, 0x02, 0xfc, 0xf3, 0xe3, + 0xd2, 0xd3, 0xcc, 0xcd, 0xe1, 0xf0, 0xec, 0xe0, 0xc7, 0xcd, 0xd8, 0xe1, + 0xde, 0xeb, 0x0d, 0x2d, 0x39, 0x43, 0x43, 0x3f, 0x3a, 0x3e, 0x3f, 0x3c, + 0x22, 0x1c, 0x0d, 0xfe, 0xf0, 0xd1, 0xc6, 0xb6, 0xaa, 0xad, 0xb2, 0xb3, + 0xc5, 0xef, 0x03, 0x11, 0x1c, 0x19, 0x17, 0x1a, 0x17, 0x23, 0x31, 0x2e, + 0x37, 0x32, 0x1b, 0x06, 0xf8, 0xe5, 0xca, 0xcd, 0xd2, 0xd3, 0xd4, 0xd7, + 0xef, 0x06, 0xf0, 0xec, 0xf8, 0xf1, 0x07, 0x08, 0x0d, 0x14, 0x19, 0x10, + 0x0a, 0x04, 0xfc, 0x0c, 0x10, 0x0b, 0x12, 0x12, 0x22, 0x1e, 0x22, 0x10, + 0x04, 0x05, 0x00, 0xf0, 0xdf, 0xd4, 0xc6, 0xc9, 0xd3, 0xd3, 0xd5, 0xca, + 0xcc, 0xd1, 0xe5, 0xf3, 0x01, 0x0d, 0x2a, 0x39, 0x43, 0x43, 0x39, 0x28, + 0x1c, 0x1e, 0x18, 0x13, 0x08, 0x01, 0xf5, 0xe3, 0xd5, 0xd3, 0xce, 0xc2, + 0xbf, 0xcb, 0xdf, 0xf7, 0x07, 0x06, 0x0e, 0x1c, 0x12, 0x12, 0x10, 0x0c, + 0x08, 0x0d, 0x0b, 0x10, 0x0a, 0xfb, 0xfa, 0x00, 0xf8, 0xf1, 0xfb, 0xfc, + 0xfe, 0x07, 0x15, 0x10, 0x09, 0x00, 0xee, 0xe6, 0xdf, 0xdb, 0xdf, 0xdf, + 0xe8, 0xfa, 0xfc, 0xf3, 0xfa, 0xf4, 0xf8, 0x0a, 0x17, 0x20, 0x2a, 0x2b, + 0x33, 0x32, 0x21, 0x15, 0x06, 0xfc, 0xf2, 0xed, 0xe3, 0xda, 0xce, 0xc5, + 0xc2, 0xc3, 0xc8, 0xca, 0xd4, 0xe1, 0xec, 0xff, 0x15, 0x1d, 0x28, 0x30, + 0x31, 0x2e, 0x2e, 0x20, 0x12, 0x0c, 0x11, 0x16, 0x14, 0x14, 0x01, 0xf2, + 0xf4, 0xf5, 0xf6, 0xec, 0xe0, 0xe6, 0xe9, 0xf1, 0xfd, 0xf8, 0xf1, 0xec, + 0xe8, 0xe7, 0xee, 0xf6, 0xfb, 0x04, 0x00, 0xfd, 0x06, 0x0a, 0x0d, 0x0a, + 0x04, 0x0f, 0x1e, 0x24, 0x21, 0x08, 0xff, 0xfa, 0xf5, 0xee, 0xec, 0xe0, + 0xd5, 0xd0, 0xda, 0xed, 0xf7, 0xf7, 0xf4, 0xf9, 0x03, 0x05, 0x0d, 0x12, + 0x17, 0x1f, 0x25, 0x2c, 0x28, 0x1c, 0x08, 0xf7, 0xec, 0xe3, 0xe4, 0xea, + 0xef, 0xed, 0xef, 0xe8, 0xe1, 0xe0, 0xdf, 0xe0, 0xed, 0xf4, 0xff, 0x0b, + 0x11, 0x0d, 0x04, 0x05, 0x10, 0x10, 0x12, 0x12, 0x10, 0x09, 0x0a, 0x13, + 0x13, 0x14, 0x10, 0x0d, 0x0a, 0x03, 0x00, 0xf9, 0xf4, 0xf5, 0xf5, 0xf2, + 0xe7, 0xdf, 0xe3, 0xdd, 0xd3, 0xde, 0xe4, 0xec, 0xf3, 0xfd, 0xfb, 0x03, + 0x08, 0x0b, 0x08, 0x06, 0x0c, 0x17, 0x1b, 0x1c, 0x19, 0x11, 0x05, 0x01, + 0x04, 0x00, 0xf6, 0xf9, 0xf1, 0xf1, 0xf3, 0xef, 0xea, 0xef, 0xf7, 0x02, + 0x00, 0xfc, 0x00, 0xfe, 0x07, 0x18, 0x19, 0x16, 0x0e, 0x08, 0xfc, 0xf6, + 0xec, 0xea, 0xf0, 0xf1, 0xfa, 0xf7, 0xf8, 0xef, 0xe9, 0xe5, 0xeb, 0xe8, + 0xea, 0xf2, 0xfe, 0x04, 0x06, 0x0c, 0x11, 0x0d, 0x09, 0x08, 0x06, 0x0a, + 0x10, 0x12, 0x0e, 0x10, 0x0a, 0x05, 0x04, 0x05, 0x03, 0xff, 0xfe, 0x04, + 0xff, 0xfa, 0xf4, 0xf3, 0xf1, 0xea, 0xe7, 0xe6, 0xe4, 0xe7, 0xe7, 0xf7, + 0xfa, 0xfc, 0x03, 0x06, 0x03, 0x06, 0x00, 0xff, 0x04, 0x10, 0x13, 0x13, + 0x12, 0x08, 0x00, 0xfa, 0xf1, 0xea, 0xe7, 0xe7, 0xf2, 0xfd, 0xfc, 0xfc, + 0xfd, 0x06, 0x08, 0x0d, 0x13, 0x12, 0x12, 0x10, 0x12, 0x11, 0x0c, 0x06, + 0xfd, 0xf9, 0xf2, 0xe9, 0xe7, 0xe6, 0xe1, 0xe5, 0xe7, 0xeb, 0xf5, 0x04, + 0x05, 0x04, 0x04, 0x06, 0x0c, 0x0c, 0x09, 0x07, 0x04, 0xff, 0xf8, 0xef, + 0xe9, 0xe4, 0xeb, 0xf4, 0xfa, 0x01, 0x0b, 0x0a, 0x07, 0x06, 0x0a, 0x0b, + 0x0c, 0x0c, 0x10, 0x10, 0x09, 0x00, 0xf7, 0xef, 0xef, 0xe9, 0xe6, 0xe5, + 0xf1, 0xf2, 0xf5, 0xf9, 0xff, 0x0b, 0x15, 0x16, 0x13, 0x15, 0x14, 0x11, + 0x0c, 0x0b, 0x05, 0x00, 0xf6, 0xec, 0xe4, 0xd7, 0xd9, 0xd9, 0xdf, 0xef, + 0xfa, 0xff, 0x03, 0x0a, 0x10, 0x10, 0x10, 0x12, 0x0c, 0x0c, 0x10, 0x0a, + 0x02, 0xfb, 0xfc, 0xf7, 0xf0, 0xee, 0xf5, 0xfd, 0xff, 0xff, 0x01, 0xfe, + 0xff, 0x05, 0x08, 0x07, 0x07, 0x01, 0xf8, 0xf0, 0xef, 0xeb, 0xe4, 0xe4, + 0xe2, 0xe6, 0xe7, 0xef, 0xf1, 0xf8, 0x04, 0x10, 0x1d, 0x28, 0x2c, 0x29, + 0x20, 0x18, 0x16, 0x10, 0x05, 0xff, 0xf4, 0xea, 0xe6, 0xe4, 0xe2, 0xdc, + 0xdf, 0xe4, 0xec, 0xf3, 0xff, 0x08, 0x0c, 0x10, 0x17, 0x17, 0x14, 0x10, + 0x0b, 0x00, 0xf4, 0xf6, 0xf6, 0xf3, 0xf5, 0xef, 0xe8, 0xe7, 0xed, 0xf7, + 0x00, 0x04, 0x09, 0x09, 0x0b, 0x11, 0x14, 0x11, 0x08, 0xfe, 0xfa, 0xf1, + 0xf4, 0xf0, 0xea, 0xe9, 0xe9, 0xeb, 0xee, 0xf4, 0xfb, 0xff, 0x03, 0x12, + 0x1e, 0x29, 0x28, 0x22, 0x12, 0x07, 0xfe, 0xf1, 0xef, 0xea, 0xe3, 0xdd, + 0xd8, 0xdd, 0xe2, 0xe3, 0xec, 0xf5, 0xfb, 0x06, 0x12, 0x18, 0x18, 0x19, + 0x1b, 0x1c, 0x1d, 0x1b, 0x10, 0x08, 0xfd, 0xee, 0xe8, 0xe5, 0xe7, 0xea, + 0xec, 0xec, 0xef, 0xf9, 0xfb, 0xff, 0x09, 0x12, 0x10, 0x10, 0x18, 0x12, + 0x05, 0xfa, 0xf4, 0xec, 0xea, 0xea, 0xed, 0xec, 0xf1, 0xf6, 0xfb, 0xfd, + 0x06, 0x0b, 0x0f, 0x10, 0x13, 0x10, 0x10, 0x0c, 0x01, 0xfa, 0xf4, 0xee, + 0xe5, 0xe0, 0xde, 0xde, 0xdd, 0xe1, 0xef, 0xff, 0x08, 0x0d, 0x11, 0x12, + 0x16, 0x1d, 0x1e, 0x23, 0x26, 0x20, 0x16, 0x09, 0xfc, 0xec, 0xe3, 0xdf, + 0xe1, 0xe2, 0xe4, 0xe7, 0xeb, 0xf3, 0xf5, 0xf5, 0xf6, 0xfc, 0x04, 0x0d, + 0x11, 0x0d, 0x09, 0x0a, 0x08, 0x04, 0xfe, 0xf7, 0xf2, 0xf2, 0xf7, 0xfa, + 0x01, 0x05, 0x08, 0x08, 0x0a, 0x0c, 0x0c, 0x0c, 0x0a, 0x00, 0xfd, 0xfd, + 0xfa, 0xf6, 0xee, 0xe7, 0xdf, 0xe1, 0xe6, 0xed, 0xf1, 0xf6, 0x01, 0x0a, + 0x0f, 0x12, 0x12, 0x10, 0x13, 0x12, 0x0d, 0x0c, 0x08, 0x02, 0xfe, 0xf5, + 0xeb, 0xe1, 0xe1, 0xe3, 0xe8, 0xeb, 0xf1, 0xf6, 0xfb, 0x04, 0x0d, 0x0e, + 0x0c, 0x0f, 0x10, 0x14, 0x16, 0x10, 0x02, 0xfd, 0xfa, 0xf7, 0xf6, 0xf2, + 0xf0, 0xf3, 0xf3, 0xf5, 0xfb, 0x00, 0x02, 0x06, 0x08, 0x06, 0x05, 0x00, + 0xfe, 0xfc, 0xf8, 0xf7, 0xf7, 0xf5, 0xf7, 0xf3, 0xed, 0xed, 0xef, 0xf4, + 0xf7, 0x00, 0x06, 0x0a, 0x12, 0x13, 0x11, 0x0d, 0x0b, 0x0c, 0x05, 0x03, + 0xff, 0xf4, 0xee, 0xed, 0xea, 0xea, 0xe9, 0xed, 0xf2, 0xf8, 0xfa, 0x01, + 0x05, 0x0c, 0x13, 0x15, 0x16, 0x15, 0x10, 0x09, 0x04, 0xff, 0xfb, 0xf9, + 0xf8, 0xf5, 0xf1, 0xed, 0xe8, 0xeb, 0xf2, 0xf3, 0xf7, 0xfd, 0xff, 0x03, + 0x08, 0x07, 0x04, 0x06, 0x05, 0x08, 0x0a, 0x06, 0x01, 0xfa, 0xf7, 0xfb, + 0xfe, 0xf9, 0xfb, 0xfc, 0xfb, 0xf9, 0xf8, 0xf7, 0xf9, 0xfb, 0xfc, 0xfd, + 0xff, 0xfc, 0xf7, 0xf8, 0xf9, 0xf2, 0xf3, 0xf8, 0xfd, 0xff, 0xfe, 0x03, + 0x05, 0x0a, 0x0e, 0x10, 0x0d, 0x0e, 0x0d, 0x0b, 0x09, 0x08, 0x01, 0xfb, + 0xf7, 0xf9, 0xf5, 0xf1, 0xf1, 0xf5, 0xf7, 0xf7, 0xf7, 0xfb, 0xfd, 0xfd, + 0xff, 0xff, 0xfd, 0xff, 0x05, 0x07, 0x05, 0x02, 0x04, 0x02, 0xfd, 0xf8, + 0xf4, 0xf3, 0xf3, 0xf3, 0xf4, 0xf5, 0xf6, 0xf5, 0xf7, 0xf8, 0xfa, 0xfb, + 0xfc, 0x02, 0x05, 0x05, 0x08, 0x09, 0x08, 0x07, 0x07, 0x05, 0x04, 0x07, + 0x0b, 0x0b, 0x0b, 0x09, 0x08, 0x03, 0x00, 0x00, 0xfe, 0xfd, 0xfc, 0xfc, + 0xf7, 0xf6, 0xf5, 0xef, 0xed, 0xef, 0xf1, 0xf1, 0xf1, 0xef, 0xf0, 0xef, + 0xf2, 0xf5, 0xf6, 0xfb, 0x02, 0x04, 0x03, 0x05, 0x07, 0x09, 0x0b, 0x0a, + 0x08, 0x09, 0x06, 0x03, 0x01, 0xfe, 0xfe, 0xfb, 0xfd, 0xfd, 0xff, 0x00, + 0xfc, 0xfb, 0xfe, 0xff, 0xff, 0x00, 0xff, 0x01, 0x00, 0x00, 0x01, 0x00, + 0xff, 0x01, 0xff, 0xfd, 0xfe, 0xfb, 0xf6, 0xf4, 0xf4, 0xf2, 0xf5, 0xf9, + 0xfb, 0xf8, 0xf7, 0xfa, 0xfa, 0xfb, 0xff, 0x02, 0x02, 0x01, 0xff, 0xfd, + 0xfd, 0xfc, 0xfb, 0xfe, 0x02, 0x03, 0x05, 0x04, 0x01, 0xfe, 0x00, 0x03, + 0x04, 0x04, 0x07, 0x08, 0x06, 0x04, 0x04, 0x00, 0xfe, 0xfd, 0xfd, 0xf9, + 0xf7, 0xf7, 0xf3, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf5, 0xf6, 0xf5, 0xf5, + 0xf8, 0xff, 0x01, 0x00, 0x03, 0x06, 0x02, 0xfe, 0xff, 0x01, 0x01, 0x02, + 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x06, 0x06, 0x06, 0x06, 0x05, 0x00, + 0xfd, 0xfc, 0xfb, 0xf9, 0xf8, 0xf7, 0xf8, 0xf7, 0xf9, 0xf9, 0xfb, 0xfd, + 0xfc, 0xfd, 0xff, 0xff, 0x00, 0x02, 0x02, 0x01, 0xff, 0xfc, 0xf7, 0xf6, + 0xf5, 0xf2, 0xf2, 0xf1, 0xf1, 0xf1, 0xf4, 0xf5, 0xfa, 0xff, 0x02, 0x07, + 0x0d, 0x10, 0x11, 0x13, 0x13, 0x11, 0x0f, 0x10, 0x0c, 0x06, 0x00, 0xfb, + 0xf7, 0xf4, 0xf3, 0xf1, 0xf1, 0xf2, 0xf4, 0xf6, 0xf7, 0xf9, 0xfa, 0xfa, + 0xfa, 0xfe, 0x00, 0x01, 0x00, 0x01, 0x00, 0xfd, 0xfd, 0xfb, 0xfc, 0xfd, + 0xfc, 0xfc, 0xfd, 0xff, 0x01, 0x01, 0x04, 0x05, 0x05, 0x05, 0x06, 0x04, + 0x00, 0xff, 0xfe, 0xfb, 0xf9, 0xf8, 0xf5, 0xf2, 0xf0, 0xf3, 0xf7, 0xfc, + 0xff, 0x00, 0x04, 0x07, 0x0a, 0x0a, 0x07, 0x07, 0x07, 0x05, 0x02, 0xfe, + 0xf8, 0xf5, 0xef, 0xed, 0xee, 0xef, 0xef, 0xf2, 0xf5, 0xf8, 0xfc, 0xfe, + 0xff, 0x04, 0x09, 0x0e, 0x11, 0x10, 0x0c, 0x08, 0x06, 0x03, 0x01, 0x02, + 0x00, 0xfe, 0xfc, 0xfd, 0xfc, 0xfb, 0xfa, 0xfb, 0xfc, 0xff, 0xfe, 0xfe, + 0xfe, 0xfb, 0xf9, 0xf7, 0xf6, 0xf6, 0xf5, 0xf2, 0xef, 0xf0, 0xf2, 0xf5, + 0xfa, 0xfe, 0xff, 0x04, 0x09, 0x0f, 0x10, 0x10, 0x10, 0x0e, 0x0b, 0x07, + 0x03, 0xff, 0xf8, 0xf3, 0xef, 0xee, 0xf0, 0xf1, 0xef, 0xf2, 0xf5, 0xf5, + 0xf9, 0xfe, 0x03, 0x07, 0x0b, 0x0d, 0x10, 0x11, 0x10, 0x09, 0x02, 0xfe, + 0xfc, 0xfb, 0xfa, 0xf8, 0xf3, 0xf2, 0xf4, 0xf2, 0xf2, 0xf4, 0xf7, 0xf9, + 0xfa, 0xfc, 0xfe, 0x00, 0x00, 0xff, 0xfd, 0xfc, 0xfd, 0xfd, 0xfc, 0xfc, + 0xfb, 0xfd, 0x00, 0x01, 0x07, 0x0b, 0x0b, 0x0c, 0x0d, 0x0c, 0x0c, 0x08, + 0x06, 0x03, 0xff, 0xfb, 0xf7, 0xf1, 0xee, 0xed, 0xeb, 0xea, 0xed, 0xf0, + 0xf3, 0xf6, 0xfc, 0x01, 0x04, 0x07, 0x0b, 0x0e, 0x10, 0x10, 0x0e, 0x09, + 0x05, 0x02, 0xfd, 0xf9, 0xf5, 0xf0, 0xee, 0xef, 0xef, 0xef, 0xf1, 0xf3, + 0xf9, 0xfe, 0x00, 0x05, 0x06, 0x05, 0x07, 0x08, 0x07, 0x05, 0x04, 0x02, + 0x00, 0xff, 0xfd, 0xfc, 0xfb, 0xfd, 0xff, 0xff, 0x01, 0x02, 0x02, 0x01, + 0x00, 0xff, 0xfb, 0xf9, 0xf9, 0xf9, 0xf7, 0xf5, 0xf3, 0xf0, 0xef, 0xf0, + 0xf2, 0xf5, 0xf9, 0xff, 0x05, 0x08, 0x0d, 0x10, 0x11, 0x12, 0x11, 0x10, + 0x0d, 0x0a, 0x06, 0x00, 0xfa, 0xf6, 0xf3, 0xef, 0xed, 0xed, 0xeb, 0xec, + 0xf0, 0xf4, 0xf9, 0xfe, 0x02, 0x06, 0x08, 0x08, 0x08, 0x07, 0x04, 0x03, + 0x03, 0x03, 0x01, 0x00, 0xfd, 0xf9, 0xf7, 0xfa, 0xfc, 0xfc, 0xfd, 0xfc, + 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xff, 0xff, 0xfe, 0xfc, 0xfc, 0xfb, + 0xf9, 0xfb, 0xfd, 0x00, 0x01, 0x02, 0x04, 0x06, 0x07, 0x08, 0x09, 0x08, + 0x07, 0x06, 0x05, 0x02, 0x00, 0xfb, 0xf7, 0xf5, 0xf2, 0xf2, 0xf2, 0xf2, + 0xf2, 0xf5, 0xf8, 0xfb, 0xfe, 0x00, 0x02, 0x05, 0x07, 0x07, 0x05, 0x04, + 0x04, 0x01, 0x00, 0xff, 0xfd, 0xfc, 0xfd, 0xfd, 0xfc, 0xfc, 0xfd, 0xfd, + 0xfd, 0xfd, 0xfd, 0xff, 0x00, 0x01, 0x03, 0x04, 0x03, 0x03, 0x01, 0xff, + 0xfc, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x02, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, + 0xfc, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, + 0x03, 0x03, 0x01, 0x00, 0x00, 0xff, 0xfd, 0xfc, 0xfa, 0xf9, 0xf9, 0xf9, + 0xf9, 0xfa, 0xfb, 0xfc, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0xff, 0xfe, 0xfe, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfb, 0xfc, 0xfb, 0xfc, + 0xfb, 0xfb, 0xfd, 0xfe, 0x00, 0x01, 0x02, 0x02, 0x03, 0x03, 0x04, 0x03, + 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0xfd, 0xfe, + 0xfe, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x43, 0xc8, 0x18, 0x65, 0xbb, 0xbb, 0x2b, 0x07, + 0xfd, 0xe1, 0xb4, 0x5f, 0x38, 0xb2, 0xd0, 0x40, 0x06, 0x7f, 0x0f, 0x37, + 0xfc, 0xb7, 0x13, 0x64, 0x08, 0x0f, 0x1f, 0x40, 0xf3, 0xd2, 0xa8, 0x44, + 0x63, 0x2e, 0x1a, 0x01, 0x99, 0xfc, 0x57, 0xe3, 0x30, 0xe3, 0xa7, 0xb5, + 0x61, 0x4e, 0xf3, 0x33, 0xf1, 0xea, 0x09, 0xc3, 0xd0, 0x62, 0xbb, 0xe3, + 0xcc, 0xba, 0x24, 0xb1, 0xe0, 0xca, 0x07, 0x02, 0xa2, 0xcf, 0xee, 0xd6, + 0xc3, 0x01, 0xf6, 0xd5, 0xac, 0xe4, 0xa8, 0xec, 0x2a, 0xed, 0xc3, 0x2c, + 0x03, 0xf6, 0xce, 0xf6, 0xff, 0x35, 0xf1, 0xa0, 0x0e, 0xba, 0x0f, 0x2e, + 0x3a, 0x48, 0xf0, 0xaa, 0xcd, 0x01, 0xe4, 0xf6, 0xf3, 0x02, 0x01, 0x17, + 0x13, 0x22, 0x61, 0xf8, 0xdb, 0x37, 0xee, 0x12, 0x35, 0x3f, 0x20, 0x49, + 0x58, 0x42, 0x6e, 0x63, 0x3e, 0xfc, 0x5f, 0x43, 0x42, 0x08, 0x33, 0x7f, + 0x22, 0x49, 0x54, 0x37, 0x35, 0xf2, 0x5e, 0x18, 0x59, 0x38, 0x20, 0x04, + 0x53, 0x03, 0x2a, 0x27, 0x1a, 0x1c, 0x15, 0x0f, 0x0d, 0x06, 0x0a, 0xfe, + 0xfb, 0xff, 0xfc, 0xf9, 0xfc, 0xf9, 0xf2, 0xec, 0xed, 0xed, 0xe2, 0xd9, + 0xe6, 0xdd, 0xd8, 0xd6, 0xe3, 0xd4, 0xcb, 0xd4, 0xdd, 0xea, 0xbf, 0x9e, + 0x9b, 0x84, 0x9a, 0xa2, 0xa7, 0xad, 0x9d, 0xa3, 0xa3, 0xae, 0xa9, 0xa9, + 0xc3, 0xbe, 0xc5, 0xc4, 0xa6, 0xd1, 0xbb, 0xd4, 0xd7, 0xdc, 0xed, 0xd1, + 0xe0, 0x18, 0xf8, 0xc5, 0x18, 0x07, 0xeb, 0x04, 0x1b, 0x7f, 0x00, 0x28, + 0x7f, 0x0f, 0x1b, 0x4b, 0x51, 0x14, 0xc8, 0x3e, 0x7c, 0x2d, 0x15, 0x35, + 0x4a, 0xd4, 0xbb, 0x1b, 0xee, 0x2d, 0x0c, 0x0d, 0x2b, 0x50, 0x02, 0xec, + 0x0c, 0xfd, 0x05, 0x22, 0x31, 0x14, 0x2a, 0x25, 0x13, 0x3e, 0x48, 0x36, + 0x20, 0xd4, 0x26, 0x3d, 0x1d, 0x25, 0x2f, 0x1c, 0x26, 0x2b, 0x11, 0xf2, + 0x0a, 0x32, 0x2a, 0xda, 0xea, 0x19, 0xec, 0x04, 0x17, 0x01, 0x1e, 0xf1, + 0xd1, 0xe6, 0xeb, 0x04, 0x23, 0xfb, 0xec, 0xcc, 0x9b, 0xec, 0x15, 0xea, + 0x04, 0xb9, 0xc4, 0x06, 0xb7, 0x88, 0xb9, 0xcc, 0xd9, 0xc0, 0xae, 0xaf, + 0xba, 0xb8, 0xc3, 0xd7, 0xc8, 0xbb, 0xd4, 0xc9, 0xd9, 0xd6, 0xe0, 0xe1, + 0x1b, 0xc4, 0xd0, 0xf0, 0xdb, 0xed, 0x0e, 0x25, 0x05, 0xfd, 0x05, 0x0f, + 0x06, 0xf6, 0x0a, 0x0a, 0x1c, 0x0e, 0x1f, 0x1f, 0x0d, 0x17, 0x1d, 0x1c, + 0x23, 0x25, 0x32, 0x4e, 0x4f, 0x2d, 0xd8, 0x5b, 0x54, 0x7f, 0x43, 0x3f, + 0x3f, 0x51, 0x29, 0x4e, 0x4f, 0x34, 0x3c, 0x35, 0x3d, 0x2a, 0x2d, 0x30, + 0x01, 0x07, 0x32, 0x0e, 0xfc, 0x61, 0x21, 0x27, 0x0e, 0x1a, 0x24, 0x01, + 0xc3, 0x98, 0x20, 0xe7, 0xc9, 0xfb, 0xec, 0x39, 0xff, 0xb7, 0xf6, 0x18, + 0xec, 0xfa, 0x00, 0x1f, 0xee, 0xf9, 0xfc, 0x01, 0x08, 0xf6, 0xd4, 0xdb, + 0xfc, 0xf9, 0xf2, 0xfe, 0xf9, 0xf6, 0xdc, 0xe1, 0xec, 0xe7, 0xe4, 0x0c, + 0xe0, 0x01, 0xdb, 0xa7, 0xe2, 0x25, 0xcd, 0x8e, 0xbe, 0xfe, 0xf7, 0xc3, + 0xbb, 0xc9, 0xd6, 0x1b, 0xf1, 0x9e, 0x00, 0x18, 0xe8, 0xbd, 0x01, 0x02, + 0xd6, 0xf0, 0xfc, 0x00, 0xc1, 0xf8, 0xe9, 0x0e, 0x1d, 0xe6, 0x10, 0x0a, + 0xee, 0xe8, 0xf1, 0xfb, 0x19, 0x10, 0x17, 0x21, 0x22, 0x17, 0x50, 0xf8, + 0x21, 0x56, 0x09, 0x0b, 0xe5, 0x2b, 0x70, 0x63, 0x27, 0xeb, 0x3d, 0x4a, + 0xea, 0x1c, 0x2f, 0x0a, 0x01, 0x3b, 0x01, 0x07, 0x19, 0x07, 0xf1, 0x46, + 0x0b, 0x4d, 0x2c, 0x1f, 0x04, 0xdb, 0x22, 0x28, 0x0f, 0x1e, 0x2d, 0xe6, + 0xf6, 0x33, 0x16, 0x03, 0xfd, 0x1b, 0xeb, 0xd9, 0xbe, 0x35, 0xfe, 0xf3, + 0x16, 0xec, 0xfe, 0xe6, 0xed, 0xc9, 0xf8, 0x14, 0xe9, 0x10, 0xdb, 0xfa, + 0xd2, 0xdf, 0x15, 0xc6, 0xd6, 0xf6, 0x02, 0x8c, 0x16, 0x47, 0xe6, 0x12, + 0xb6, 0xdd, 0x0b, 0xcc, 0x05, 0x0d, 0xd7, 0xb2, 0xb0, 0x03, 0xbc, 0x0e, + 0xae, 0xdc, 0xfe, 0xb4, 0x0f, 0x3c, 0xd5, 0xa5, 0xfb, 0x1c, 0xfc, 0xb2, + 0xec, 0xeb, 0xed, 0x35, 0x12, 0xa1, 0x22, 0x1f, 0xde, 0xd8, 0x08, 0x01, + 0x3f, 0x0f, 0xb4, 0x26, 0x2f, 0x2a, 0x1d, 0xe1, 0xfc, 0x4c, 0x47, 0xef, + 0xfb, 0xdb, 0xfb, 0xfd, 0x2f, 0x27, 0x25, 0x0b, 0xc0, 0x2b, 0xff, 0xcf, + 0x1a, 0xfe, 0x0c, 0x57, 0x11, 0x0d, 0x74, 0xc5, 0xdd, 0x57, 0x3c, 0xe9, + 0xdb, 0x4f, 0x06, 0xe5, 0x11, 0xfd, 0x0c, 0x2e, 0x16, 0x2a, 0x16, 0xab, + 0x3a, 0x3e, 0x2a, 0xfe, 0xbb, 0x38, 0xcd, 0xd4, 0x17, 0x3d, 0x3e, 0xf6, + 0xf3, 0x29, 0xe8, 0xe8, 0x5f, 0xd7, 0x15, 0xc9, 0x1a, 0x1f, 0xbd, 0xdd, + 0x58, 0xc2, 0xf1, 0x40, 0x1f, 0xf7, 0x09, 0x07, 0xd4, 0xff, 0xe7, 0xf9, + 0xce, 0xcb, 0x04, 0x12, 0xc9, 0xdc, 0x15, 0xd7, 0xc1, 0xc0, 0xe1, 0x15, + 0xa0, 0xc4, 0xec, 0xcb, 0x0c, 0x26, 0xf7, 0x34, 0xa7, 0xf0, 0x05, 0xb2, + 0xec, 0xc0, 0xfe, 0x03, 0xd0, 0xc7, 0x21, 0xfc, 0xaa, 0x21, 0xf8, 0x31, + 0xff, 0xf2, 0x29, 0x5d, 0xf9, 0xcd, 0xf2, 0x0d, 0xf2, 0x3a, 0x61, 0x3d, + 0xf9, 0x00, 0xcc, 0x0b, 0x3f, 0x0f, 0x25, 0xdc, 0xfc, 0x49, 0x3c, 0xfe, + 0xe6, 0x44, 0xf4, 0xc4, 0xf8, 0x1b, 0xe8, 0xf0, 0x52, 0x3c, 0xb5, 0xe9, + 0x4a, 0xf3, 0xe5, 0x00, 0x0d, 0x0d, 0xfe, 0x4e, 0xb1, 0xe9, 0x46, 0x3a, + 0x1d, 0x1b, 0xfb, 0x00, 0x05, 0xdc, 0xfa, 0xe4, 0xb8, 0xf4, 0xdf, 0x07, + 0x3c, 0x10, 0x13, 0x1e, 0xc9, 0x9a, 0x26, 0xfc, 0xbd, 0xea, 0x31, 0x3b, + 0x33, 0xf4, 0xd6, 0xed, 0x15, 0xe2, 0x28, 0x0d, 0xc4, 0xef, 0x45, 0xeb, + 0x32, 0xc2, 0xfe, 0xf6, 0x25, 0x1c, 0xf4, 0x18, 0x0c, 0x0d, 0x06, 0xfa, + 0xe6, 0xe7, 0xdc, 0xc9, 0xdc, 0x09, 0xf4, 0x01, 0x1b, 0xd8, 0xfe, 0xdb, + 0xec, 0xdf, 0xd7, 0xe6, 0xf6, 0x08, 0x4a, 0xb9, 0xd3, 0xf7, 0xfb, 0xf2, + 0xf6, 0xfd, 0x01, 0x05, 0xcb, 0x1a, 0x06, 0xdc, 0x31, 0x1f, 0xfa, 0xb9, + 0xfe, 0x3f, 0x42, 0xca, 0xf0, 0x44, 0xf2, 0xf8, 0xe7, 0x49, 0xff, 0xd3, + 0x36, 0x13, 0xf6, 0x62, 0x29, 0x0c, 0x2c, 0xf7, 0xd2, 0x00, 0x0e, 0x48, + 0xda, 0xf4, 0x5d, 0xfb, 0xfd, 0x23, 0x31, 0x1c, 0xca, 0x24, 0x25, 0xc3, + 0xfa, 0xf6, 0x4d, 0xfe, 0x15, 0x3b, 0xf2, 0xc8, 0xaa, 0x0a, 0x19, 0xfa, + 0x94, 0xef, 0x38, 0x27, 0xd0, 0x02, 0x27, 0xb5, 0xac, 0xe9, 0xba, 0x1c, + 0x41, 0xf2, 0xa7, 0xef, 0xcb, 0x11, 0xb4, 0xe0, 0x08, 0xe5, 0x00, 0x27, + 0xf0, 0xf2, 0xd9, 0xf8, 0xd3, 0xdb, 0x08, 0x34, 0xf5, 0x23, 0xe9, 0xc4, + 0x0e, 0x3f, 0xf4, 0xe5, 0x04, 0x31, 0x3d, 0x1d, 0x33, 0x23, 0x0b, 0x17, + 0xfa, 0x09, 0xfd, 0x38, 0xe1, 0x05, 0x3b, 0xef, 0xf5, 0x25, 0x47, 0x01, + 0xfe, 0x2a, 0x1f, 0xd2, 0xc8, 0x3d, 0x12, 0xbb, 0x0b, 0x0c, 0xcd, 0xdf, + 0x4f, 0x2e, 0xbc, 0xfe, 0xbf, 0x1d, 0x06, 0xdf, 0xea, 0x05, 0xff, 0x05, + 0xdc, 0x37, 0x0b, 0x97, 0xf5, 0x1e, 0x2c, 0xdb, 0xe7, 0x05, 0xc8, 0x14, + 0xf2, 0xe7, 0x24, 0xe2, 0x04, 0x30, 0xc6, 0x16, 0x44, 0xa3, 0x0a, 0xf5, + 0xd8, 0xde, 0x0d, 0xd9, 0xe8, 0x37, 0x2a, 0xd3, 0x07, 0x1b, 0xb7, 0xf5, + 0x04, 0x00, 0xb9, 0xce, 0xf5, 0x33, 0x41, 0x9f, 0x00, 0x43, 0xeb, 0xe3, + 0xee, 0xfc, 0x12, 0xed, 0x0c, 0xc6, 0x02, 0x5b, 0xee, 0xda, 0x1b, 0x1f, + 0xe9, 0x04, 0xf0, 0x0c, 0xfd, 0x0c, 0xff, 0x0c, 0x3d, 0x00, 0x0d, 0xfc, + 0x2a, 0x25, 0xdf, 0x06, 0xfb, 0x39, 0x3f, 0x09, 0x08, 0xee, 0x0f, 0x1c, + 0x0e, 0x2c, 0x1d, 0x01, 0xfd, 0x23, 0xba, 0x04, 0x63, 0xe0, 0xd8, 0x07, + 0x01, 0x04, 0x33, 0xde, 0xf4, 0xf6, 0xeb, 0xf0, 0xda, 0x09, 0x10, 0x2d, + 0x03, 0x0a, 0xaf, 0xf8, 0xff, 0xf1, 0xfe, 0xe6, 0xdf, 0xf0, 0xd4, 0xf5, + 0x1f, 0xd8, 0xe1, 0xf3, 0xe9, 0xd5, 0xca, 0x07, 0xf9, 0xdf, 0xf6, 0xc0, + 0xea, 0x07, 0xf8, 0xdf, 0xe4, 0x26, 0xfa, 0xf4, 0x25, 0x06, 0xea, 0xff, + 0x39, 0x02, 0xbe, 0x11, 0x0f, 0x1f, 0xe2, 0x11, 0xf5, 0x21, 0xfb, 0x01, + 0x3f, 0x13, 0x28, 0x16, 0x03, 0xd4, 0x11, 0x0a, 0xea, 0x05, 0x2e, 0x32, + 0xe0, 0xb2, 0x37, 0xe8, 0xb9, 0x0a, 0x11, 0xed, 0xf0, 0x10, 0x11, 0xdd, + 0xee, 0xff, 0x1c, 0xd8, 0x02, 0xf5, 0xe7, 0xf9, 0xbc, 0x22, 0x3f, 0xf3, + 0xcc, 0xfe, 0x16, 0x09, 0xe6, 0xed, 0x06, 0x04, 0x2d, 0x32, 0xf9, 0xfe, + 0x0c, 0x48, 0x20, 0xf6, 0x09, 0xee, 0x0c, 0x3e, 0x1e, 0xe4, 0xda, 0xfc, + 0x12, 0xfd, 0x08, 0x3a, 0x29, 0x11, 0xe3, 0xed, 0xe6, 0x34, 0x0b, 0xe1, + 0xfc, 0x1d, 0xe3, 0xf8, 0x21, 0xdf, 0xea, 0xd1, 0x1a, 0x1c, 0xe2, 0x1c, + 0x08, 0x11, 0xdd, 0x07, 0xf0, 0xd3, 0xdb, 0xf5, 0x10, 0xf9, 0xfc, 0xdb, + 0x06, 0x14, 0xd9, 0x02, 0x09, 0xf6, 0xfc, 0x09, 0xd0, 0xb7, 0x0b, 0xfc, + 0x11, 0xc9, 0xd9, 0x09, 0x3f, 0x17, 0x8d, 0xe1, 0x0b, 0x01, 0x00, 0x0c, + 0xd0, 0xfc, 0x21, 0xcc, 0x19, 0xcf, 0xfc, 0x2d, 0x04, 0xd0, 0xe6, 0xef, + 0x33, 0x3e, 0xe9, 0x00, 0x27, 0xd9, 0x3a, 0xed, 0xf9, 0x36, 0x15, 0xf9, + 0x31, 0x03, 0x0a, 0x0a, 0xf9, 0x0d, 0x28, 0xf7, 0xe5, 0x45, 0x24, 0xbe, + 0x0a, 0x47, 0xed, 0xe2, 0x55, 0x10, 0x12, 0xf7, 0x06, 0xf7, 0xe7, 0xf1, + 0x1b, 0xeb, 0xc0, 0x25, 0x16, 0xd4, 0xe1, 0x07, 0x0c, 0xf1, 0xef, 0xd4, + 0x08, 0x1b, 0x0f, 0xdd, 0xf9, 0xd8, 0xed, 0x19, 0x01, 0xb4, 0x0d, 0x23, + 0x11, 0xd5, 0x1f, 0x1a, 0xc6, 0xf2, 0x09, 0xf3, 0x01, 0x14, 0xf7, 0x02, + 0xf7, 0x32, 0x16, 0xf5, 0xea, 0xff, 0xff, 0x4b, 0x14, 0xde, 0xf1, 0x2e, + 0x3e, 0x0a, 0xe0, 0x00, 0xfc, 0xea, 0x40, 0x05, 0xed, 0xd9, 0x07, 0xd2, + 0xe6, 0xcb, 0x03, 0xf2, 0x08, 0x01, 0xe1, 0x34, 0xd8, 0x0b, 0xcf, 0xd2, + 0x06, 0x02, 0xcc, 0x09, 0xf8, 0xf2, 0x08, 0xe4, 0x0a, 0x01, 0xdd, 0xef, + 0x11, 0xe2, 0xe3, 0x2a, 0xe9, 0x22, 0x28, 0xf7, 0xec, 0xd0, 0xf6, 0xf7, + 0x07, 0xfa, 0xf5, 0xe7, 0x12, 0x35, 0xfa, 0xe0, 0xfd, 0x01, 0x2a, 0x0c, + 0x09, 0x1c, 0x03, 0x00, 0x1b, 0xfb, 0xf0, 0x03, 0x26, 0xfe, 0xdc, 0xef, + 0x2b, 0x26, 0x2f, 0xfa, 0xfa, 0x48, 0xf3, 0x01, 0x1f, 0x12, 0x13, 0x2f, + 0xe6, 0x13, 0x3c, 0x17, 0x0a, 0x06, 0xf2, 0x37, 0xff, 0xd8, 0x36, 0xf2, + 0xe6, 0xdf, 0xda, 0x0e, 0xe4, 0xed, 0xf4, 0x08, 0xef, 0xec, 0xf4, 0xe4, + 0x0f, 0xd0, 0xdb, 0x04, 0xd7, 0xf8, 0xfe, 0xf1, 0xf6, 0x0f, 0xdf, 0xd2, + 0xfe, 0xf3, 0xd5, 0xea, 0x07, 0xe8, 0xd1, 0x26, 0x07, 0xdb, 0xef, 0x06, + 0x26, 0x14, 0xbf, 0x11, 0x29, 0xcd, 0xdb, 0xe6, 0xe7, 0xf9, 0x01, 0x31, + 0x03, 0xc6, 0xec, 0x06, 0xf8, 0xea, 0xea, 0x1d, 0xfa, 0xd6, 0x08, 0x23, + 0x1c, 0x0a, 0xba, 0xdf, 0x09, 0xf8, 0xea, 0xf8, 0x0b, 0x19, 0xfa, 0x0c, + 0xea, 0xe9, 0x0a, 0x64, 0xfc, 0xe2, 0x2c, 0x22, 0x10, 0x10, 0xf7, 0x35, + 0x2d, 0xdd, 0x2b, 0x38, 0xf9, 0x22, 0x31, 0x20, 0x10, 0x2c, 0x1a, 0x19, + 0x0e, 0x01, 0x07, 0x16, 0xfa, 0x0c, 0x24, 0x05, 0xd3, 0x1c, 0xf7, 0xf9, + 0x0a, 0xf6, 0x24, 0xfb, 0xf0, 0x08, 0xff, 0xd6, 0xfc, 0x1a, 0xeb, 0xf0, + 0xde, 0xec, 0x00, 0x11, 0xcf, 0xea, 0xea, 0x00, 0x09, 0xd4, 0x08, 0xfb, + 0xc5, 0xe1, 0xfc, 0x16, 0xf0, 0x29, 0xf9, 0xec, 0xe9, 0xce, 0x0a, 0x1b, + 0xd8, 0xf3, 0x10, 0xdb, 0xfa, 0xe7, 0x04, 0xfc, 0xe6, 0xe3, 0xf6, 0xf0, + 0xf0, 0x02, 0xfc, 0xfc, 0x01, 0xec, 0x02, 0x01, 0xdd, 0xf3, 0x05, 0x17, + 0xe8, 0xda, 0x11, 0x04, 0x01, 0x08, 0x04, 0x04, 0xdc, 0x0f, 0x21, 0x0d, + 0xd2, 0x0d, 0xff, 0x1b, 0x45, 0xf0, 0xe9, 0xff, 0x35, 0x3c, 0xf2, 0xec, + 0x0c, 0xf6, 0xf2, 0xf6, 0xf3, 0xec, 0x09, 0x0b, 0xf9, 0x18, 0xeb, 0xf6, + 0x0b, 0x21, 0x06, 0x15, 0xe8, 0x02, 0x18, 0x04, 0xee, 0x1b, 0x1e, 0x0a, + 0xfe, 0x00, 0x14, 0x1b, 0x2a, 0xf5, 0xf8, 0xfc, 0x09, 0x12, 0x26, 0x1f, + 0x01, 0xf2, 0x12, 0xed, 0x17, 0x05, 0xfa, 0xff, 0x09, 0x00, 0xf0, 0xfa, + 0x0e, 0xf1, 0xdc, 0xf7, 0x13, 0xfc, 0xed, 0xc8, 0xf0, 0x05, 0xff, 0x05, + 0xef, 0xcf, 0xef, 0xf1, 0xff, 0x01, 0xd2, 0xfc, 0x03, 0xcc, 0xe3, 0x09, + 0xff, 0x01, 0xe8, 0xd7, 0xfc, 0x0f, 0x11, 0xe5, 0xd7, 0xf5, 0xda, 0xed, + 0xdf, 0x07, 0x05, 0xe4, 0xf5, 0x03, 0x00, 0xd6, 0x03, 0x24, 0xfe, 0xfa, + 0xf9, 0x03, 0x08, 0x07, 0x07, 0x21, 0x0d, 0x10, 0xec, 0x22, 0x19, 0xd7, + 0x17, 0x38, 0xf9, 0xf3, 0x0b, 0xe3, 0x1d, 0x08, 0x28, 0x17, 0x1c, 0xed, + 0xeb, 0x0d, 0xf2, 0xf3, 0x0f, 0x1c, 0x32, 0x20, 0x1f, 0xe5, 0xe9, 0x06, + 0x22, 0x29, 0xf7, 0x00, 0x26, 0xec, 0x03, 0x17, 0x10, 0xfb, 0x10, 0x06, + 0x2c, 0xfc, 0xfa, 0xfc, 0x1c, 0xee, 0xbf, 0x04, 0x01, 0xe1, 0x12, 0xf1, + 0xf6, 0x01, 0xed, 0xfb, 0xf2, 0xfe, 0xea, 0xf4, 0x03, 0xf0, 0xd5, 0xfc, + 0x1e, 0xee, 0x03, 0xf0, 0x04, 0xff, 0xff, 0xe9, 0xe2, 0xe1, 0x06, 0x18, + 0xd9, 0xef, 0xea, 0x00, 0xe6, 0x12, 0x07, 0x04, 0x07, 0xff, 0xe9, 0xed, + 0xf4, 0xf0, 0xf3, 0xfe, 0x18, 0xf3, 0x01, 0x05, 0xff, 0xff, 0xfc, 0xed, + 0x04, 0xf0, 0x0f, 0x03, 0xe8, 0x06, 0x1f, 0xf1, 0xf6, 0xe7, 0x0e, 0x00, + 0x01, 0x01, 0xec, 0x09, 0xfa, 0xf5, 0x29, 0x05, 0xee, 0xf6, 0x25, 0xfe, + 0xe8, 0x18, 0x17, 0x00, 0x0f, 0xe2, 0x0a, 0x13, 0x0d, 0x0a, 0xe6, 0x2b, + 0x22, 0xfd, 0xd9, 0x18, 0x23, 0xfa, 0x00, 0x01, 0x04, 0x13, 0x1f, 0x06, + 0x07, 0xfa, 0x02, 0x2e, 0xf8, 0xe8, 0x04, 0x05, 0x25, 0xf4, 0x06, 0x29, + 0x0c, 0xe5, 0xff, 0x24, 0x06, 0xe6, 0xf4, 0x08, 0xf3, 0x12, 0x14, 0xfa, + 0xed, 0x04, 0xec, 0x02, 0xe5, 0x00, 0x18, 0xf7, 0xd3, 0xc2, 0xfe, 0x08, + 0xef, 0xfe, 0xf9, 0xbf, 0xc3, 0xf7, 0x03, 0xf8, 0xdb, 0x10, 0xf6, 0xea, + 0xd7, 0xf5, 0x18, 0x05, 0xdc, 0xdd, 0x1c, 0xfe, 0x00, 0x23, 0x1f, 0xec, + 0xe7, 0x28, 0x23, 0xf3, 0xfc, 0xf5, 0x01, 0x14, 0xf0, 0xf6, 0x01, 0x00, + 0xf8, 0xfc, 0xf1, 0x03, 0xe1, 0x06, 0x14, 0x0d, 0x0d, 0xcc, 0x21, 0xe0, + 0xf1, 0x47, 0xff, 0xfd, 0xff, 0xfc, 0x1c, 0x13, 0x01, 0x13, 0xec, 0xf6, + 0x03, 0x04, 0x07, 0x04, 0x2d, 0x07, 0xde, 0x01, 0x11, 0x10, 0x05, 0xeb, + 0xed, 0xed, 0x15, 0xed, 0xd9, 0xff, 0x12, 0x06, 0xdf, 0x07, 0x10, 0xfe, + 0x0c, 0xf1, 0x21, 0x12, 0x1a, 0x19, 0xe6, 0xe9, 0x15, 0x1c, 0x07, 0xee, + 0x1e, 0x0b, 0xf1, 0x07, 0x07, 0xfd, 0x00, 0x01, 0x00, 0x01, 0x1b, 0x19, + 0xf5, 0xde, 0xf6, 0x03, 0xf8, 0xf9, 0x01, 0xdd, 0x07, 0x23, 0xf4, 0xdb, + 0xe4, 0x05, 0x00, 0xec, 0xf0, 0x04, 0xf8, 0xe7, 0x06, 0x0c, 0xf1, 0xdc, + 0xd7, 0xea, 0x16, 0xfe, 0xfb, 0x01, 0x08, 0x0e, 0x10, 0x0d, 0xde, 0x01, + 0xff, 0xf8, 0xf6, 0xf9, 0xfc, 0xfc, 0xf1, 0xec, 0x20, 0x07, 0xf5, 0xf6, + 0xf9, 0x12, 0xf8, 0xe2, 0x0b, 0x07, 0x16, 0xcd, 0xfc, 0x01, 0x09, 0xee, + 0x03, 0x05, 0xf7, 0xfc, 0xff, 0x27, 0x09, 0x06, 0x00, 0xff, 0xf0, 0x22, + 0x07, 0x0a, 0x0a, 0xfe, 0x17, 0x10, 0xf4, 0x00, 0x01, 0x26, 0x2c, 0xf1, + 0xdb, 0x1b, 0x0d, 0xed, 0x13, 0xe9, 0x02, 0x00, 0xff, 0x1b, 0x04, 0xeb, + 0xf0, 0x02, 0x09, 0x07, 0xf2, 0xf9, 0xfc, 0xed, 0x05, 0x1f, 0xff, 0xe4, + 0x2c, 0x05, 0xf9, 0xf1, 0xfe, 0x24, 0xe5, 0xe1, 0x0f, 0x00, 0xfb, 0xff, + 0xf0, 0x0f, 0xff, 0xf4, 0x01, 0xf4, 0x03, 0xf7, 0x0a, 0xeb, 0xff, 0x02, + 0xdd, 0x05, 0xed, 0x02, 0x1f, 0xee, 0xe7, 0xed, 0x20, 0xfb, 0xf0, 0x04, + 0x0c, 0xee, 0xf6, 0x07, 0x0b, 0xf5, 0xf9, 0x12, 0xfe, 0xff, 0x01, 0xec, + 0xff, 0x02, 0xf7, 0xf2, 0xdd, 0x02, 0x02, 0xf7, 0xfc, 0xf1, 0xf6, 0xfd, + 0xea, 0x0d, 0x00, 0xe5, 0xf1, 0xf7, 0xeb, 0x0d, 0x0a, 0xee, 0xf0, 0x09, + 0xfe, 0xf4, 0xfd, 0x15, 0x17, 0xfa, 0xe5, 0x06, 0xf7, 0xf2, 0x1b, 0x01, + 0x2d, 0xf7, 0xf0, 0x0f, 0xff, 0xe1, 0x01, 0x20, 0x0a, 0xf4, 0x06, 0x0f, + 0x1c, 0xee, 0x0b, 0x07, 0x12, 0x22, 0xf7, 0xff, 0x14, 0xfe, 0x22, 0x11, + 0x13, 0x16, 0x07, 0x0d, 0x02, 0xff, 0x2e, 0x00, 0x19, 0x07, 0x07, 0x19, + 0x07, 0xf5, 0x01, 0x01, 0x22, 0x02, 0xeb, 0xed, 0xea, 0x21, 0x00, 0xd9, + 0x06, 0xf0, 0x02, 0xe5, 0xd1, 0xdc, 0xde, 0xf4, 0xfb, 0x00, 0x01, 0xff, + 0xe9, 0xed, 0xf8, 0xeb, 0x03, 0x00, 0xff, 0xf0, 0xfa, 0xfc, 0xf1, 0xf6, + 0x01, 0xf4, 0xfd, 0xf9, 0xe3, 0xea, 0xf5, 0x08, 0xf7, 0xdb, 0xe8, 0x05, + 0x00, 0x05, 0xf7, 0x03, 0x10, 0xfd, 0x01, 0x1b, 0xe3, 0xed, 0x27, 0x06, + 0x03, 0xf3, 0xfd, 0x01, 0x0c, 0x1c, 0xe6, 0xfb, 0x0e, 0xfe, 0x01, 0x01, + 0x10, 0xf8, 0x02, 0x01, 0x04, 0xfa, 0x11, 0xfd, 0x00, 0x10, 0xfc, 0xff, + 0x09, 0xee, 0xf3, 0xfe, 0x02, 0x00, 0x01, 0x04, 0x0b, 0xf5, 0xfc, 0xf1, + 0x04, 0x1f, 0x07, 0xf9, 0xfc, 0xfc, 0x11, 0x02, 0xef, 0xfe, 0x15, 0xf7, + 0x15, 0xfb, 0xed, 0x18, 0x0d, 0x10, 0x01, 0x1a, 0x0b, 0xf4, 0xf9, 0x0e, + 0x1c, 0x0e, 0x17, 0x0f, 0xf0, 0x07, 0x0b, 0xff, 0x04, 0xfe, 0xe5, 0xea, + 0xed, 0xe6, 0xf2, 0xde, 0x09, 0x17, 0xeb, 0xe8, 0xed, 0xf4, 0xe1, 0xef, + 0xf8, 0x0f, 0xf5, 0xe7, 0x04, 0xe9, 0xe6, 0xe0, 0x07, 0x1f, 0x16, 0xfb, + 0xf0, 0xf3, 0xfa, 0x00, 0x05, 0x25, 0x01, 0x00, 0xf4, 0xfd, 0x02, 0x1f, + 0x03, 0xeb, 0x09, 0x04, 0x01, 0x04, 0xfe, 0xf4, 0xf6, 0xf3, 0xfe, 0x01, + 0x00, 0x23, 0xf9, 0x00, 0xf8, 0xf6, 0x12, 0xf8, 0xea, 0xf4, 0x0f, 0x0d, + 0xf8, 0xe6, 0xf5, 0x03, 0x05, 0x04, 0x07, 0x04, 0x0b, 0x07, 0xff, 0xf8, + 0x00, 0x05, 0x01, 0xf0, 0xf3, 0x02, 0x10, 0x0a, 0xf5, 0xee, 0xf3, 0x0c, + 0xfd, 0xf4, 0x07, 0x04, 0x0b, 0x19, 0xee, 0x02, 0x17, 0xf7, 0x09, 0x0a, + 0x2b, 0x25, 0xf6, 0xf8, 0xf9, 0x06, 0x04, 0x01, 0xff, 0xf8, 0x06, 0x0b, + 0xd7, 0xfb, 0x02, 0xf4, 0xe4, 0x16, 0x2b, 0xdc, 0xe7, 0x0b, 0x01, 0xff, + 0xfc, 0xf1, 0x1b, 0x16, 0xf6, 0xfc, 0x06, 0x0f, 0x06, 0xeb, 0xf7, 0x0f, + 0xfd, 0xfc, 0x01, 0x26, 0x18, 0xf5, 0x02, 0x01, 0x08, 0xeb, 0xf3, 0x03, + 0xf8, 0xf9, 0xdb, 0xda, 0x0e, 0x0b, 0xea, 0xf7, 0x02, 0xf8, 0xfc, 0xde, + 0xe4, 0xf6, 0xf3, 0x03, 0xff, 0x00, 0x01, 0xfb, 0xf1, 0xfe, 0x09, 0x12, + 0x0f, 0xfd, 0x00, 0x00, 0x00, 0x12, 0xf5, 0x01, 0x21, 0x14, 0xf7, 0xfd, + 0x00, 0x07, 0xff, 0xf5, 0xfa, 0xfd, 0x0f, 0x1b, 0xfa, 0xee, 0xf1, 0xea, + 0xfa, 0x02, 0xf9, 0xf7, 0xec, 0x04, 0xfd, 0xf6, 0xfe, 0x00, 0x07, 0xec, + 0xee, 0xf1, 0x03, 0x16, 0xf4, 0xe1, 0x0e, 0x11, 0xfd, 0x00, 0x00, 0x00, + 0x07, 0x06, 0x13, 0x00, 0xfc, 0x00, 0x00, 0xeb, 0x08, 0x18, 0x0d, 0xf9, + 0x08, 0x06, 0xff, 0xf1, 0xfb, 0xfd, 0x00, 0x1c, 0xfe, 0x00, 0x07, 0x0d, + 0x09, 0xdf, 0xf8, 0x0e, 0x06, 0xf7, 0xed, 0x0b, 0x1a, 0x02, 0x13, 0x07, + 0xfe, 0x00, 0x00, 0xfd, 0xfd, 0x00, 0x00, 0x11, 0x0e, 0xfd, 0xeb, 0xf2, + 0xfc, 0x01, 0x07, 0xff, 0x03, 0xf8, 0xf4, 0x0a, 0x12, 0x1d, 0xfa, 0xdf, + 0xeb, 0x05, 0x03, 0x00, 0x00, 0xef, 0xea, 0x05, 0xfd, 0x04, 0x06, 0xf1, + 0x02, 0xf6, 0x02, 0xf6, 0xf5, 0xeb, 0xf0, 0x04, 0xf3, 0xff, 0x0a, 0xf1, + 0x02, 0x00, 0x00, 0x03, 0x0f, 0xfd, 0x00, 0x00, 0x03, 0x00, 0x0d, 0x0d, + 0xfd, 0xea, 0xf0, 0xf3, 0xff, 0x00, 0x00, 0xf6, 0x02, 0x00, 0x0a, 0xfe, + 0xf6, 0x02, 0x0c, 0xfe, 0x03, 0xf9, 0x01, 0x03, 0xfc, 0x00, 0x0c, 0x08, + 0x02, 0x09, 0x0a, 0xfe, 0xf6, 0xfe, 0x00, 0x0a, 0x05, 0xff, 0x00, 0x00, + 0x00, 0xf1, 0xdf, 0x03, 0x07, 0x05, 0x03, 0xfc, 0xfb, 0x01, 0x03, 0x00, + 0x00, 0x06, 0x03, 0x00, 0x00, 0x0f, 0x04, 0xff, 0x06, 0xff, 0xfd, 0xf5, + 0x11, 0x04, 0xf9, 0x07, 0xff, 0x00, 0xfd, 0xec, 0x10, 0x0a, 0xef, 0xf2, + 0xec, 0xdb, 0xf7, 0xff, 0x00, 0x06, 0x03, 0x05, 0x03, 0xf9, 0xf6, 0x0b, + 0x0d, 0xfd, 0x00, 0x0b, 0x1d, 0x0c, 0x03, 0xf4, 0xff, 0x06, 0x07, 0xff, + 0x00, 0x14, 0x10, 0x05, 0x07, 0x12, 0x0d, 0xf4, 0xf9, 0xff, 0xf8, 0x01, + 0x00, 0x06, 0xf6, 0xf4, 0x00, 0x09, 0xf8, 0x03, 0x00, 0xf0, 0x00, 0xec, + 0xf1, 0x03, 0x08, 0xf6, 0xf4, 0xf7, 0x02, 0x05, 0xfd, 0x00, 0xf3, 0xf3, + 0xf8, 0xff, 0xee, 0xf3, 0xfb, 0x06, 0x04, 0x04, 0xfa, 0x01, 0x00, 0xfe, + 0xfe, 0x00, 0xee, 0xf9, 0x04, 0x00, 0xfb, 0xfa, 0x01, 0x12, 0x04, 0xff, + 0xfb, 0xf2, 0x03, 0x0c, 0xfe, 0xf9, 0xee, 0xff, 0x03, 0x00, 0x05, 0xfd, + 0x03, 0x09, 0x14, 0x08, 0xf9, 0x01, 0x0a, 0xfe, 0x05, 0x02, 0x00, 0xfb, + 0x01, 0xfb, 0x12, 0x0c, 0xfd, 0x00, 0x05, 0xff, 0xfb, 0x01, 0x0a, 0x06, + 0xfc, 0xfc, 0x01, 0xfb, 0xfc, 0x10, 0x0d, 0xfd, 0xf4, 0xfd, 0x01, 0xf6, + 0xfa, 0xff, 0x05, 0xff, 0xfe, 0x05, 0xff, 0xee, 0xfc, 0x01, 0x05, 0xff, + 0xfe, 0x00, 0x02, 0xfd, 0xfc, 0x06, 0x0c, 0x06, 0x01, 0xf2, 0xf5, 0x02, + 0x07, 0x0c, 0xfe, 0xfb, 0x0e, 0x06, 0xff, 0xfa, 0x01, 0x02, 0xf2, 0xf7, + 0xf5, 0xf4, 0xfa, 0x01, 0xfe, 0xf8, 0xf9, 0xff, 0x05, 0xf9, 0x0a, 0x0a, + 0xf9, 0xf0, 0x01, 0xfc, 0xf6, 0xfd, 0x04, 0x03, 0x02, 0x03, 0x02, 0x00, + 0x03, 0x02, 0x00, 0xfa, 0xf5, 0xf8, 0x0c, 0x0d, 0xfd, 0xfa, 0xf8, 0x02, + 0x03, 0x0e, 0x06, 0xff, 0x00, 0x00, 0xf3, 0x00, 0x06, 0x03, 0xfc, 0xfb, + 0x05, 0x00, 0xfa, 0xfa, 0xff, 0x08, 0xff, 0x02, 0xfd, 0xfd, 0x08, 0x01, + 0xfa, 0x05, 0x06, 0xf9, 0xfd, 0x07, 0xfd, 0xf7, 0xfe, 0xfe, 0x06, 0x03, + 0xf9, 0xfd, 0x00, 0x02, 0x02, 0x00, 0x02, 0x09, 0x01, 0x05, 0xff, 0x03, + 0x03, 0x08, 0x0d, 0x02, 0xfe, 0x00, 0x01, 0x07, 0x06, 0xf7, 0x01, 0x0b, + 0xfe, 0x01, 0x07, 0x00, 0xff, 0xf8, 0xf9, 0xfe, 0xfc, 0xf6, 0xfd, 0x08, + 0x04, 0xff, 0xfb, 0xfd, 0xfc, 0x01, 0x03, 0xfb, 0xfa, 0x01, 0x00, 0x00, + 0xfd, 0xfc, 0xfd, 0xf8, 0xfe, 0x00, 0xff, 0xf8, 0xf9, 0x01, 0xfd, 0xfb, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x1f, 0x23, 0xd4, 0xaf, 0xdd, 0x2e, 0x53, + 0x16, 0xd0, 0xd6, 0x30, 0xe5, 0xb1, 0xa0, 0xd4, 0x07, 0xc9, 0xf0, 0xb8, + 0xa4, 0xda, 0x0c, 0xcf, 0xbc, 0x9b, 0x99, 0xee, 0xc0, 0xb5, 0xd2, 0x0c, + 0xc7, 0xf7, 0xd6, 0xee, 0xcd, 0x25, 0x33, 0xda, 0xe7, 0xf5, 0x4a, 0x19, + 0xcf, 0x18, 0x25, 0x28, 0x4b, 0xff, 0x16, 0x37, 0xfb, 0xd2, 0x14, 0x4b, + 0x4a, 0x16, 0x5e, 0x7a, 0x7d, 0x39, 0x37, 0x1b, 0x51, 0x2a, 0x14, 0x53, + 0x3d, 0x18, 0x4b, 0x5c, 0x5e, 0x56, 0x4b, 0x37, 0x40, 0x4f, 0x48, 0x37, + 0x3d, 0x37, 0x37, 0x39, 0x28, 0x16, 0x28, 0x23, 0x07, 0x10, 0xf9, 0x18, + 0xf7, 0x28, 0x0b, 0xea, 0xe7, 0x07, 0xe3, 0xd6, 0xc5, 0xc2, 0xd4, 0xc2, + 0xc9, 0xe1, 0xf5, 0xd0, 0xd8, 0xc7, 0xb8, 0xbc, 0xd2, 0xc5, 0xc5, 0xad, + 0xcd, 0xba, 0xc5, 0xbc, 0xcb, 0xda, 0xd2, 0xcf, 0xd0, 0xd2, 0xd2, 0xd8, + 0xee, 0xec, 0xdf, 0xe5, 0xf0, 0xf9, 0xf5, 0xfb, 0x03, 0x0c, 0xfb, 0x1b, + 0x16, 0x05, 0x37, 0x2e, 0x19, 0x14, 0x26, 0x2a, 0x4f, 0x67, 0x16, 0x28, + 0x58, 0x6d, 0x4d, 0x31, 0xf2, 0x3b, 0x40, 0x07, 0x4d, 0x2a, 0x1d, 0x18, + 0x2c, 0x55, 0x58, 0x39, 0x30, 0x31, 0x46, 0x3d, 0x31, 0x30, 0x2c, 0x2a, + 0x2e, 0x19, 0x10, 0x2e, 0x25, 0x1d, 0x12, 0x07, 0x07, 0x1f, 0x19, 0x0e, + 0xff, 0xdf, 0xe8, 0x14, 0xff, 0xe7, 0xd0, 0xf2, 0xdd, 0xd2, 0xe8, 0xf5, + 0xee, 0xc0, 0xe1, 0xc7, 0xb8, 0xf9, 0xbe, 0xa4, 0xd2, 0xc9, 0xc2, 0xbc, + 0xc5, 0xcd, 0xd0, 0xb8, 0xc5, 0xcd, 0xd6, 0xcf, 0xc9, 0xd4, 0xe3, 0xd4, + 0xe7, 0xea, 0xe1, 0xea, 0xe8, 0xe1, 0xf2, 0x01, 0xf4, 0xf5, 0xea, 0x03, + 0x00, 0x03, 0x07, 0x10, 0xff, 0x10, 0x07, 0x0e, 0x10, 0x25, 0x33, 0x23, + 0x23, 0x01, 0x23, 0x2c, 0x2a, 0x23, 0x3b, 0x37, 0x1f, 0x3d, 0x3b, 0x1d, + 0x21, 0x3d, 0x28, 0x23, 0x30, 0x23, 0x28, 0x23, 0x19, 0x1d, 0x1d, 0x19, + 0x1d, 0x1b, 0x14, 0x0e, 0x0b, 0x0c, 0x10, 0x0e, 0x01, 0xf2, 0x0b, 0x05, + 0x12, 0x03, 0xfd, 0xdf, 0xf2, 0xf0, 0xbc, 0xe1, 0xff, 0xf9, 0xc0, 0xc3, + 0xd2, 0xf9, 0xe5, 0xd4, 0xbc, 0xcf, 0xd0, 0xcf, 0xcb, 0xdb, 0xc5, 0xc2, + 0xc9, 0xf2, 0xe8, 0xba, 0xc9, 0xd2, 0xd0, 0xcf, 0xd8, 0xdd, 0xdb, 0xdd, + 0xd4, 0xe8, 0xe1, 0xe3, 0xee, 0xee, 0xf4, 0xe1, 0xe7, 0xec, 0x00, 0xf9, + 0xea, 0xf9, 0x0e, 0xfd, 0x01, 0x10, 0xf2, 0xf9, 0x10, 0x01, 0x09, 0x18, + 0x19, 0x05, 0x2c, 0x23, 0x1b, 0x16, 0x0c, 0x25, 0x28, 0x1d, 0x31, 0x33, + 0x42, 0x21, 0x31, 0x39, 0x33, 0x30, 0x1d, 0x2c, 0x1b, 0x1d, 0x23, 0x2a, + 0x25, 0x1d, 0x1d, 0x18, 0x18, 0x18, 0x18, 0x10, 0x0e, 0x0b, 0x07, 0x09, + 0x05, 0x0b, 0x10, 0x07, 0xfd, 0xff, 0xf5, 0xf7, 0xf0, 0xf5, 0x07, 0x00, + 0xf5, 0xf5, 0xee, 0xda, 0xc9, 0xea, 0xdd, 0x07, 0xda, 0xba, 0xbc, 0xdb, + 0xcf, 0xd0, 0xd8, 0xc9, 0xc7, 0xd4, 0xcf, 0xd4, 0xc7, 0xc5, 0xd0, 0xd2, + 0xd6, 0xd4, 0xd2, 0xe5, 0xe1, 0xdb, 0xe5, 0xe7, 0xe1, 0xe7, 0xea, 0xee, + 0xee, 0xec, 0xf5, 0x00, 0xee, 0xf2, 0x05, 0xf5, 0xf4, 0x09, 0x19, 0x03, + 0x0e, 0x03, 0x16, 0x12, 0x0c, 0x0c, 0x19, 0x30, 0x1f, 0x16, 0x30, 0x23, + 0x21, 0x16, 0x10, 0x35, 0x2c, 0x1b, 0x19, 0x1d, 0x1f, 0x2c, 0x1d, 0x1d, + 0x0b, 0x23, 0x2c, 0x19, 0x1b, 0x18, 0x10, 0x1b, 0x0e, 0x0c, 0x10, 0x0c, + 0x10, 0x0e, 0x0e, 0x14, 0x12, 0x01, 0x00, 0x05, 0xfd, 0xf9, 0xff, 0xfb, + 0x00, 0xf5, 0xe7, 0xea, 0xf0, 0xf7, 0xe8, 0xe3, 0xda, 0xf0, 0xdb, 0xe1, + 0xdb, 0xc2, 0xcf, 0xdb, 0xe1, 0xd8, 0xd0, 0xd8, 0xdb, 0xcf, 0xd8, 0xe5, + 0xcd, 0xd8, 0xd6, 0xd8, 0xe3, 0xdd, 0xda, 0xdb, 0xe7, 0xd8, 0xdd, 0xe3, + 0xec, 0xf4, 0xf0, 0xf0, 0xf2, 0xec, 0xf0, 0xfb, 0xfd, 0xff, 0xf5, 0xfd, + 0x18, 0x09, 0xf4, 0x05, 0x10, 0x0b, 0x12, 0x10, 0x1f, 0x0e, 0x16, 0x19, + 0x0e, 0x14, 0x09, 0x14, 0x10, 0x0b, 0x2e, 0x1d, 0x1d, 0x28, 0x21, 0x26, + 0x28, 0x1f, 0x2c, 0x2c, 0x19, 0x16, 0x19, 0x1f, 0x26, 0x1b, 0x0c, 0x1d, + 0x21, 0x21, 0x1b, 0x12, 0x14, 0x10, 0x0c, 0x09, 0x09, 0x07, 0x03, 0x0b, + 0x09, 0x03, 0x03, 0xf9, 0xf2, 0xfb, 0x03, 0xf4, 0xec, 0xff, 0xff, 0xf2, + 0xec, 0xf0, 0xf2, 0xf5, 0xf7, 0xe5, 0xea, 0xe3, 0xe3, 0xe5, 0xe3, 0xd6, + 0xe3, 0xe8, 0xdd, 0xe3, 0xe5, 0xdf, 0xda, 0xd8, 0xe5, 0xea, 0xdf, 0xdd, + 0xdf, 0xe1, 0xe8, 0xe7, 0xe7, 0xee, 0xf0, 0xe3, 0xec, 0xf5, 0xf5, 0xee, + 0xea, 0xf5, 0xf9, 0xff, 0x09, 0xee, 0xe8, 0xf5, 0xfd, 0xec, 0x07, 0xff, + 0x00, 0xf5, 0x03, 0x05, 0xf9, 0x00, 0x23, 0x2e, 0x1b, 0x0e, 0xf0, 0x19, + 0x1b, 0x30, 0xfb, 0x0c, 0x35, 0x18, 0x0c, 0x26, 0x01, 0x18, 0x25, 0x12, + 0x1b, 0x25, 0x25, 0x12, 0x12, 0x25, 0x26, 0x0e, 0x12, 0x1f, 0x18, 0x16, + 0x1d, 0x1d, 0x14, 0x12, 0x10, 0x12, 0x0c, 0xff, 0x03, 0x10, 0x0c, 0xff, + 0xf7, 0xff, 0x00, 0x10, 0xfd, 0x09, 0xfd, 0x00, 0x03, 0xff, 0xdf, 0xec, + 0xf7, 0xff, 0xe1, 0xdd, 0xf2, 0xe8, 0xdd, 0xda, 0xe3, 0xdd, 0xe5, 0xda, + 0xdd, 0xdf, 0xd8, 0xd6, 0xd4, 0xdf, 0xe3, 0xd8, 0xd6, 0xe5, 0xe5, 0xea, + 0xe3, 0xe7, 0xee, 0xe7, 0xea, 0xee, 0xf0, 0xe7, 0xea, 0xf4, 0xf5, 0xf2, + 0xf7, 0xf2, 0x03, 0x01, 0xf5, 0xf7, 0xfd, 0xfd, 0x07, 0xfb, 0x0b, 0x01, + 0xf9, 0x03, 0x0e, 0x00, 0x03, 0x09, 0x05, 0x07, 0x05, 0x26, 0x19, 0x0b, + 0x2e, 0x1b, 0xfd, 0x0c, 0x30, 0x21, 0x03, 0x0e, 0x2a, 0x30, 0x28, 0x1b, + 0x1f, 0x18, 0x1d, 0x2a, 0x33, 0x19, 0x14, 0x1d, 0x16, 0x19, 0x19, 0x14, + 0x16, 0x16, 0x19, 0x14, 0x14, 0x12, 0x0e, 0x0b, 0x00, 0x10, 0x16, 0x0c, + 0x07, 0x05, 0x09, 0x01, 0xfb, 0xfb, 0x05, 0xf5, 0xf4, 0xf7, 0xe8, 0xff, + 0xee, 0xf0, 0xf2, 0xea, 0xdf, 0xdf, 0xe8, 0xe8, 0xdf, 0xd6, 0xdd, 0xe1, + 0xe8, 0xe1, 0xd6, 0xd2, 0xd6, 0xdf, 0xdd, 0xea, 0xe8, 0xdb, 0xdb, 0xd6, + 0xda, 0xe7, 0xe1, 0xe7, 0xe1, 0xe3, 0xe7, 0xec, 0xe8, 0xf2, 0xf0, 0xf7, + 0xf2, 0xf5, 0xf4, 0xee, 0xf0, 0xf7, 0xfd, 0xfb, 0xf7, 0x05, 0x0b, 0xff, + 0xff, 0x09, 0x1f, 0x0c, 0x12, 0x18, 0x14, 0x07, 0x16, 0x2a, 0x23, 0x1f, + 0x1d, 0x0c, 0x19, 0x25, 0x2a, 0x19, 0x16, 0x2a, 0x37, 0x1f, 0x28, 0x30, + 0x28, 0x1f, 0x25, 0x25, 0x16, 0x23, 0x21, 0x1d, 0x1b, 0x19, 0x21, 0x1b, + 0x12, 0x18, 0x16, 0x07, 0x12, 0x14, 0x0c, 0xff, 0xfd, 0x0b, 0x0c, 0x0c, + 0x07, 0x00, 0x03, 0xf5, 0xf2, 0xf0, 0xf2, 0xf0, 0xdf, 0xff, 0xec, 0xf2, + 0xe7, 0xdb, 0xe3, 0xe5, 0xd2, 0xdb, 0xe1, 0xdf, 0xdd, 0xd6, 0xd2, 0xd4, + 0xd0, 0xcf, 0xd8, 0xda, 0xe1, 0xdb, 0xd6, 0xd0, 0xd6, 0xda, 0xe1, 0xda, + 0xdb, 0xe3, 0xf0, 0xe8, 0xdf, 0xe1, 0xea, 0xee, 0xf0, 0xf4, 0xee, 0xf5, + 0xfb, 0xf4, 0xf4, 0xf4, 0xfb, 0xf9, 0x00, 0x01, 0x00, 0x03, 0x03, 0x12, + 0x18, 0x0b, 0x0e, 0x14, 0x12, 0x18, 0x21, 0x1f, 0x12, 0x21, 0x26, 0x21, + 0x1f, 0x26, 0x2a, 0x2c, 0x28, 0x1d, 0x1f, 0x25, 0x37, 0x2c, 0x21, 0x23, + 0x2e, 0x2a, 0x25, 0x1d, 0x16, 0x1f, 0x23, 0x23, 0x16, 0x14, 0x16, 0x1d, + 0x23, 0x12, 0x09, 0x12, 0x1d, 0x16, 0x0c, 0x07, 0x0e, 0x03, 0x03, 0x01, + 0x01, 0xfd, 0xf4, 0xf7, 0x01, 0xfd, 0xf7, 0xea, 0xe3, 0xea, 0xe8, 0xdd, + 0xe1, 0xe1, 0xdf, 0xe5, 0xdd, 0xda, 0xd2, 0xd4, 0xcd, 0xd6, 0xd4, 0xd0, + 0xda, 0xd6, 0xd8, 0xdd, 0xd8, 0xd4, 0xd8, 0xdb, 0xdd, 0xd8, 0xdf, 0xdf, + 0xe1, 0xdd, 0xe5, 0xea, 0xea, 0xea, 0xea, 0xea, 0xf0, 0xf0, 0xf2, 0xf9, + 0xff, 0xfd, 0xff, 0x00, 0x09, 0x05, 0x00, 0x07, 0x03, 0x01, 0x07, 0x10, + 0x18, 0x18, 0x12, 0x18, 0x1f, 0x14, 0x19, 0x21, 0x23, 0x23, 0x2c, 0x23, + 0x21, 0x23, 0x2a, 0x2a, 0x23, 0x21, 0x23, 0x21, 0x25, 0x1d, 0x21, 0x1f, + 0x18, 0x19, 0x1b, 0x1d, 0x23, 0x1b, 0x0c, 0x19, 0x1b, 0x19, 0x1b, 0x14, + 0x0e, 0x0e, 0x0c, 0x0b, 0x0b, 0x07, 0x05, 0x01, 0x01, 0x01, 0xff, 0xf7, + 0xf5, 0xf2, 0xf0, 0xf2, 0xee, 0xec, 0xea, 0xf0, 0xe5, 0xea, 0xee, 0xe7, + 0xdd, 0xe1, 0xe5, 0xe3, 0xe1, 0xe3, 0xd6, 0xd0, 0xdb, 0xe5, 0xe5, 0xd4, + 0xd8, 0xdf, 0xdb, 0xe5, 0xe5, 0xdf, 0xdd, 0xe7, 0xe5, 0xe7, 0xe8, 0xe7, + 0xee, 0xee, 0xea, 0xea, 0xea, 0xf5, 0xf5, 0xf4, 0xf4, 0xf5, 0xfb, 0xff, + 0x00, 0x01, 0x01, 0xff, 0x05, 0x09, 0x09, 0x07, 0x09, 0x10, 0x0c, 0x12, + 0x14, 0x12, 0x0c, 0x12, 0x14, 0x16, 0x18, 0x16, 0x10, 0x14, 0x12, 0x10, + 0x1b, 0x1f, 0x25, 0x16, 0x12, 0x12, 0x18, 0x18, 0x16, 0x12, 0x18, 0x19, + 0x1b, 0x19, 0x10, 0x0e, 0x14, 0x10, 0x14, 0x18, 0x12, 0x10, 0x18, 0x10, + 0x0b, 0x09, 0x10, 0x0e, 0x03, 0xfd, 0x07, 0x07, 0x0c, 0x05, 0xf9, 0xf9, + 0x05, 0xff, 0xf5, 0xfd, 0xf5, 0xf9, 0xf5, 0xee, 0xf5, 0xf4, 0xf4, 0xf0, + 0xf5, 0xf9, 0xf2, 0xec, 0xea, 0xe1, 0xe5, 0xee, 0xec, 0xec, 0xe7, 0xf0, + 0xec, 0xee, 0xf0, 0xee, 0xe8, 0xe7, 0xec, 0xf0, 0xf0, 0xf0, 0xf4, 0xf2, + 0xee, 0xe8, 0xf4, 0xf7, 0xf7, 0xf5, 0xf2, 0xf7, 0xf9, 0xf5, 0xf4, 0xf9, + 0xff, 0xf9, 0xf4, 0xfb, 0xf7, 0xf4, 0xf7, 0xfd, 0xff, 0x03, 0x01, 0x00, + 0x01, 0x05, 0x00, 0x07, 0x03, 0x01, 0x07, 0x07, 0x0b, 0x09, 0x0c, 0x10, + 0x0e, 0x0b, 0x10, 0x0e, 0x0b, 0x09, 0x03, 0x03, 0x0b, 0x0c, 0x0b, 0x12, + 0x0e, 0x12, 0x14, 0x12, 0x10, 0x0e, 0x16, 0x14, 0x12, 0x0e, 0x12, 0x16, + 0x16, 0x12, 0x18, 0x14, 0x12, 0x14, 0x18, 0x0e, 0x0e, 0x16, 0x12, 0x01, + 0x09, 0x12, 0x10, 0x09, 0x07, 0x09, 0x10, 0x07, 0xfd, 0xfd, 0x09, 0x05, + 0xf9, 0xf5, 0x03, 0x03, 0xfb, 0xf2, 0xf9, 0xf2, 0xfb, 0xff, 0xf0, 0xec, + 0xf0, 0xee, 0xf0, 0xec, 0xea, 0xfb, 0xf2, 0xe3, 0xe7, 0xe8, 0xe7, 0xe5, + 0xea, 0xea, 0xe7, 0xec, 0xe8, 0xe8, 0xe8, 0xf0, 0xec, 0xe7, 0xea, 0xec, + 0xec, 0xe5, 0xea, 0xec, 0xf4, 0xf4, 0xf2, 0xf2, 0xf2, 0xf5, 0xf5, 0xf0, + 0xf2, 0xf2, 0xf4, 0xfb, 0xfd, 0xfb, 0xf5, 0xf4, 0xf9, 0xf7, 0xfb, 0xf7, + 0xf5, 0x00, 0x05, 0x07, 0x07, 0x07, 0x0c, 0x09, 0x0b, 0x0c, 0x10, 0x10, + 0x14, 0x16, 0x14, 0x12, 0x14, 0x1b, 0x1f, 0x21, 0x23, 0x23, 0x21, 0x1d, + 0x1b, 0x1b, 0x21, 0x1d, 0x1d, 0x21, 0x1b, 0x1d, 0x16, 0x1d, 0x1b, 0x19, + 0x1b, 0x18, 0x12, 0x12, 0x16, 0x0e, 0x0e, 0x0b, 0x05, 0x0e, 0x10, 0x07, + 0x05, 0x03, 0x05, 0x00, 0xf7, 0xff, 0x00, 0xfb, 0xf9, 0xf9, 0xfb, 0xf9, + 0xf4, 0xf4, 0xf2, 0xe8, 0xf0, 0xea, 0xec, 0xea, 0xe8, 0xe7, 0xe3, 0xdd, + 0xdb, 0xdf, 0xe7, 0xdf, 0xda, 0xe3, 0xdd, 0xe5, 0xe1, 0xdd, 0xdf, 0xe3, + 0xe1, 0xe5, 0xe7, 0xe5, 0xe5, 0xdd, 0xe7, 0xee, 0xe7, 0xe8, 0xea, 0xf2, + 0xf4, 0xee, 0xf0, 0xf5, 0xf7, 0xf5, 0xf7, 0xf7, 0xff, 0x00, 0x01, 0x03, + 0xfd, 0x00, 0x0b, 0x10, 0x0e, 0x05, 0x12, 0x14, 0x12, 0x18, 0x16, 0x16, + 0x18, 0x16, 0x19, 0x1f, 0x21, 0x1d, 0x1f, 0x1d, 0x23, 0x1f, 0x21, 0x23, + 0x23, 0x21, 0x1f, 0x21, 0x23, 0x1f, 0x21, 0x1b, 0x1b, 0x19, 0x23, 0x23, + 0x1d, 0x14, 0x16, 0x1d, 0x18, 0x18, 0x12, 0x10, 0x0e, 0x16, 0x10, 0x0e, + 0x07, 0x05, 0x07, 0x05, 0x05, 0xff, 0xfd, 0x01, 0xfd, 0xfb, 0xf7, 0xf4, + 0xf2, 0xee, 0xee, 0xf7, 0xea, 0xe3, 0xe7, 0xee, 0xea, 0xe5, 0xe3, 0xea, + 0xe8, 0xe3, 0xe3, 0xe7, 0xdd, 0xe3, 0xe5, 0xe5, 0xdf, 0xdd, 0xdd, 0xdb, + 0xe1, 0xdf, 0xdb, 0xe3, 0xe5, 0xe3, 0xe7, 0xe3, 0xdf, 0xe3, 0xe5, 0xea, + 0xea, 0xe7, 0xec, 0xf0, 0xee, 0xf0, 0xf4, 0xf4, 0xf2, 0xf0, 0x00, 0x01, + 0xf9, 0xf9, 0x00, 0x09, 0x09, 0x05, 0x03, 0x09, 0x0c, 0x12, 0x14, 0x14, + 0x12, 0x12, 0x16, 0x19, 0x10, 0x12, 0x12, 0x14, 0x18, 0x1b, 0x1b, 0x19, + 0x1b, 0x1d, 0x21, 0x1f, 0x1b, 0x19, 0x1f, 0x23, 0x1b, 0x19, 0x1b, 0x16, + 0x1d, 0x18, 0x14, 0x18, 0x16, 0x14, 0x14, 0x16, 0x10, 0x0e, 0x0e, 0x14, + 0x12, 0x0c, 0x0b, 0x03, 0x0b, 0x07, 0x01, 0x01, 0x03, 0x01, 0x03, 0xfb, + 0xfd, 0xf9, 0xf9, 0xf5, 0xf2, 0xf2, 0xf5, 0xf7, 0xf0, 0xea, 0xf0, 0xf9, + 0xf2, 0xea, 0xf0, 0xf7, 0xf2, 0xe7, 0xe8, 0xf0, 0xf0, 0xee, 0xea, 0xea, + 0xf4, 0xf4, 0xe8, 0xec, 0xee, 0xe8, 0xe7, 0xea, 0xea, 0xee, 0xe5, 0xec, + 0xf2, 0xf2, 0xf0, 0xf0, 0xf2, 0xf9, 0xf2, 0xf4, 0xfb, 0xf5, 0xee, 0xf0, + 0xfd, 0xff, 0xfd, 0xf7, 0xfb, 0xff, 0x00, 0x01, 0x03, 0x03, 0x01, 0x01, + 0x01, 0x05, 0x09, 0x0e, 0x0c, 0x03, 0x07, 0x09, 0x0e, 0x0e, 0x0e, 0x07, + 0x07, 0x0c, 0x0b, 0x0c, 0x14, 0x10, 0x0c, 0x0c, 0x09, 0x12, 0x0c, 0x09, + 0x09, 0x0e, 0x12, 0x0c, 0x0c, 0x0e, 0x0c, 0x0e, 0x0e, 0x0b, 0x0c, 0x0b, + 0x0b, 0x09, 0x0b, 0x0b, 0x0b, 0x07, 0x05, 0x05, 0x0c, 0x05, 0x07, 0x05, + 0x09, 0x09, 0x09, 0x07, 0x05, 0x07, 0x03, 0x03, 0x09, 0x09, 0x05, 0x00, + 0x00, 0xff, 0xff, 0x03, 0x01, 0xff, 0x00, 0x01, 0xfd, 0xf5, 0xf9, 0x00, + 0xfb, 0xf5, 0xf4, 0xf7, 0xfb, 0xf7, 0xfb, 0xfb, 0xfb, 0xf0, 0xf4, 0xf5, + 0xf7, 0xf4, 0xec, 0xf2, 0xf2, 0xf5, 0xf5, 0xf2, 0xee, 0xec, 0xf0, 0xee, + 0xf2, 0xf5, 0xf2, 0xec, 0xf4, 0xf7, 0xf0, 0xf4, 0xf9, 0xf7, 0xf2, 0xf4, + 0xf5, 0xf5, 0xf7, 0xf5, 0xf9, 0xf4, 0xf5, 0xfd, 0x00, 0xf9, 0xf9, 0xf9, + 0xf9, 0xff, 0x01, 0xfd, 0x00, 0xfd, 0x03, 0x05, 0xfd, 0x01, 0x03, 0x03, + 0x01, 0x03, 0x01, 0x05, 0x0c, 0x0b, 0x09, 0x05, 0x09, 0x0b, 0x09, 0x0c, + 0x10, 0x0c, 0x09, 0x0c, 0x0b, 0x12, 0x0b, 0x09, 0x0c, 0x0c, 0x0e, 0x12, + 0x0e, 0x0e, 0x0c, 0x0b, 0x0e, 0x14, 0x0c, 0x10, 0x12, 0x18, 0x16, 0x0b, + 0x03, 0x07, 0x0b, 0x0c, 0x0b, 0x0c, 0x0e, 0x09, 0x09, 0x01, 0x05, 0x0c, + 0x05, 0x05, 0x0b, 0x03, 0xfd, 0xfd, 0x00, 0xfb, 0xff, 0xfd, 0xfd, 0xff, + 0xfd, 0xff, 0xf9, 0xf5, 0xf4, 0xf5, 0xf5, 0xf5, 0xf9, 0xf7, 0xf2, 0xf2, + 0xea, 0xf0, 0xf4, 0xf2, 0xee, 0xec, 0xf0, 0xf2, 0xe8, 0xe8, 0xee, 0xea, + 0xe5, 0xe8, 0xe8, 0xee, 0xe8, 0xec, 0xe7, 0xe8, 0xe8, 0xee, 0xf0, 0xf4, + 0xf2, 0xf4, 0xf4, 0xf4, 0xf2, 0xf2, 0xf5, 0xf7, 0xf9, 0xf9, 0xff, 0x00, + 0xfb, 0xfd, 0x01, 0x03, 0x03, 0x09, 0x01, 0x01, 0x05, 0x09, 0x09, 0x07, + 0x03, 0x07, 0x0c, 0x0e, 0x0b, 0x10, 0x0e, 0x09, 0x0c, 0x0c, 0x0e, 0x0e, + 0x0e, 0x0c, 0x10, 0x12, 0x14, 0x16, 0x10, 0x0e, 0x0e, 0x0e, 0x0c, 0x0e, + 0x12, 0x10, 0x0b, 0x12, 0x10, 0x0e, 0x0c, 0x0e, 0x0e, 0x10, 0x0b, 0x0e, + 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x03, 0x0b, 0x09, 0x01, 0x01, 0x01, + 0x01, 0x05, 0x05, 0x00, 0x01, 0x00, 0x05, 0xff, 0xfd, 0xfb, 0xf9, 0xfd, + 0xfb, 0xf0, 0xf9, 0xf5, 0xfb, 0xf5, 0xf2, 0xf0, 0xfb, 0xf7, 0xf4, 0xee, + 0xf0, 0xea, 0xea, 0xe5, 0xec, 0xf0, 0xec, 0xe8, 0xee, 0xf5, 0xf4, 0xee, + 0xee, 0xf0, 0xee, 0xea, 0xec, 0xec, 0xf4, 0xf5, 0xec, 0xf2, 0xf2, 0xf4, + 0xf0, 0xee, 0xf0, 0xf5, 0xf2, 0xf4, 0xf5, 0xf9, 0xfd, 0xfb, 0xf4, 0xff, + 0xff, 0xfd, 0xfb, 0xfd, 0x01, 0x00, 0xff, 0x00, 0x09, 0x00, 0x05, 0x09, + 0x09, 0x09, 0x0c, 0x05, 0x03, 0xff, 0x03, 0x0c, 0x0c, 0x00, 0x01, 0x09, + 0x0e, 0x0b, 0x09, 0x10, 0x10, 0x0b, 0x0e, 0x0b, 0x07, 0x0b, 0x0c, 0x0b, + 0x0e, 0x12, 0x10, 0x0e, 0x0c, 0x0e, 0x0e, 0x0c, 0x0c, 0x0e, 0x09, 0x10, + 0x0c, 0x14, 0x14, 0x10, 0x0e, 0x0c, 0x0b, 0x0e, 0x0e, 0x0e, 0x09, 0x09, + 0x0c, 0x0c, 0x0b, 0x0c, 0x07, 0x07, 0x0b, 0x05, 0x01, 0xff, 0x00, 0xfb, + 0x03, 0x01, 0x00, 0x01, 0x05, 0x05, 0xff, 0xf9, 0xf5, 0xfb, 0xf9, 0xf7, + 0xfb, 0xf2, 0xf4, 0xf4, 0xf5, 0xf2, 0xf4, 0xf5, 0xf2, 0xec, 0xee, 0xf0, + 0xea, 0xe7, 0xec, 0xee, 0xec, 0xea, 0xec, 0xf0, 0xee, 0xea, 0xec, 0xea, + 0xec, 0xea, 0xea, 0xf0, 0xec, 0xee, 0xea, 0xec, 0xf2, 0xf4, 0xf4, 0xee, + 0xf4, 0xf5, 0xf0, 0xf0, 0xf7, 0xfb, 0xfb, 0xf7, 0xf5, 0xf9, 0xfd, 0xfb, + 0xfd, 0x00, 0x00, 0xff, 0x00, 0x03, 0x01, 0x01, 0x05, 0x05, 0x01, 0x05, + 0x0b, 0x0e, 0x09, 0x05, 0x0b, 0x10, 0x09, 0x09, 0x0b, 0x10, 0x18, 0x14, + 0x12, 0x12, 0x12, 0x16, 0x12, 0x0c, 0x14, 0x19, 0x18, 0x18, 0x19, 0x1b, + 0x1b, 0x19, 0x16, 0x16, 0x1b, 0x1d, 0x1d, 0x1f, 0x16, 0x12, 0x16, 0x18, + 0x18, 0x12, 0x16, 0x19, 0x10, 0x12, 0x12, 0x10, 0x0e, 0x0b, 0x07, 0x09, + 0x0c, 0x05, 0x03, 0x03, 0x03, 0x05, 0x00, 0xfb, 0xfb, 0xfd, 0xf9, 0xf4, + 0xf5, 0xf7, 0xf4, 0xec, 0xea, 0xea, 0xf0, 0xee, 0xec, 0xe5, 0xe3, 0xea, + 0xe5, 0xe8, 0xdf, 0xdd, 0xe1, 0xe3, 0xdd, 0xdd, 0xe1, 0xe5, 0xdd, 0xdd, + 0xdd, 0xe1, 0xe3, 0xe7, 0xe3, 0xe5, 0xe3, 0xe1, 0xe3, 0xe8, 0xe1, 0xe7, + 0xec, 0xec, 0xe8, 0xec, 0xf0, 0xf2, 0xee, 0xec, 0xee, 0xfb, 0xff, 0xf9, + 0xf5, 0xff, 0xff, 0xff, 0xff, 0x03, 0x03, 0x05, 0x09, 0x09, 0x0b, 0x07, + 0x07, 0x0c, 0x10, 0x10, 0x0e, 0x0e, 0x16, 0x16, 0x10, 0x10, 0x14, 0x18, + 0x16, 0x16, 0x18, 0x18, 0x19, 0x16, 0x16, 0x12, 0x16, 0x19, 0x19, 0x1b, + 0x1b, 0x18, 0x18, 0x19, 0x1f, 0x18, 0x18, 0x19, 0x18, 0x1d, 0x19, 0x18, + 0x16, 0x18, 0x18, 0x19, 0x16, 0x12, 0x0c, 0x0e, 0x10, 0x0c, 0x0c, 0x0b, + 0x09, 0x05, 0x09, 0x05, 0xff, 0x00, 0xfb, 0xfd, 0xff, 0xf7, 0xf4, 0xf7, + 0xf7, 0xf7, 0xf4, 0xf0, 0xf4, 0xf0, 0xf0, 0xe7, 0xe5, 0xe8, 0xe7, 0xe7, + 0xea, 0xe8, 0xe7, 0xe7, 0xe7, 0xe5, 0xe3, 0xe1, 0xe3, 0xe1, 0xe3, 0xe5, + 0xe1, 0xdf, 0xe1, 0xe5, 0xea, 0xe7, 0xe3, 0xe5, 0xe8, 0xee, 0xf2, 0xec, + 0xe8, 0xe7, 0xec, 0xf4, 0xf7, 0xf5, 0xf7, 0xf4, 0xf9, 0xfd, 0xfd, 0xfb, + 0xfb, 0xfb, 0xff, 0x01, 0x01, 0x03, 0x03, 0x01, 0x00, 0x01, 0x07, 0x0b, + 0x05, 0x05, 0x09, 0x07, 0x0c, 0x0c, 0x0c, 0x14, 0x14, 0x14, 0x0c, 0x0c, + 0x0e, 0x0e, 0x10, 0x0c, 0x10, 0x16, 0x16, 0x10, 0x14, 0x16, 0x14, 0x16, + 0x14, 0x12, 0x18, 0x19, 0x14, 0x10, 0x1b, 0x1b, 0x19, 0x18, 0x14, 0x19, + 0x18, 0x14, 0x12, 0x14, 0x16, 0x12, 0x0c, 0x10, 0x12, 0x10, 0x0e, 0x0c, + 0x0b, 0x09, 0x07, 0x07, 0x07, 0x05, 0x03, 0x05, 0x03, 0x07, 0x00, 0xfb, + 0xf9, 0xff, 0x00, 0xfd, 0xf7, 0xf9, 0xf4, 0xf2, 0xf5, 0xf4, 0xf0, 0xf5, + 0xf2, 0xee, 0xea, 0xec, 0xec, 0xea, 0xe8, 0xea, 0xe3, 0xe5, 0xe7, 0xea, + 0xe8, 0xe5, 0xe7, 0xe8, 0xe7, 0xe1, 0xdf, 0xe3, 0xe7, 0xe3, 0xe5, 0xea, + 0xe8, 0xe8, 0xea, 0xee, 0xea, 0xe5, 0xe8, 0xee, 0xee, 0xf0, 0xf0, 0xf0, + 0xf4, 0xf4, 0xf0, 0xf2, 0xf2, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, 0xfb, + 0x00, 0x00, 0xfb, 0xff, 0x05, 0x09, 0x01, 0x09, 0x09, 0x07, 0x07, 0x0b, + 0x0e, 0x10, 0x0c, 0x12, 0x16, 0x12, 0x0e, 0x14, 0x16, 0x19, 0x1b, 0x18, + 0x18, 0x19, 0x1b, 0x1b, 0x1b, 0x18, 0x1b, 0x1d, 0x1f, 0x23, 0x1f, 0x1b, + 0x1b, 0x18, 0x19, 0x1b, 0x1d, 0x1f, 0x1d, 0x1b, 0x1d, 0x1b, 0x18, 0x18, + 0x16, 0x14, 0x16, 0x12, 0x12, 0x14, 0x10, 0x0e, 0x0e, 0x0c, 0x09, 0x05, + 0x07, 0x09, 0x07, 0x00, 0xfb, 0xfd, 0xf9, 0xf7, 0xf5, 0xf2, 0xf0, 0xf0, + 0xf0, 0xea, 0xec, 0xe7, 0xe8, 0xe5, 0xe5, 0xe7, 0xe3, 0xe3, 0xe1, 0xe1, + 0xda, 0xdb, 0xe5, 0xdf, 0xdb, 0xdd, 0xdb, 0xdf, 0xdd, 0xdd, 0xdb, 0xdd, + 0xdb, 0xdd, 0xdb, 0xdd, 0xe3, 0xe5, 0xe5, 0xe3, 0xe1, 0xe5, 0xe5, 0xe7, + 0xea, 0xea, 0xee, 0xf2, 0xf4, 0xf5, 0xf2, 0xf4, 0xf7, 0xfb, 0xfd, 0xfd, + 0xfd, 0xff, 0x01, 0x05, 0x07, 0x07, 0x07, 0x09, 0x07, 0x0c, 0x0b, 0x0e, + 0x0e, 0x12, 0x16, 0x16, 0x14, 0x19, 0x1b, 0x1b, 0x19, 0x19, 0x1b, 0x1b, + 0x1d, 0x1d, 0x1b, 0x1b, 0x1f, 0x23, 0x21, 0x1b, 0x1b, 0x1d, 0x19, 0x1b, + 0x1d, 0x1d, 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x16, 0x18, 0x16, 0x12, 0x12, + 0x12, 0x10, 0x0e, 0x0c, 0x09, 0x0b, 0x0b, 0x09, 0x05, 0x00, 0x03, 0xff, + 0x00, 0xfd, 0xfd, 0xfb, 0xf7, 0xfd, 0xf9, 0xf4, 0xf4, 0xf2, 0xf0, 0xee, + 0xea, 0xea, 0xea, 0xea, 0xe7, 0xe7, 0xe5, 0xe7, 0xe5, 0xe3, 0xe1, 0xe1, + 0xe3, 0xe3, 0xe3, 0xe5, 0xe1, 0xe1, 0xe3, 0xe7, 0xe7, 0xe7, 0xe8, 0xe5, + 0xe7, 0xe8, 0xea, 0xec, 0xea, 0xee, 0xf2, 0xf2, 0xf2, 0xee, 0xf4, 0xf4, + 0xf4, 0xf2, 0xf4, 0xf7, 0xf9, 0xf9, 0xf9, 0xfb, 0x00, 0x03, 0x01, 0x00, + 0x00, 0x03, 0x05, 0x05, 0x07, 0x0b, 0x0e, 0x0c, 0x0c, 0x10, 0x10, 0x0e, + 0x0c, 0x10, 0x14, 0x14, 0x12, 0x12, 0x12, 0x12, 0x12, 0x14, 0x12, 0x14, + 0x14, 0x12, 0x10, 0x10, 0x12, 0x0e, 0x0c, 0x0c, 0x10, 0x10, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0e, 0x0c, 0x0e, 0x09, 0x09, 0x0b, 0x09, 0x07, 0x05, 0x09, + 0x0c, 0x0b, 0x01, 0x07, 0x09, 0x05, 0x07, 0x01, 0x01, 0x00, 0xff, 0x00, + 0xff, 0xfb, 0xfb, 0xfd, 0xfd, 0xfb, 0xf7, 0xfb, 0xfd, 0xf7, 0xf5, 0xf5, + 0xf5, 0xf9, 0xf5, 0xf5, 0xf7, 0xf5, 0xf7, 0xf7, 0xf7, 0xf4, 0xf4, 0xf4, + 0xf9, 0xf7, 0xf4, 0xf5, 0xf9, 0xfb, 0xf9, 0xf5, 0xf4, 0xf7, 0xf2, 0xf5, + 0xf4, 0xf4, 0xf2, 0xf2, 0xf5, 0xf5, 0xf7, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, + 0xf5, 0xfb, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0xfb, 0xff, 0x01, 0x00, 0x00, + 0x00, 0x01, 0x01, 0xff, 0x00, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, + 0x01, 0x00, 0x00, 0x01, 0x03, 0x03, 0x01, 0x00, 0xfd, 0xff, 0x03, 0x01, + 0x01, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x05, 0x05, 0x05, 0x07, 0x07, + 0x07, 0x09, 0x07, 0x07, 0x05, 0x05, 0x0b, 0x09, 0x07, 0x09, 0x07, 0x09, + 0x09, 0x07, 0x05, 0x03, 0x05, 0x09, 0x07, 0x07, 0x09, 0x07, 0x05, 0x01, + 0x00, 0x03, 0x07, 0x07, 0x05, 0x03, 0x05, 0x01, 0x01, 0x03, 0x03, 0x01, + 0x07, 0x07, 0x03, 0x00, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0xfd, + 0xfb, 0xfd, 0xfb, 0xfb, 0xfb, 0xf9, 0xfb, 0xf9, 0xf5, 0xf5, 0xf5, 0xf7, + 0xf5, 0xf5, 0xf9, 0xf7, 0xf9, 0xf7, 0xf4, 0xf4, 0xf5, 0xf7, 0xf5, 0xf4, + 0xf2, 0xf4, 0xf7, 0xf7, 0xf9, 0xfb, 0xf9, 0xf4, 0xf5, 0xf9, 0xf9, 0xf7, + 0xf7, 0xf7, 0xfb, 0xfd, 0xfd, 0xfb, 0xf9, 0xfb, 0xfd, 0xfd, 0xfb, 0xfb, + 0xff, 0xff, 0xff, 0xff, 0xfd, 0xfd, 0x00, 0x01, 0x01, 0x00, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x01, 0x05, 0x05, 0x07, 0x09, 0x07, 0x07, 0x0b, 0x09, + 0x09, 0x07, 0x07, 0x07, 0x0b, 0x0c, 0x09, 0x05, 0x07, 0x09, 0x09, 0x07, + 0x07, 0x07, 0x05, 0x05, 0x05, 0x07, 0x07, 0x03, 0x03, 0x03, 0x09, 0x05, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x05, 0x03, 0x00, 0x01, 0x03, + 0x01, 0x01, 0x00, 0xfd, 0xff, 0x00, 0xff, 0xfd, 0xf9, 0xfb, 0xfb, 0xf9, + 0xf9, 0xf9, 0xf7, 0xf7, 0xf5, 0xf5, 0xf7, 0xfb, 0xf7, 0xf7, 0xf5, 0xf7, + 0xf9, 0xfb, 0xf9, 0xf9, 0xf9, 0xfb, 0xfb, 0xfb, 0xff, 0xfb, 0xf7, 0xfb, + 0xfd, 0xff, 0xfd, 0xf7, 0xf7, 0xf9, 0xfd, 0xfd, 0xfd, 0xfd, 0x00, 0x00, + 0x01, 0x00, 0xff, 0x00, 0xff, 0x01, 0x01, 0x00, 0x03, 0x03, 0x01, 0x03, + 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x07, 0x07, 0x09, 0x09, 0x07, + 0x07, 0x07, 0x05, 0x07, 0x09, 0x09, 0x07, 0x05, 0x07, 0x05, 0x07, 0x05, + 0x03, 0x03, 0x01, 0x00, 0x01, 0x05, 0x03, 0x00, 0xff, 0x01, 0x03, 0xff, + 0xfb, 0x00, 0xff, 0xfb, 0xfb, 0xff, 0xfd, 0xf9, 0xf9, 0xf7, 0xf9, 0xf7, + 0xf7, 0xf9, 0xfb, 0xf9, 0xf9, 0xf7, 0xf9, 0xf9, 0xf7, 0xf7, 0x00, 0x00, + 0xfe, 0xfc, 0xf4, 0xf4, 0xeb, 0xf4, 0xe4, 0xff, 0x01, 0xe7, 0xf4, 0xdb, + 0xff, 0xe3, 0x17, 0xfd, 0xfb, 0xe5, 0x02, 0x18, 0xdc, 0xf9, 0x0d, 0x0b, + 0x0b, 0x26, 0xe1, 0x34, 0x38, 0x24, 0xff, 0x22, 0x03, 0x26, 0x09, 0x4d, + 0x09, 0x34, 0x28, 0x22, 0x11, 0x3a, 0x20, 0x30, 0x1b, 0x30, 0x1d, 0x1d, + 0x2e, 0x32, 0x4f, 0x57, 0x38, 0x68, 0x20, 0x3c, 0xe1, 0x40, 0x2a, 0x40, + 0x3c, 0x26, 0x2e, 0x40, 0x53, 0x61, 0x1b, 0x45, 0x05, 0x49, 0x0b, 0x4b, + 0x4b, 0x40, 0x49, 0x32, 0x30, 0x2e, 0x59, 0x3a, 0x4d, 0xff, 0x1f, 0x4d, + 0x22, 0x4b, 0x00, 0x05, 0x3e, 0x4b, 0x1d, 0x03, 0x07, 0x45, 0x2e, 0x1d, + 0x34, 0x01, 0x20, 0x11, 0x0b, 0xfb, 0x30, 0x0b, 0xe5, 0x09, 0x13, 0x1b, + 0x0d, 0xff, 0xc8, 0x0b, 0xd4, 0x26, 0x11, 0xe3, 0xc0, 0xd2, 0x0d, 0xfb, + 0xc2, 0xda, 0xcc, 0xef, 0xd6, 0xfb, 0xd2, 0xed, 0xb1, 0xca, 0xe5, 0xc0, + 0xd4, 0xbb, 0xb9, 0xbd, 0xd6, 0xcc, 0xb3, 0xd6, 0xb5, 0xc0, 0xce, 0xce, + 0xbb, 0xbd, 0xb3, 0xd0, 0xbf, 0xb5, 0xb3, 0xbd, 0xbd, 0xc4, 0xc4, 0xc4, + 0xa7, 0xc2, 0xab, 0xd8, 0xb7, 0xc6, 0xc2, 0xb1, 0xbd, 0xd6, 0xca, 0xc4, + 0xbb, 0xc4, 0xe3, 0xb5, 0xe1, 0xbb, 0xd6, 0xdc, 0xde, 0xc0, 0xca, 0xd4, + 0xeb, 0xd8, 0xd6, 0xcc, 0xcc, 0xed, 0xde, 0xe9, 0xe1, 0xe1, 0xf5, 0xdc, + 0xda, 0xed, 0xf1, 0xf1, 0xe3, 0xda, 0xe9, 0xf5, 0xf7, 0xf3, 0xff, 0x03, + 0x0f, 0x07, 0xff, 0xff, 0x03, 0x07, 0x1b, 0x07, 0x07, 0x05, 0x24, 0x13, + 0x19, 0x0f, 0x1f, 0x0d, 0x1f, 0x20, 0x11, 0x20, 0x1f, 0x32, 0x28, 0x3a, + 0x20, 0x2e, 0x1b, 0x30, 0x2c, 0x3c, 0x2e, 0x2a, 0x30, 0x3e, 0x38, 0x34, + 0x24, 0x2e, 0x22, 0x2e, 0x32, 0x47, 0x30, 0x34, 0x38, 0x2c, 0x3a, 0x41, + 0x38, 0x2c, 0x45, 0x2c, 0x26, 0x38, 0x24, 0x22, 0x3e, 0x36, 0x3e, 0x28, + 0x24, 0x20, 0x2e, 0x28, 0x3a, 0x32, 0x32, 0x2c, 0x34, 0x17, 0x2e, 0x1d, + 0x2e, 0x2e, 0x32, 0x30, 0x2a, 0x26, 0x28, 0x19, 0x28, 0x24, 0x26, 0x32, + 0x1d, 0x1f, 0x26, 0x20, 0x24, 0x22, 0x1b, 0x17, 0x17, 0x1f, 0x24, 0x24, + 0x17, 0x1b, 0x17, 0x19, 0x13, 0x1d, 0x0f, 0x11, 0x0f, 0x0f, 0x0d, 0x0f, + 0x09, 0x11, 0x00, 0x0b, 0x05, 0x0d, 0x00, 0x0d, 0x01, 0x03, 0x03, 0xf7, + 0x01, 0xfd, 0x03, 0x07, 0xfb, 0x01, 0xf9, 0xf7, 0xf5, 0xfd, 0xf7, 0xf5, + 0xf7, 0xe9, 0xf1, 0x00, 0xf7, 0xeb, 0xde, 0xe1, 0xde, 0xe9, 0xf1, 0xef, + 0xed, 0xe3, 0xd4, 0xde, 0xe3, 0xe3, 0xe0, 0xe0, 0xdc, 0xde, 0xd8, 0xda, + 0xd8, 0xd8, 0xd4, 0xd2, 0xcc, 0xd0, 0xcc, 0xc8, 0xce, 0xd6, 0xcc, 0xca, + 0xc8, 0xc8, 0xc6, 0xcc, 0xc4, 0xca, 0xc4, 0xc6, 0xc6, 0xc6, 0xc6, 0xcc, + 0xc2, 0xc0, 0xc4, 0xc8, 0xca, 0xcc, 0xca, 0xc4, 0xc8, 0xc6, 0xce, 0xc4, + 0xce, 0xc8, 0xc6, 0xce, 0xce, 0xd0, 0xd4, 0xd4, 0xd4, 0xd6, 0xd6, 0xd8, + 0xd8, 0xd4, 0xd8, 0xde, 0xde, 0xde, 0xe0, 0xe1, 0xde, 0xe1, 0xe1, 0xe5, + 0xe7, 0xeb, 0xed, 0xed, 0xe9, 0xeb, 0xef, 0xf1, 0xf3, 0xef, 0xf7, 0xfd, + 0xfb, 0xf7, 0xf5, 0xf9, 0xff, 0xfd, 0xff, 0xff, 0x03, 0x07, 0x05, 0x00, + 0x09, 0x07, 0x0d, 0x09, 0x0d, 0x09, 0x11, 0x15, 0x1b, 0x15, 0x0f, 0x0d, + 0x13, 0x13, 0x15, 0x17, 0x1d, 0x17, 0x17, 0x17, 0x1d, 0x1d, 0x24, 0x24, + 0x22, 0x1d, 0x1d, 0x22, 0x26, 0x26, 0x26, 0x20, 0x22, 0x22, 0x22, 0x24, + 0x26, 0x26, 0x28, 0x2a, 0x28, 0x20, 0x22, 0x26, 0x26, 0x2a, 0x2a, 0x2a, + 0x28, 0x2a, 0x26, 0x24, 0x22, 0x28, 0x2a, 0x2a, 0x28, 0x2a, 0x2c, 0x2e, + 0x2c, 0x28, 0x26, 0x26, 0x26, 0x26, 0x2a, 0x28, 0x26, 0x26, 0x26, 0x22, + 0x1f, 0x24, 0x28, 0x2a, 0x2a, 0x22, 0x24, 0x26, 0x24, 0x20, 0x1f, 0x20, + 0x1f, 0x1d, 0x1d, 0x19, 0x1b, 0x1b, 0x1f, 0x1f, 0x1b, 0x15, 0x17, 0x1b, + 0x1f, 0x1b, 0x15, 0x13, 0x13, 0x11, 0x11, 0x13, 0x15, 0x13, 0x11, 0x0d, + 0x0b, 0x0d, 0x0d, 0x0b, 0x0d, 0x0b, 0x05, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x09, 0x05, 0xff, 0xf9, 0xf7, 0xfd, 0x01, 0x01, 0x00, 0xff, 0xfb, 0xf9, + 0xf9, 0xf9, 0xf5, 0xf5, 0xf9, 0xf9, 0xf5, 0xef, 0xef, 0xed, 0xf1, 0xf3, + 0xf1, 0xef, 0xeb, 0xe9, 0xe9, 0xeb, 0xeb, 0xeb, 0xe7, 0xe7, 0xe5, 0xe7, + 0xed, 0xeb, 0xe3, 0xe0, 0xe1, 0xe3, 0xe3, 0xe1, 0xe3, 0xe5, 0xe7, 0xe7, + 0xe1, 0xe0, 0xde, 0xe0, 0xe0, 0xe0, 0xe1, 0xe1, 0xe3, 0xe3, 0xe5, 0xe7, + 0xe3, 0xde, 0xde, 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xdc, 0xe1, 0xe3, 0xe1, + 0xe3, 0xe1, 0xe1, 0xe0, 0xe0, 0xe1, 0xe0, 0xe1, 0xe3, 0xe7, 0xeb, 0xe7, + 0xe3, 0xe0, 0xe0, 0xe3, 0xe5, 0xe7, 0xe3, 0xe1, 0xe3, 0xe7, 0xed, 0xed, + 0xeb, 0xe9, 0xed, 0xed, 0xef, 0xed, 0xef, 0xed, 0xeb, 0xed, 0xf1, 0xf3, + 0xf3, 0xf5, 0xf5, 0xf3, 0xf1, 0xef, 0xef, 0xf1, 0xf5, 0xf5, 0xf3, 0xf1, + 0xed, 0xf1, 0xf5, 0xf9, 0xfd, 0xfd, 0xf7, 0xf3, 0xf3, 0xf7, 0xf9, 0xfb, + 0xfb, 0xfb, 0xf9, 0xf9, 0xf9, 0xf9, 0xfb, 0xfd, 0xff, 0xfd, 0xff, 0xfd, + 0xfd, 0xfd, 0x00, 0xff, 0xfd, 0xfd, 0xfd, 0x00, 0x01, 0x01, 0xff, 0xfd, + 0xfd, 0x00, 0x01, 0x03, 0x03, 0x03, 0x01, 0x00, 0xff, 0x01, 0x01, 0x03, + 0x03, 0x00, 0x00, 0x01, 0x05, 0x05, 0x05, 0x03, 0x03, 0x05, 0x03, 0x01, + 0x03, 0x07, 0x09, 0x07, 0x03, 0x01, 0x05, 0x07, 0x09, 0x07, 0x05, 0x05, + 0x07, 0x0b, 0x09, 0x05, 0x03, 0x01, 0x03, 0x07, 0x09, 0x0b, 0x09, 0x09, + 0x0b, 0x0b, 0x0b, 0x0d, 0x0b, 0x0d, 0x0d, 0x0d, 0x0d, 0x0b, 0x07, 0x09, + 0x0b, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x13, 0x13, 0x11, 0x0f, 0x0d, 0x0d, + 0x0f, 0x11, 0x11, 0x0f, 0x0d, 0x0f, 0x0f, 0x11, 0x0f, 0x11, 0x13, 0x0f, + 0x0f, 0x0f, 0x13, 0x13, 0x15, 0x13, 0x11, 0x11, 0x11, 0x0f, 0x0f, 0x0d, + 0x13, 0x17, 0x13, 0x11, 0x11, 0x13, 0x15, 0x13, 0x13, 0x15, 0x15, 0x17, + 0x15, 0x11, 0x11, 0x15, 0x17, 0x15, 0x13, 0x15, 0x19, 0x19, 0x19, 0x15, + 0x13, 0x13, 0x15, 0x15, 0x15, 0x17, 0x17, 0x15, 0x13, 0x13, 0x13, 0x13, + 0x11, 0x15, 0x15, 0x15, 0x15, 0x15, 0x17, 0x17, 0x15, 0x15, 0x13, 0x0f, + 0x0f, 0x17, 0x1d, 0x1b, 0x17, 0x15, 0x13, 0x15, 0x1b, 0x1b, 0x17, 0x17, + 0x17, 0x17, 0x15, 0x15, 0x13, 0x11, 0x11, 0x13, 0x15, 0x17, 0x11, 0x0d, + 0x0d, 0x0f, 0x0f, 0x0f, 0x0d, 0x0b, 0x09, 0x0b, 0x0f, 0x0d, 0x09, 0x09, + 0x07, 0x09, 0x0b, 0x0b, 0x09, 0x01, 0x00, 0x01, 0x03, 0x03, 0x03, 0x00, + 0xff, 0xff, 0xff, 0xfd, 0xfd, 0xfb, 0xfb, 0xfb, 0xf9, 0xf9, 0xf7, 0xf3, + 0xf3, 0xf5, 0xf7, 0xf5, 0xf1, 0xf1, 0xf3, 0xf3, 0xf1, 0xed, 0xeb, 0xe9, + 0xed, 0xed, 0xed, 0xeb, 0xe9, 0xe7, 0xe7, 0xe5, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe5, 0xe3, 0xe0, 0xe0, 0xe0, 0xe0, 0xde, 0xdc, 0xde, + 0xe0, 0xe0, 0xdc, 0xd8, 0xd8, 0xdc, 0xde, 0xda, 0xd8, 0xd8, 0xde, 0xe0, + 0xdc, 0xda, 0xda, 0xdc, 0xde, 0xe0, 0xde, 0xdc, 0xdc, 0xde, 0xde, 0xdc, + 0xdc, 0xde, 0xde, 0xdc, 0xdc, 0xdc, 0xde, 0xe1, 0xe3, 0xe1, 0xe0, 0xe0, + 0xde, 0xe0, 0xe0, 0xe1, 0xe3, 0xe5, 0xe1, 0xe0, 0xe1, 0xe3, 0xe7, 0xe9, + 0xe9, 0xe9, 0xeb, 0xeb, 0xe9, 0xe7, 0xe5, 0xe9, 0xed, 0xed, 0xe9, 0xe5, + 0xe3, 0xe7, 0xeb, 0xed, 0xeb, 0xeb, 0xeb, 0xe9, 0xeb, 0xed, 0xf1, 0xf1, + 0xf1, 0xef, 0xed, 0xeb, 0xed, 0xf1, 0xf3, 0xf1, 0xed, 0xed, 0xef, 0xf1, + 0xf5, 0xf3, 0xf3, 0xf5, 0xf5, 0xf5, 0xf7, 0xf7, 0xf9, 0xf9, 0xf9, 0xf9, + 0xfb, 0xfd, 0xfd, 0xff, 0xfd, 0xfb, 0xf9, 0xfd, 0xfd, 0xff, 0xfd, 0xfd, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, + 0x03, 0x01, 0x01, 0x05, 0x07, 0x07, 0x09, 0x09, 0x05, 0x05, 0x01, 0x03, + 0x05, 0x07, 0x05, 0x05, 0x05, 0x07, 0x0b, 0x0d, 0x07, 0x05, 0x05, 0x07, + 0x0d, 0x0d, 0x0b, 0x09, 0x0d, 0x0f, 0x0f, 0x0d, 0x0d, 0x0f, 0x0f, 0x0f, + 0x0d, 0x0d, 0x0f, 0x0f, 0x13, 0x17, 0x15, 0x11, 0x0f, 0x11, 0x13, 0x15, + 0x15, 0x17, 0x17, 0x19, 0x19, 0x19, 0x15, 0x11, 0x11, 0x15, 0x1b, 0x1f, + 0x1b, 0x17, 0x11, 0x15, 0x19, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1b, 0x19, + 0x19, 0x19, 0x1b, 0x1f, 0x1f, 0x1d, 0x1d, 0x1d, 0x1b, 0x19, 0x1b, 0x1d, + 0x1d, 0x1b, 0x1d, 0x1f, 0x1f, 0x1f, 0x1d, 0x1b, 0x19, 0x19, 0x1b, 0x1b, + 0x1d, 0x1d, 0x1b, 0x1d, 0x1d, 0x1f, 0x1f, 0x19, 0x15, 0x17, 0x1b, 0x20, + 0x22, 0x1f, 0x1b, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1b, 0x1b, 0x19, 0x17, + 0x17, 0x19, 0x19, 0x17, 0x15, 0x15, 0x17, 0x19, 0x17, 0x13, 0x11, 0x11, + 0x13, 0x15, 0x13, 0x0f, 0x0f, 0x0d, 0x09, 0x07, 0x09, 0x0d, 0x0f, 0x0f, + 0x0d, 0x07, 0x07, 0x07, 0x09, 0x09, 0x09, 0x05, 0x05, 0x03, 0x05, 0x07, + 0x07, 0x03, 0x01, 0x00, 0x01, 0x03, 0x05, 0x05, 0x03, 0x00, 0xff, 0xff, + 0x00, 0x01, 0x01, 0xff, 0xff, 0xfd, 0xfb, 0xfb, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfd, 0xfb, 0xfb, 0xfb, 0xf9, 0xf9, 0xfb, 0xfd, 0xfd, 0xfd, 0xfd, + 0xf9, 0xf7, 0xf9, 0xfb, 0xfd, 0xfb, 0xf9, 0xf9, 0xf9, 0xf7, 0xf5, 0xf1, + 0xf1, 0xf3, 0xf7, 0xf9, 0xf5, 0xf1, 0xf1, 0xf3, 0xf5, 0xf5, 0xf1, 0xef, + 0xef, 0xf1, 0xf1, 0xf1, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xf1, 0xf3, + 0xf1, 0xef, 0xed, 0xeb, 0xeb, 0xeb, 0xef, 0xef, 0xed, 0xeb, 0xe7, 0xe9, + 0xe9, 0xeb, 0xed, 0xed, 0xeb, 0xe9, 0xeb, 0xeb, 0xe5, 0xe3, 0xe5, 0xe9, + 0xed, 0xed, 0xe7, 0xe1, 0xe1, 0xe5, 0xe7, 0xe7, 0xe7, 0xeb, 0xe9, 0xe5, + 0xe3, 0xe1, 0xe3, 0xe9, 0xeb, 0xe9, 0xe3, 0xe1, 0xe3, 0xe3, 0xe3, 0xe3, + 0xe3, 0xe5, 0xe3, 0xe1, 0xe3, 0xe7, 0xe9, 0xe7, 0xe3, 0xe1, 0xe1, 0xe3, + 0xe5, 0xe5, 0xe3, 0xe5, 0xe7, 0xe7, 0xe7, 0xe7, 0xe3, 0xe3, 0xe7, 0xe9, + 0xed, 0xeb, 0xe9, 0xeb, 0xe9, 0xe7, 0xe5, 0xe5, 0xe9, 0xeb, 0xeb, 0xe9, + 0xeb, 0xed, 0xed, 0xed, 0xeb, 0xeb, 0xeb, 0xe7, 0xe9, 0xe9, 0xf1, 0xf7, + 0xf7, 0xf1, 0xeb, 0xeb, 0xf3, 0xf7, 0xf5, 0xf1, 0xef, 0xf1, 0xf3, 0xf3, + 0xf3, 0xf3, 0xf5, 0xf7, 0xf7, 0xf3, 0xf3, 0xf5, 0xf9, 0xf9, 0xf7, 0xf7, + 0xfb, 0xfb, 0xfb, 0xfb, 0xf9, 0xf9, 0xf7, 0xf7, 0xf7, 0xfb, 0xfd, 0x00, + 0x01, 0x00, 0xfd, 0xf9, 0xfb, 0xff, 0x01, 0x07, 0x09, 0x07, 0x03, 0xfd, + 0xf9, 0xfb, 0x03, 0x09, 0x07, 0x03, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09, + 0x09, 0x07, 0x05, 0x05, 0x05, 0x0b, 0x0d, 0x0b, 0x07, 0x07, 0x0b, 0x0d, + 0x0f, 0x0d, 0x09, 0x09, 0x07, 0x07, 0x0b, 0x0f, 0x11, 0x11, 0x0d, 0x0b, + 0x0b, 0x0d, 0x0d, 0x0f, 0x0f, 0x0f, 0x0d, 0x0f, 0x15, 0x17, 0x15, 0x0f, + 0x0b, 0x0f, 0x11, 0x13, 0x13, 0x15, 0x15, 0x15, 0x13, 0x11, 0x13, 0x19, + 0x1d, 0x19, 0x13, 0x0d, 0x11, 0x17, 0x19, 0x17, 0x13, 0x11, 0x17, 0x1d, + 0x1f, 0x19, 0x17, 0x15, 0x15, 0x17, 0x1d, 0x1f, 0x1f, 0x1b, 0x00, 0x00, + 0xff, 0xf6, 0x01, 0xff, 0xff, 0xf9, 0x01, 0xf6, 0x09, 0xff, 0xf1, 0x03, + 0x01, 0xfb, 0xfd, 0x02, 0xf3, 0x07, 0xfa, 0xdd, 0x16, 0xf0, 0xee, 0xf2, + 0x13, 0xf1, 0xf5, 0x01, 0xf6, 0xf9, 0xf9, 0x00, 0x01, 0xea, 0xfb, 0x10, + 0x09, 0x0b, 0x46, 0x14, 0xea, 0x27, 0x0a, 0xee, 0xdd, 0xff, 0x00, 0x0f, + 0x0a, 0x14, 0xf2, 0xfe, 0xe0, 0xfd, 0xd3, 0xbd, 0xcb, 0xe0, 0xcc, 0xb6, + 0xe1, 0xd4, 0xca, 0xdc, 0xd0, 0xe8, 0x09, 0x16, 0xf2, 0xdb, 0xf6, 0xf6, + 0x05, 0x14, 0x24, 0x35, 0x42, 0x48, 0x43, 0x42, 0x4c, 0x51, 0x54, 0x46, + 0x5d, 0x50, 0x28, 0x4c, 0x37, 0x28, 0x50, 0x48, 0x41, 0x09, 0x12, 0xdb, + 0xcc, 0xfb, 0xe9, 0x00, 0xee, 0xea, 0xf3, 0xf0, 0xc9, 0xe3, 0xbd, 0xb2, + 0xb0, 0xad, 0xb0, 0xb5, 0x9c, 0xb0, 0xb2, 0xb0, 0xa0, 0xa8, 0xd0, 0xc5, + 0xc7, 0xf2, 0xf6, 0xf1, 0xfe, 0x02, 0xee, 0x03, 0x09, 0x0e, 0x3f, 0x47, + 0x59, 0x42, 0x46, 0x62, 0x47, 0x4c, 0x30, 0x32, 0x20, 0x0e, 0xf1, 0xf9, + 0x09, 0xf5, 0xe8, 0x0a, 0xf9, 0xed, 0xd4, 0xc9, 0xc7, 0xc2, 0xba, 0xee, + 0xca, 0xb4, 0xb2, 0xb2, 0xa8, 0xb4, 0xc2, 0xc3, 0xd7, 0xd6, 0x03, 0x2d, + 0x1c, 0x41, 0x41, 0x30, 0x29, 0x4f, 0x48, 0x41, 0x51, 0x5e, 0x48, 0x51, + 0x50, 0x4b, 0x43, 0x37, 0x3a, 0x35, 0x31, 0x2a, 0x20, 0x16, 0x09, 0x02, + 0xfa, 0xf5, 0xe0, 0xd2, 0xf0, 0xd0, 0xbe, 0xaf, 0xca, 0xb0, 0x9a, 0xad, + 0xb5, 0xad, 0x9c, 0xcc, 0xc6, 0xcf, 0xd8, 0xd3, 0xb6, 0xbd, 0xd7, 0xdc, + 0xdb, 0xed, 0xf6, 0xe5, 0xf1, 0x0e, 0xfa, 0x0a, 0xfb, 0x06, 0x0f, 0x13, + 0x1a, 0x1b, 0x27, 0x32, 0x20, 0x3b, 0x3f, 0x36, 0x1f, 0x47, 0x37, 0x2d, + 0x36, 0x3d, 0x27, 0x25, 0x24, 0x05, 0x27, 0x1f, 0x06, 0xf7, 0xff, 0xe8, + 0xd6, 0xd8, 0xdf, 0xdb, 0xd8, 0xec, 0xc5, 0xcb, 0xd4, 0xc9, 0xb6, 0xdd, + 0xdc, 0xf1, 0xe5, 0xf1, 0x01, 0xf3, 0xf0, 0x06, 0xfe, 0x06, 0x09, 0x0b, + 0x1f, 0x2d, 0x27, 0x30, 0x37, 0x23, 0x29, 0x27, 0x2c, 0x20, 0x48, 0x25, + 0x03, 0x0d, 0xe6, 0xec, 0xdd, 0xd2, 0xf5, 0xd3, 0xcf, 0xd7, 0xd6, 0xc2, + 0xb2, 0xce, 0xc2, 0xc3, 0xdf, 0xf1, 0xe9, 0xee, 0xe5, 0xcf, 0x0a, 0xf6, + 0xf6, 0x06, 0x16, 0x0d, 0xf1, 0x2a, 0x0f, 0x16, 0x3a, 0x2e, 0x1c, 0x32, + 0x28, 0x2c, 0x0f, 0x27, 0x23, 0x1f, 0x02, 0x1f, 0x0a, 0x01, 0xfa, 0x0d, + 0xf3, 0xf2, 0x07, 0x05, 0x05, 0xf5, 0x0d, 0xfd, 0xf6, 0xf0, 0xf5, 0xe9, + 0xdf, 0xd7, 0xf2, 0xdf, 0xcb, 0xec, 0xe5, 0xe0, 0xfe, 0xe9, 0xf6, 0xf7, + 0xd9, 0xe0, 0xe1, 0xdf, 0xdf, 0xe6, 0xe9, 0xec, 0xed, 0xdd, 0xf3, 0x0b, + 0x0d, 0x03, 0x2a, 0x28, 0x28, 0x1c, 0x35, 0x29, 0x2e, 0x18, 0x25, 0x27, + 0x30, 0x1a, 0x27, 0x29, 0x1a, 0x0e, 0x0b, 0x14, 0x03, 0x09, 0xf6, 0xe4, + 0x02, 0xdd, 0xcc, 0xdb, 0xd9, 0xcc, 0xb0, 0xdf, 0xc7, 0xca, 0xc7, 0xd9, + 0xd2, 0xdc, 0xf3, 0xfa, 0xff, 0x06, 0x0f, 0x13, 0x05, 0x0a, 0x1c, 0xff, + 0x16, 0x17, 0x03, 0x0a, 0x30, 0x05, 0x1f, 0x23, 0x20, 0x0d, 0x2e, 0x1b, + 0x12, 0x03, 0x07, 0xfa, 0xf7, 0xf0, 0xe5, 0xdd, 0xdd, 0xe3, 0xe1, 0xd2, + 0xf3, 0xe4, 0xd0, 0xf0, 0xee, 0xf5, 0xea, 0x0e, 0xf2, 0xff, 0xed, 0xe6, + 0x09, 0xf6, 0xfb, 0xee, 0x1c, 0xfa, 0x01, 0x0f, 0x0b, 0x0a, 0x0b, 0x10, + 0x05, 0x00, 0x0a, 0x01, 0xfb, 0x00, 0x0b, 0x07, 0xf2, 0x1a, 0x01, 0x0d, + 0x02, 0x10, 0x17, 0x00, 0x18, 0x1a, 0x14, 0xfd, 0x1b, 0xf6, 0x07, 0x02, + 0xf6, 0x01, 0xfb, 0xf2, 0xd8, 0xf7, 0xdc, 0xdc, 0xe3, 0xdb, 0xc7, 0xfb, + 0xe3, 0xd8, 0xe3, 0xf1, 0xcf, 0xdd, 0xe8, 0xe1, 0xdc, 0xee, 0x01, 0xe6, + 0x03, 0x06, 0x07, 0x02, 0x27, 0x21, 0x27, 0x27, 0x30, 0x27, 0x1d, 0x2c, + 0x1a, 0xfe, 0x24, 0x12, 0x10, 0x06, 0x1b, 0x07, 0xff, 0x09, 0x03, 0xed, + 0xf9, 0xf9, 0xea, 0xd7, 0xec, 0xe3, 0xdd, 0xdb, 0xdc, 0xd7, 0xd3, 0xdb, + 0xe1, 0xe0, 0xf3, 0xfd, 0xff, 0xf9, 0x10, 0x01, 0xfe, 0x16, 0x10, 0x09, + 0x13, 0x02, 0x01, 0x1a, 0x07, 0xf6, 0x0d, 0x06, 0x06, 0x01, 0x0d, 0x03, + 0x0b, 0x09, 0xf5, 0xfd, 0xfd, 0x02, 0xfa, 0xf6, 0x06, 0xe6, 0x06, 0xf7, + 0xf0, 0x0a, 0xfe, 0xfb, 0x03, 0x0a, 0x0d, 0x0a, 0x07, 0xf9, 0x0f, 0xfb, + 0xf3, 0xf3, 0xee, 0xf0, 0xea, 0xdb, 0xf9, 0xea, 0xe3, 0xea, 0xfa, 0xea, + 0xf7, 0x01, 0x02, 0xe6, 0x02, 0xf5, 0xfa, 0xf9, 0xff, 0xf7, 0xfb, 0x14, + 0x0e, 0xff, 0x1d, 0x18, 0x1b, 0x1b, 0x0b, 0x2a, 0x20, 0x18, 0x0f, 0x18, + 0x0b, 0x02, 0x00, 0xfe, 0xfa, 0xfa, 0xe4, 0xfa, 0xe8, 0xf0, 0xe1, 0xe3, + 0xdf, 0xcc, 0xe4, 0xd8, 0xc7, 0xd9, 0xe4, 0xdb, 0xcc, 0xf6, 0xe1, 0xd9, + 0xfa, 0xf2, 0xf6, 0x00, 0x12, 0x03, 0x0e, 0x1b, 0x1a, 0x20, 0x13, 0x27, + 0x1f, 0x0d, 0x25, 0x17, 0x14, 0x13, 0x05, 0x07, 0x10, 0x06, 0x03, 0x18, + 0x0f, 0xff, 0x0d, 0x0a, 0x00, 0xfb, 0xe6, 0xfe, 0xf9, 0xf9, 0xf6, 0xea, + 0x01, 0xf0, 0xec, 0xe3, 0xfa, 0xf1, 0xed, 0xf5, 0xfe, 0x02, 0xee, 0xfd, + 0xf6, 0xf5, 0xf6, 0xec, 0xed, 0xf6, 0xf5, 0xec, 0xf0, 0x07, 0xfd, 0xf0, + 0x07, 0x01, 0xff, 0xf6, 0x07, 0x03, 0x01, 0x06, 0x07, 0x06, 0x06, 0x09, + 0xf3, 0x06, 0x17, 0x0a, 0x18, 0x16, 0x12, 0x0f, 0x05, 0x02, 0x01, 0xf5, + 0xfb, 0xfd, 0xf1, 0xf7, 0xf2, 0xea, 0xed, 0xed, 0xd8, 0xdc, 0xf0, 0xe0, + 0xec, 0xfd, 0xf2, 0xed, 0x0f, 0xf6, 0xea, 0xfd, 0xfd, 0x02, 0xf0, 0x0d, + 0x06, 0x07, 0xfd, 0x21, 0xfb, 0x10, 0x1c, 0x16, 0x09, 0x24, 0x1b, 0x18, + 0x01, 0x1d, 0x06, 0xfa, 0xf9, 0xf9, 0xee, 0xf1, 0xe8, 0xee, 0xf0, 0xf0, + 0xf5, 0xfd, 0xee, 0xe9, 0x01, 0xee, 0xec, 0xf2, 0xec, 0xd8, 0xf6, 0xec, + 0xea, 0xe5, 0x01, 0xf6, 0xf5, 0xff, 0x02, 0x06, 0x0f, 0x06, 0xfb, 0x12, + 0x01, 0xf7, 0x05, 0x09, 0x09, 0x0f, 0xf9, 0x10, 0x0e, 0x0b, 0xf7, 0x17, + 0x05, 0x00, 0x05, 0x0e, 0x05, 0x12, 0x0b, 0xfb, 0x14, 0x05, 0x0a, 0x00, + 0x05, 0x02, 0x00, 0xff, 0xfd, 0xfa, 0xf9, 0xf9, 0xe6, 0x06, 0xf9, 0xf7, + 0xe5, 0xff, 0xec, 0xdd, 0xf5, 0xf1, 0xdd, 0xe5, 0xea, 0xe9, 0xd8, 0xf9, + 0xf1, 0xee, 0xee, 0x0b, 0xea, 0xfe, 0x02, 0x01, 0xf2, 0x0f, 0x00, 0x0b, + 0x01, 0x05, 0x09, 0xf3, 0x0e, 0x0f, 0x0e, 0x00, 0x1f, 0x10, 0x0f, 0xfe, + 0x1d, 0x06, 0xf7, 0x01, 0x06, 0xff, 0xfe, 0xff, 0xfb, 0xff, 0xf7, 0xf3, + 0xfd, 0xf6, 0xf6, 0xf6, 0xf7, 0xed, 0xfb, 0xf2, 0xe9, 0xf6, 0x01, 0xfe, + 0xf1, 0x0a, 0xff, 0xed, 0x09, 0x00, 0xfb, 0xfd, 0x0b, 0x06, 0x0b, 0x12, + 0x0f, 0x0a, 0x0a, 0x09, 0x09, 0x00, 0xf3, 0x09, 0xee, 0xf6, 0xfb, 0xee, + 0xe5, 0x0a, 0xe8, 0xf3, 0x02, 0xfb, 0xed, 0x00, 0xfd, 0xf6, 0xea, 0xf7, + 0xee, 0xee, 0xf2, 0xee, 0xe8, 0xfe, 0xee, 0xed, 0xff, 0xfe, 0x02, 0xf5, + 0x0b, 0x03, 0x03, 0x0b, 0x06, 0x09, 0x06, 0x05, 0x03, 0x03, 0x03, 0x06, + 0xfb, 0x06, 0x12, 0x0a, 0xfe, 0x18, 0x07, 0xfd, 0x0f, 0x05, 0xfe, 0x01, + 0x07, 0x01, 0xfa, 0x0d, 0x00, 0xf0, 0x09, 0xff, 0x03, 0xf1, 0x0a, 0xfe, + 0xf3, 0xfd, 0xf7, 0xfe, 0xe4, 0x00, 0xf3, 0xe4, 0xf9, 0xec, 0xf0, 0xee, + 0xee, 0xee, 0xf0, 0xf0, 0xf5, 0xfe, 0xff, 0xe6, 0x0a, 0xff, 0xfd, 0x02, + 0x0b, 0xff, 0xfd, 0x06, 0x00, 0xff, 0xfd, 0x01, 0xff, 0x06, 0x0a, 0x0e, + 0x00, 0x10, 0x07, 0x0f, 0x05, 0xf5, 0x07, 0xfa, 0x00, 0xe9, 0xfa, 0xf2, + 0xf6, 0xe0, 0xf3, 0xf2, 0xf7, 0xe8, 0x0a, 0xfe, 0xfd, 0xf7, 0x05, 0xf9, + 0x01, 0x09, 0xfa, 0x06, 0x13, 0x00, 0x05, 0x16, 0x0a, 0x00, 0x0f, 0x06, + 0x0b, 0x0b, 0x0a, 0xfb, 0x13, 0x03, 0xfb, 0xff, 0xfd, 0x00, 0xf2, 0xec, + 0xfa, 0xf1, 0xe6, 0xec, 0xf9, 0xec, 0xe0, 0xf7, 0xec, 0xf1, 0xf2, 0xf6, + 0xf3, 0xff, 0x05, 0x02, 0xf7, 0x07, 0x01, 0x01, 0x02, 0x0a, 0xfa, 0x06, + 0x12, 0x02, 0xf5, 0x13, 0x02, 0xff, 0xfd, 0x07, 0xf7, 0xf3, 0xf5, 0xee, + 0xf1, 0xf1, 0xf0, 0xed, 0xff, 0xf9, 0xf9, 0xff, 0x01, 0xff, 0x09, 0x09, + 0xff, 0x02, 0x09, 0xff, 0x05, 0x06, 0x0a, 0xfa, 0x0a, 0x0d, 0x07, 0xfd, + 0x17, 0x05, 0x09, 0xfe, 0xf7, 0x0b, 0xf9, 0xe8, 0xfe, 0xf5, 0xf2, 0xe8, + 0xf5, 0xec, 0xf5, 0xe8, 0xf6, 0xf7, 0xf6, 0xf9, 0xfa, 0x01, 0xee, 0x06, + 0x09, 0x01, 0x0d, 0x16, 0x0d, 0xfd, 0x17, 0x0d, 0x03, 0x09, 0x13, 0x09, + 0xfa, 0x0f, 0x06, 0x02, 0xfd, 0x05, 0xf9, 0xf9, 0xf5, 0xf2, 0xe3, 0xec, + 0xe5, 0xe5, 0xe6, 0xed, 0xdb, 0xee, 0xf7, 0xec, 0xfb, 0x00, 0xff, 0xf3, + 0x0a, 0x05, 0x03, 0x01, 0x14, 0x06, 0x09, 0x0a, 0x07, 0x0b, 0x06, 0x06, + 0x07, 0x09, 0x06, 0x05, 0xf7, 0x02, 0x02, 0xfa, 0xf5, 0x02, 0xf5, 0xf6, + 0xf3, 0xf5, 0xf7, 0xfb, 0x00, 0xf3, 0xff, 0x07, 0xfd, 0xf7, 0x05, 0xff, + 0xfb, 0xff, 0x02, 0x06, 0xfd, 0x03, 0x09, 0x03, 0xff, 0xfa, 0x02, 0xfa, + 0xee, 0xf6, 0xf9, 0xea, 0xf1, 0xf0, 0xea, 0xf1, 0xed, 0xe6, 0xf1, 0xec, + 0xf0, 0xf2, 0xf0, 0xf9, 0xf7, 0xf5, 0x03, 0x02, 0xfa, 0x14, 0x12, 0x14, + 0x0b, 0x2d, 0x16, 0x1a, 0x0f, 0x1f, 0x0d, 0x09, 0x10, 0x0b, 0x06, 0x05, + 0x02, 0xfd, 0xfd, 0xf9, 0xf5, 0xe1, 0xf7, 0xee, 0xf1, 0xdc, 0xf2, 0xea, + 0xe8, 0xe1, 0xf2, 0xea, 0xf7, 0xee, 0xf3, 0x00, 0xff, 0xf6, 0x0e, 0x06, + 0x07, 0xff, 0x1a, 0x0d, 0x02, 0x13, 0x0f, 0x00, 0x09, 0x0d, 0xfb, 0xfd, + 0x01, 0xf9, 0xf1, 0xfd, 0xf9, 0xfe, 0xf0, 0xf5, 0xfd, 0xf6, 0xe5, 0xf6, + 0xf1, 0xe3, 0xfb, 0xf6, 0xed, 0x09, 0x00, 0xfd, 0x03, 0x07, 0xfa, 0x06, + 0x09, 0x00, 0x0e, 0x0b, 0x0b, 0x0a, 0xfe, 0x0f, 0x01, 0xf6, 0x01, 0xf9, + 0xf7, 0xf6, 0xed, 0xfb, 0xf3, 0xf2, 0xe6, 0xf7, 0xf1, 0xee, 0xf1, 0xf9, + 0xec, 0xf7, 0xfd, 0xf6, 0xfd, 0x00, 0x06, 0xf9, 0x06, 0x1a, 0x13, 0x07, + 0x24, 0x1a, 0x0d, 0x1b, 0x0f, 0x09, 0xfb, 0x0a, 0xfe, 0xfa, 0xf6, 0xf9, + 0xe4, 0xf5, 0xf5, 0xec, 0xdf, 0xf1, 0xe5, 0xea, 0xd9, 0xf3, 0xed, 0xed, + 0xe3, 0xfe, 0xf3, 0xfa, 0xfd, 0xf7, 0x09, 0x09, 0x0b, 0x06, 0x17, 0x0b, + 0x0e, 0x13, 0x0f, 0x0e, 0x14, 0x12, 0x03, 0x17, 0x0e, 0x06, 0x01, 0x0b, + 0xff, 0xea, 0xff, 0xf2, 0xf1, 0xe1, 0xfd, 0xee, 0xea, 0xf1, 0xfb, 0xf0, + 0xe8, 0xff, 0xf5, 0xee, 0xfd, 0x03, 0xf0, 0x05, 0x03, 0x06, 0xff, 0x13, + 0x03, 0x0f, 0x0a, 0x05, 0x13, 0x0a, 0x02, 0x00, 0x00, 0xf7, 0xf9, 0xf9, + 0xf3, 0xdc, 0x03, 0xee, 0xf0, 0xf0, 0xfb, 0xf1, 0xed, 0xfe, 0xf6, 0xfd, + 0xfe, 0xf2, 0x03, 0x03, 0x09, 0xfa, 0x0e, 0x09, 0x0d, 0x05, 0x05, 0x17, + 0x09, 0xff, 0x0e, 0x09, 0xf7, 0x03, 0xfd, 0xfa, 0xee, 0xf9, 0xf2, 0xec, + 0xed, 0xee, 0xe6, 0xdc, 0xfa, 0xe4, 0xea, 0xe0, 0xf7, 0xf3, 0xf6, 0xfd, + 0x06, 0x05, 0x07, 0x00, 0x0a, 0x10, 0x07, 0x07, 0x16, 0x13, 0x0a, 0x14, + 0x18, 0x13, 0x17, 0x1d, 0x0a, 0x09, 0x16, 0x05, 0xf6, 0xff, 0xf6, 0xf3, + 0xe5, 0xea, 0xee, 0xea, 0xec, 0xf0, 0xe3, 0xf1, 0xf2, 0xe8, 0xee, 0xfd, + 0xf7, 0xf9, 0xee, 0xff, 0xfa, 0xf9, 0xf6, 0x01, 0x01, 0xff, 0x0b, 0x0a, + 0x03, 0x05, 0x0f, 0x02, 0x00, 0x09, 0x05, 0x02, 0x01, 0x00, 0x01, 0xf5, + 0xf3, 0x01, 0xf1, 0xf1, 0xfd, 0xfe, 0xf6, 0xfb, 0x06, 0x01, 0x02, 0x01, + 0x0a, 0xff, 0x02, 0x0e, 0x06, 0xff, 0x06, 0x0f, 0xff, 0x00, 0x0e, 0xfd, + 0xfe, 0xff, 0xfe, 0xfd, 0x01, 0xf2, 0xf7, 0xfb, 0xf2, 0xe8, 0xed, 0xea, + 0xee, 0xe9, 0xee, 0xf5, 0xf1, 0xf0, 0xfd, 0xfa, 0xed, 0x0b, 0x03, 0x06, + 0xfe, 0x14, 0x0a, 0x02, 0x10, 0x0a, 0x0a, 0x0b, 0x0a, 0x0a, 0x09, 0x07, + 0xff, 0x0b, 0x03, 0xff, 0xf7, 0x0b, 0xfb, 0xea, 0xff, 0xf0, 0xe1, 0xf0, + 0xe9, 0xf2, 0xe8, 0xf1, 0xf2, 0xed, 0xf5, 0xfd, 0xf6, 0xf7, 0xfe, 0x00, + 0x03, 0xf5, 0x16, 0x07, 0x06, 0xfd, 0x13, 0x09, 0x01, 0x0b, 0x0d, 0x10, + 0x09, 0x01, 0x0f, 0xf9, 0x03, 0xfa, 0xf6, 0x02, 0xf6, 0xfa, 0xf7, 0xfa, + 0xf5, 0xe5, 0x0b, 0xed, 0xfb, 0xf5, 0xf9, 0xfd, 0xfe, 0xfd, 0xff, 0x01, + 0x01, 0x02, 0x03, 0x03, 0x02, 0x02, 0x05, 0xf3, 0x0a, 0xfe, 0xf5, 0x02, + 0xfb, 0xfb, 0xed, 0x05, 0xf6, 0xf3, 0xff, 0xf3, 0xf9, 0xf7, 0xf3, 0xf1, + 0xf5, 0xf3, 0xf2, 0xf7, 0xf9, 0xf6, 0xf2, 0x0f, 0x01, 0xf6, 0x0b, 0x07, + 0x0b, 0x07, 0x02, 0x16, 0x09, 0xff, 0x06, 0x07, 0x07, 0x05, 0xfb, 0x07, + 0xfe, 0x05, 0xfa, 0xed, 0x02, 0xee, 0xf3, 0xf3, 0xec, 0xf2, 0xf2, 0xec, + 0xf5, 0xf3, 0xf5, 0xf3, 0xf9, 0x00, 0xfb, 0xf1, 0x09, 0x01, 0x06, 0xfe, + 0x07, 0x14, 0x09, 0x05, 0x13, 0x0e, 0x07, 0x0a, 0x0b, 0x00, 0x05, 0xff, + 0x00, 0x01, 0xf5, 0xfd, 0xfd, 0xf5, 0xfa, 0xfa, 0xf9, 0xf3, 0xed, 0x00, + 0xf1, 0xe8, 0xf5, 0xf5, 0xf3, 0xf6, 0xfb, 0xf1, 0xff, 0xfe, 0xfb, 0xff, + 0x01, 0x03, 0x01, 0x05, 0x00, 0x02, 0x02, 0xf6, 0x06, 0x03, 0x03, 0x01, + 0x09, 0x03, 0x09, 0xf6, 0xff, 0x01, 0xfb, 0xf0, 0x03, 0xfd, 0xf6, 0x00, + 0xfb, 0xfd, 0xf5, 0x0a, 0xf5, 0xf3, 0x09, 0xf2, 0xf7, 0x00, 0xfb, 0xf0, + 0xff, 0xfb, 0xfe, 0xfd, 0xf7, 0xff, 0x01, 0xf9, 0xfe, 0x01, 0xea, 0x02, + 0xfb, 0xf7, 0xf3, 0xfd, 0xf7, 0xed, 0xfe, 0xfd, 0xfe, 0xf9, 0x01, 0xfb, + 0x02, 0xff, 0xff, 0x06, 0x02, 0x07, 0x09, 0x09, 0x09, 0x07, 0x0b, 0x07, + 0x05, 0x07, 0x06, 0x05, 0x05, 0x05, 0x03, 0xfb, 0x03, 0xfd, 0xfb, 0xf0, + 0x00, 0xf7, 0xff, 0xec, 0xf6, 0xf7, 0xf7, 0xf5, 0xf3, 0x02, 0xfa, 0xf2, + 0xfe, 0xfa, 0xfe, 0xfe, 0xf3, 0x06, 0xfe, 0x02, 0xff, 0xf6, 0x06, 0xfe, + 0xf9, 0x00, 0x06, 0x02, 0x06, 0xfe, 0xff, 0x06, 0x02, 0xf7, 0x01, 0x02, + 0xfe, 0xf1, 0xff, 0xf9, 0xf9, 0xea, 0x00, 0xf7, 0xf0, 0xf9, 0xfb, 0xf9, + 0xf1, 0x03, 0xf9, 0xee, 0x03, 0xfa, 0xfa, 0xf5, 0x03, 0xfb, 0xf2, 0x05, + 0xfe, 0x01, 0xf5, 0x0a, 0x01, 0x03, 0x01, 0x03, 0x05, 0x01, 0x03, 0x05, + 0x03, 0xf3, 0x13, 0xfd, 0xff, 0x06, 0x03, 0x05, 0x00, 0x06, 0x06, 0x06, + 0x05, 0x03, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xee, 0x0a, + 0xfe, 0xfa, 0xfa, 0xfd, 0xfd, 0xf3, 0xf6, 0xff, 0xf6, 0xf3, 0xf3, 0xf5, + 0xec, 0xfe, 0xf6, 0xee, 0xff, 0xf6, 0xf5, 0xed, 0x00, 0xf5, 0xf0, 0xf6, + 0xfa, 0xf7, 0xf6, 0xf9, 0xfe, 0xfe, 0xfa, 0xfb, 0x0d, 0x01, 0xfa, 0x01, + 0x09, 0x02, 0x03, 0x05, 0x05, 0x06, 0x06, 0x02, 0xff, 0x0d, 0x05, 0xfe, + 0x02, 0x01, 0x01, 0xff, 0xf9, 0x03, 0xff, 0xf5, 0xfd, 0x00, 0xfe, 0xf3, + 0x09, 0xff, 0xf7, 0x02, 0xfe, 0xfd, 0xf2, 0x07, 0xfe, 0xf6, 0x02, 0x00, + 0xfa, 0xfa, 0x0a, 0xff, 0xf5, 0x07, 0x00, 0xfd, 0xfa, 0x07, 0xff, 0xf5, + 0x07, 0xff, 0x00, 0xfa, 0x03, 0xff, 0xf6, 0xff, 0xfe, 0xff, 0xf0, 0xfa, + 0xfb, 0xf9, 0xed, 0xff, 0xf6, 0xf7, 0xf9, 0xfe, 0xf9, 0xfd, 0xfb, 0xfe, + 0xe8, 0x05, 0xfb, 0xfd, 0xfb, 0xf3, 0x09, 0xff, 0xf6, 0x06, 0x00, 0x00, + 0xf5, 0x07, 0xfe, 0xfb, 0xff, 0xfe, 0xf5, 0xfd, 0x02, 0xfa, 0xfb, 0x00, + 0x01, 0x03, 0xfa, 0x05, 0x02, 0xfd, 0x00, 0x02, 0xfb, 0xfd, 0x02, 0x01, + 0xff, 0xff, 0x0a, 0xf7, 0x00, 0x0d, 0x03, 0xf9, 0x09, 0x02, 0xff, 0xfd, + 0x06, 0x00, 0xf9, 0xfb, 0x06, 0xf9, 0xfa, 0x01, 0xfb, 0xf2, 0xfb, 0xff, + 0xf5, 0xee, 0x01, 0xf6, 0xec, 0xfd, 0xf6, 0xf7, 0xed, 0xfe, 0xf7, 0xfa, + 0xf9, 0xf9, 0xf9, 0xfa, 0xf9, 0xfa, 0xfd, 0xff, 0xff, 0x02, 0xf5, 0xff, + 0x09, 0xff, 0x02, 0x02, 0xff, 0xfb, 0xff, 0xff, 0x00, 0xfd, 0xff, 0x09, + 0xf3, 0x03, 0x01, 0x03, 0xf3, 0x06, 0x01, 0xfe, 0xfb, 0x0a, 0xfd, 0x02, + 0x09, 0x02, 0xfe, 0x02, 0x03, 0x03, 0x02, 0xfa, 0x0a, 0xfb, 0xfa, 0xfd, + 0x02, 0xf7, 0xf6, 0x05, 0xfa, 0xf0, 0x00, 0xfa, 0xfb, 0xf0, 0x02, 0xfa, + 0xfd, 0xf3, 0xff, 0xfe, 0xfe, 0xf5, 0x02, 0xfe, 0xfe, 0xfe, 0x02, 0xff, + 0xff, 0x02, 0xfe, 0xf6, 0x0e, 0x00, 0xf7, 0x02, 0x01, 0xfa, 0xf3, 0x01, + 0xfa, 0xf9, 0xf3, 0xfe, 0xf3, 0xf1, 0x01, 0xf1, 0xf3, 0xfa, 0xf7, 0xf3, + 0xf2, 0x05, 0xf2, 0xf0, 0x06, 0xfe, 0xff, 0xfe, 0x02, 0x05, 0x06, 0x02, + 0x0f, 0x09, 0x0a, 0x07, 0x0b, 0x0b, 0x0a, 0x0d, 0x09, 0x01, 0x14, 0x07, + 0xff, 0x07, 0x02, 0x00, 0xf3, 0xff, 0xfa, 0xfa, 0xf5, 0xf7, 0xf7, 0xf6, + 0xf6, 0xf6, 0xf6, 0xf6, 0xf7, 0xf9, 0xfa, 0xe9, 0x01, 0xfb, 0xfb, 0xf6, + 0x01, 0xfb, 0xfb, 0xfd, 0xfe, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xf7, 0xff, 0xff, 0xff, 0xf3, 0x02, 0xfd, 0xf7, 0xfe, 0xfd, 0x02, 0xf5, + 0xfd, 0x00, 0xfe, 0xf3, 0x01, 0x00, 0x00, 0xf5, 0x09, 0x01, 0xff, 0x02, + 0x05, 0xf5, 0x07, 0x02, 0x02, 0xfa, 0x09, 0x00, 0xfa, 0xff, 0xff, 0xfe, + 0xfd, 0xfd, 0xfa, 0xfb, 0xfb, 0xf9, 0xed, 0xff, 0xf2, 0xf6, 0xf6, 0xf5, + 0xff, 0xfb, 0xfd, 0xff, 0xff, 0xff, 0x00, 0xfd, 0x09, 0x03, 0x05, 0x02, + 0x0b, 0xfd, 0x06, 0x02, 0x02, 0x03, 0x02, 0x02, 0xfe, 0x00, 0xff, 0xf9, + 0xf7, 0xff, 0xf7, 0xf1, 0xf3, 0xf7, 0xf5, 0xec, 0xf5, 0xfb, 0xf0, 0xf7, + 0xf7, 0xf9, 0xfa, 0xfb, 0xfd, 0xf7, 0xfe, 0x03, 0xff, 0xfe, 0x03, 0x05, + 0x06, 0x07, 0x0a, 0x0a, 0x0a, 0x09, 0xff, 0x09, 0x03, 0x02, 0x02, 0x01, + 0x00, 0x00, 0x03, 0xf3, 0x02, 0xff, 0xfe, 0xf5, 0x02, 0xfd, 0xf7, 0x00, + 0xfa, 0xff, 0xf9, 0xfb, 0x00, 0xf7, 0xfe, 0xff, 0xff, 0xf3, 0x09, 0xfe, + 0xf6, 0x00, 0xfd, 0xfb, 0xf0, 0x05, 0xf9, 0xf1, 0xfd, 0xf6, 0xff, 0xf0, + 0xf6, 0xf9, 0xf5, 0xf5, 0xf6, 0xf6, 0xf7, 0xf9, 0xfb, 0xfd, 0xfb, 0xfb, + 0x07, 0xfb, 0x02, 0x07, 0x07, 0x03, 0x09, 0x0a, 0x0a, 0x03, 0x09, 0x09, + 0x09, 0x06, 0x02, 0x03, 0x02, 0x01, 0x00, 0xfd, 0xed, 0x02, 0xf3, 0xf9, + 0xec, 0xf7, 0xf6, 0xed, 0xf6, 0xf6, 0xf5, 0xea, 0x01, 0xf5, 0xf3, 0xff, + 0xf7, 0xfb, 0xfe, 0x00, 0xf9, 0x03, 0x07, 0x05, 0x01, 0x0a, 0x09, 0x09, + 0x09, 0x0a, 0x0d, 0x03, 0x01, 0x05, 0x01, 0xfb, 0xf9, 0x07, 0xfa, 0xf9, + 0xff, 0xfb, 0xf5, 0xf9, 0xfd, 0xee, 0xf6, 0xfe, 0xf7, 0xee, 0xf7, 0xfa, + 0xf7, 0xf3, 0x05, 0xf7, 0xf3, 0x06, 0xf3, 0xfe, 0xfe, 0xff, 0x00, 0xfd, + 0xf7, 0x0a, 0xf9, 0xff, 0xfa, 0xfe, 0x00, 0xfe, 0xfb, 0xfd, 0xfe, 0xfe, + 0xfd, 0xf7, 0x00, 0xfe, 0xff, 0xf7, 0x05, 0x02, 0xfe, 0x05, 0x06, 0x06, + 0x01, 0x03, 0x0d, 0x07, 0xfd, 0x07, 0x07, 0x06, 0xfa, 0x06, 0x03, 0xfd, + 0x00, 0x01, 0xfe, 0xf3, 0x02, 0xf7, 0xed, 0xfb, 0xf5, 0xf1, 0xed, 0xf9, + 0xf2, 0xe9, 0xf6, 0xf3, 0xf9, 0xf6, 0xed, 0x03, 0xf7, 0xfd, 0xfe, 0x03, + 0xff, 0x02, 0x03, 0x05, 0x03, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x07, + 0xf9, 0x14, 0xfd, 0xff, 0x02, 0xfe, 0xf2, 0x02, 0xfa, 0xf9, 0xec, 0x02, + 0xf1, 0xec, 0xfb, 0xf5, 0xf5, 0xf0, 0xfe, 0xf3, 0xee, 0xfe, 0xfa, 0xfe, + 0xf3, 0x07, 0x00, 0xfd, 0x06, 0x03, 0x00, 0x00, 0x09, 0x03, 0xfa, 0x0a, + 0x02, 0x03, 0xf7, 0x07, 0x00, 0x01, 0xfa, 0xff, 0x02, 0xfe, 0xfe, 0xf5, + 0x05, 0xfd, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0x00, 0xf6, 0x03, 0x00, 0x00, + 0xfe, 0x00, 0x00, 0xfd, 0xff, 0xff, 0xfd, 0xf3, 0xfd, 0xff, 0xf3, 0xfb, + 0xfb, 0xfa, 0xf1, 0x02, 0xf3, 0xee, 0xfb, 0xf5, 0xf5, 0xf2, 0xff, 0xf6, + 0xf0, 0xff, 0xfa, 0x00, 0xf5, 0x05, 0x03, 0x03, 0xfe, 0x0e, 0x09, 0x03, + 0x0a, 0x10, 0x00, 0x0b, 0x0a, 0x0d, 0xfe, 0x0a, 0x06, 0x06, 0xf9, 0x07, + 0xff, 0xfe, 0xf1, 0x03, 0xf5, 0xf7, 0xf5, 0xf5, 0xf3, 0xf3, 0xf5, 0xf6, + 0xe5, 0xf9, 0xf5, 0xf2, 0xf3, 0xfe, 0xf7, 0xf3, 0x03, 0xff, 0x01, 0x01, + 0x03, 0x05, 0x03, 0xfa, 0x0a, 0x03, 0x05, 0x03, 0x02, 0xff, 0x05, 0x01, + 0xf7, 0x0d, 0x00, 0x00, 0xfd, 0x01, 0xfd, 0xff, 0xf5, 0xf6, 0x00, 0xfb, + 0xf9, 0xf7, 0x05, 0xfa, 0xfd, 0xfe, 0xfd, 0xfa, 0x00, 0xfe, 0xf5, 0x00, + 0xfe, 0xfe, 0xf2, 0x02, 0xfe, 0xfb, 0xfe, 0xff, 0xfe, 0xf7, 0x02, 0xfd, + 0xf5, 0x01, 0xfd, 0xfb, 0xf0, 0x01, 0xfb, 0xfe, 0xf6, 0x02, 0x00, 0x01, + 0xfe, 0x01, 0x03, 0x02, 0x03, 0x07, 0x00, 0x05, 0x09, 0x05, 0x05, 0x05, + 0x07, 0xfa, 0x06, 0x06, 0xff, 0xf9, 0x05, 0xff, 0xf9, 0xf5, 0xfe, 0xf7, + 0xf6, 0xf0, 0xfe, 0xf5, 0xf0, 0xf5, 0xf9, 0xf2, 0xf5, 0xfb, 0xec, 0xf9, + 0xfd, 0xfb, 0xf2, 0x06, 0xff, 0xfd, 0xfe, 0x07, 0x03, 0xfd, 0x05, 0x05, + 0x03, 0xfe, 0x06, 0x02, 0x02, 0x01, 0x01, 0xff, 0xff, 0xfe, 0xfe, 0xfd, + 0xfd, 0xfd, 0xfd, 0xfe, 0xf2, 0xfd, 0xff, 0xfd, 0xf6, 0x01, 0xf5, 0x00, + 0xfe, 0xfe, 0xf7, 0xfd, 0x00, 0xfe, 0xfe, 0xf9, 0x07, 0xfe, 0x01, 0x03, + 0x03, 0xfe, 0xff, 0x0a, 0xff, 0xf9, 0x0a, 0xf9, 0xfd, 0xfd, 0xfa, 0xfa, + 0xfa, 0xfb, 0xfa, 0xf0, 0x0b, 0xf6, 0xf6, 0x01, 0xfd, 0xfb, 0xf9, 0x00, + 0xfd, 0xfd, 0xfe, 0xff, 0xfe, 0xff, 0x01, 0x01, 0xfe, 0x00, 0x06, 0x00, + 0xf7, 0x02, 0xff, 0xff, 0xf6, 0x05, 0xfe, 0xf8, 0x00, 0xfc, 0x00, 0xf4, + 0x00, 0x00, 0xf7, 0xff, 0x00, 0xff, 0xfc, 0x01, 0x00, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x01, 0xfc, 0x09, 0x00, + 0x01, 0x00, 0xf7, 0x06, 0xfc, 0x00, 0xf9, 0xfe, 0xfe, 0xfb, 0xfb, 0xf9, + 0xfb, 0xfb, 0xf7, 0xf9, 0xfb, 0xfb, 0xf9, 0xf8, 0x00, 0xf5, 0xfc, 0xfc, + 0xff, 0xf8, 0x00, 0x00, 0xfc, 0x00, 0x01, 0x00, 0xf8, 0x04, 0x00, 0x00, + 0xfd, 0x01, 0x00, 0x00, 0xfc, 0x03, 0xfe, 0xfd, 0x00, 0xff, 0xfc, 0xfe, + 0x00, 0xfe, 0xf9, 0x05, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0x00, 0xf7, 0x02, + 0x00, 0xfe, 0x00, 0x01, 0x00, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0xfc, + 0x01, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfd, 0x03, + 0xff, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, + 0xfa, 0x03, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, + 0xfb, 0xff, 0xfc, 0xfc, 0xfd, 0xfc, 0xfd, 0xfc, 0xfd, 0xfd, 0xf9, 0x00, + 0xfc, 0xfe, 0xfb, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x01, + 0x01, 0x01, 0x02, 0x02, 0x00, 0x05, 0x00, 0xfe, 0x05, 0x00, 0xff, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x01, 0xfe, 0xff, 0xff, 0x00, + 0xfd, 0xfd, 0x00, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfd, 0x01, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfe, 0x00, + 0x00, 0x00, 0xfe, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xf8, 0xfc, 0x06, + 0x25, 0x29, 0x21, 0xe6, 0xcb, 0x1b, 0x37, 0x30, 0x07, 0x01, 0xc7, 0x02, + 0x08, 0xe2, 0x07, 0xdf, 0x48, 0x3e, 0xf7, 0xb2, 0x09, 0x2e, 0x5e, 0x5d, + 0x0e, 0xff, 0xd8, 0x07, 0xd8, 0x0d, 0xe3, 0x06, 0xbb, 0xee, 0x52, 0x5d, + 0x01, 0xce, 0xfa, 0x31, 0x11, 0x7a, 0x54, 0x1f, 0x05, 0x0e, 0x1e, 0x18, + 0x12, 0xc7, 0xaf, 0xb1, 0xb0, 0xb5, 0xd4, 0xb7, 0xb3, 0xc2, 0xc7, 0xe1, + 0xc9, 0xc2, 0xc3, 0x10, 0x18, 0x13, 0xe5, 0xe4, 0xc9, 0xf0, 0xee, 0xf2, + 0xd0, 0x9f, 0xc9, 0xff, 0xe8, 0x0f, 0xf7, 0xe2, 0x03, 0x06, 0xfb, 0xfa, + 0x25, 0x29, 0xf3, 0xa5, 0xc6, 0xc7, 0x28, 0xdb, 0xcd, 0xea, 0xe3, 0xdb, + 0xe7, 0xc0, 0x9f, 0xe4, 0xcd, 0xf3, 0xef, 0xc4, 0xf8, 0xdb, 0x28, 0x1c, + 0x1e, 0x2a, 0x3c, 0x40, 0x12, 0x10, 0x32, 0x14, 0xed, 0xfa, 0xbe, 0xd7, + 0xf0, 0xf9, 0xd4, 0xed, 0xe8, 0x0e, 0x1a, 0x29, 0xf4, 0x21, 0x43, 0x2c, + 0x54, 0x45, 0x25, 0x01, 0xef, 0xff, 0x10, 0xf7, 0xfe, 0x1a, 0x55, 0x60, + 0x43, 0x70, 0x51, 0x5d, 0x26, 0x5e, 0x4e, 0x3e, 0x3e, 0x05, 0x00, 0x27, + 0x4d, 0x6a, 0x29, 0x05, 0xf2, 0x04, 0xf1, 0x58, 0x42, 0x4b, 0x49, 0x2c, + 0x2a, 0x27, 0x35, 0x2e, 0x48, 0x09, 0x10, 0x1b, 0xe5, 0xef, 0xc7, 0xc7, + 0xf8, 0x16, 0x11, 0x2c, 0x32, 0x4d, 0x3c, 0x42, 0x5b, 0x3d, 0x45, 0x09, + 0xdf, 0xd8, 0xef, 0xcb, 0xc4, 0xf4, 0x08, 0x07, 0xf1, 0xdc, 0xd0, 0xd8, + 0xf0, 0xfc, 0xdb, 0xde, 0xd8, 0xf1, 0x40, 0x30, 0xde, 0xea, 0xe8, 0xc7, + 0xb2, 0xcd, 0xbc, 0xdf, 0xd0, 0xed, 0xfc, 0xde, 0xd9, 0xbc, 0xcf, 0xe4, + 0xfd, 0xf7, 0xe3, 0xec, 0xd3, 0xd6, 0xcf, 0xcf, 0xc0, 0xa8, 0xb3, 0xb2, + 0xd8, 0xf1, 0x09, 0x10, 0x0f, 0x11, 0x0d, 0xf8, 0xda, 0xed, 0xdc, 0xf1, + 0xf0, 0x0d, 0xff, 0xe3, 0xea, 0xcf, 0xc4, 0xd3, 0xd4, 0xcd, 0xd6, 0xbe, + 0xf7, 0xf8, 0x03, 0xfa, 0xef, 0xc8, 0xc0, 0xc6, 0xd0, 0xd0, 0xd9, 0xde, + 0xf2, 0x1d, 0x1e, 0x2a, 0x1f, 0x08, 0x03, 0xe4, 0xbb, 0xb7, 0xbe, 0xc3, + 0xe1, 0xf9, 0xf7, 0xe3, 0xd0, 0xc8, 0xcd, 0xcd, 0xde, 0xf0, 0x0c, 0x27, + 0x32, 0x30, 0x25, 0x0d, 0x18, 0x26, 0x43, 0x3e, 0x34, 0x1e, 0x19, 0xff, + 0x07, 0x12, 0xfc, 0xf2, 0xf7, 0x04, 0xfa, 0xfd, 0xfa, 0x18, 0x0d, 0x12, + 0x07, 0x11, 0x1b, 0x2a, 0x31, 0x31, 0x30, 0x27, 0x18, 0x1a, 0xfb, 0x0d, + 0x26, 0x45, 0x3c, 0x38, 0x26, 0x06, 0xfa, 0xf2, 0xe8, 0xdc, 0xf1, 0xfc, + 0x09, 0x13, 0x1b, 0x31, 0x55, 0x5a, 0x5e, 0x43, 0x29, 0x1c, 0x1c, 0x10, + 0x16, 0x1c, 0x22, 0x1b, 0x22, 0x0c, 0x1e, 0x01, 0xf2, 0xf1, 0xf9, 0xf2, + 0xfe, 0x16, 0x21, 0x1c, 0x43, 0x46, 0x44, 0x46, 0x27, 0xfd, 0xe1, 0xe5, + 0xfb, 0x07, 0x1e, 0x25, 0x1e, 0x22, 0xfe, 0xe2, 0xe5, 0xff, 0xef, 0xed, + 0x06, 0x22, 0x28, 0x3a, 0x34, 0x24, 0x12, 0xf4, 0xda, 0xd7, 0xd0, 0xdc, + 0xef, 0xea, 0x0d, 0x0c, 0x08, 0x1c, 0x16, 0xfc, 0xf8, 0xf9, 0x0d, 0x26, + 0x26, 0x32, 0x33, 0x32, 0x16, 0xf0, 0xd8, 0xde, 0xdf, 0xbe, 0xb7, 0xc9, + 0xcc, 0xd6, 0xd4, 0xd4, 0xe5, 0xf0, 0xf9, 0xf8, 0xf9, 0xf9, 0xe8, 0xe7, + 0xf2, 0xff, 0xfc, 0xf1, 0xea, 0xe6, 0xdb, 0xe1, 0xf1, 0xf8, 0xf0, 0x01, + 0x01, 0xf2, 0xf3, 0xfc, 0xef, 0xef, 0xf2, 0xf7, 0xe7, 0xc7, 0xcc, 0xd6, + 0xbc, 0xc2, 0xcb, 0xc8, 0xba, 0xd4, 0xf9, 0xf7, 0xee, 0xff, 0xf8, 0xf0, + 0xe2, 0xd9, 0xcf, 0xbc, 0xd9, 0xec, 0xec, 0xdc, 0xda, 0xc3, 0xd2, 0xfb, + 0xef, 0xf2, 0xff, 0x02, 0x09, 0xf8, 0xe7, 0xdb, 0xdc, 0xe4, 0xf2, 0xf7, + 0xed, 0xed, 0xde, 0xd8, 0xf0, 0xf4, 0xfd, 0xfa, 0xf0, 0xf8, 0xf7, 0xea, + 0xee, 0xe6, 0xd8, 0xdb, 0xe2, 0xdc, 0xd7, 0xd6, 0xe6, 0xf3, 0xfa, 0x08, + 0xfc, 0xfe, 0x10, 0x27, 0x37, 0x3d, 0x35, 0x09, 0xf8, 0x18, 0x12, 0xfa, + 0xf8, 0x03, 0xfc, 0xfc, 0xf7, 0xf2, 0xfb, 0x07, 0x13, 0x16, 0x13, 0x08, + 0x0c, 0x19, 0x10, 0x0d, 0x0e, 0x09, 0x1b, 0x1b, 0x18, 0x13, 0x0d, 0x13, + 0x1f, 0x1a, 0x1a, 0x1b, 0x1f, 0x0d, 0xfd, 0x27, 0x2c, 0x2d, 0x33, 0x1a, + 0x05, 0x08, 0x16, 0x1f, 0x18, 0x19, 0x1b, 0x0c, 0xfd, 0x06, 0x01, 0x14, + 0x18, 0x1b, 0x27, 0x2d, 0x1b, 0x12, 0x1b, 0x1d, 0x1c, 0x25, 0x28, 0x2d, + 0x21, 0x0e, 0x0f, 0x0c, 0x10, 0x0f, 0x09, 0x10, 0x1e, 0x22, 0x13, 0x12, + 0x22, 0x10, 0x03, 0x0f, 0x26, 0x32, 0x34, 0x44, 0x3d, 0x28, 0x1d, 0x0d, + 0x02, 0x06, 0x08, 0x07, 0xfc, 0x02, 0x09, 0x0f, 0x00, 0x00, 0x00, 0x02, + 0x01, 0xfb, 0x05, 0x18, 0x11, 0x18, 0x34, 0x11, 0xfc, 0xec, 0xe5, 0xde, + 0xd3, 0xed, 0xfd, 0x01, 0x12, 0x11, 0x04, 0x0d, 0xfd, 0xe7, 0xf1, 0xdf, + 0xf7, 0x03, 0x11, 0x26, 0x2a, 0x16, 0x0c, 0x16, 0x0e, 0xfa, 0xf9, 0xf7, + 0xf1, 0xfc, 0xfb, 0x02, 0xfa, 0xfc, 0x00, 0xf9, 0xf8, 0xfa, 0xfb, 0xff, + 0x07, 0x0d, 0xf8, 0xf8, 0xfb, 0xf0, 0xe7, 0xf4, 0xf7, 0xf3, 0xf2, 0xde, + 0xd7, 0xe8, 0xe2, 0xd9, 0xe5, 0xf4, 0xfa, 0xee, 0xe6, 0xe6, 0xef, 0xfa, + 0xfa, 0xfc, 0xfd, 0xee, 0xdc, 0xe5, 0xf9, 0xfc, 0xf8, 0xee, 0xed, 0xed, + 0xf1, 0xe4, 0xd7, 0xdb, 0xdb, 0xdf, 0xe6, 0xf1, 0xf9, 0xf3, 0xf8, 0xef, + 0xe7, 0xf2, 0xe4, 0xd4, 0xe3, 0xfa, 0xfb, 0x02, 0x04, 0xef, 0xe4, 0xec, + 0xf3, 0xf4, 0xec, 0xf4, 0xe7, 0xf8, 0x00, 0x09, 0x07, 0x00, 0xfe, 0xfa, + 0xfa, 0xf2, 0xe4, 0xec, 0xef, 0xf1, 0xed, 0xfa, 0xf9, 0xf9, 0xf3, 0xf9, + 0x00, 0xe4, 0xd4, 0xf1, 0x04, 0x00, 0xf3, 0xfe, 0xf9, 0xea, 0xe3, 0xe4, + 0x01, 0xf4, 0xe6, 0xf2, 0xfd, 0x03, 0xfd, 0xec, 0xec, 0xf4, 0xfc, 0xfc, + 0xfd, 0xfc, 0x00, 0x01, 0xf9, 0xfe, 0xf9, 0xe5, 0xe7, 0xea, 0xe8, 0xf8, + 0x00, 0x04, 0x0d, 0x01, 0x04, 0xf9, 0xf1, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x08, 0xff, 0xfc, 0x03, 0xf4, 0x02, 0x01, 0xe7, 0xed, 0x03, + 0x08, 0x03, 0x16, 0x24, 0x0f, 0xfb, 0x07, 0x0d, 0xf1, 0x03, 0x02, 0xed, + 0x07, 0x1d, 0x0e, 0x09, 0x01, 0xee, 0xfb, 0x08, 0x0f, 0x06, 0xfc, 0x05, + 0x03, 0x02, 0x0c, 0x14, 0x02, 0xf4, 0xf9, 0x01, 0x05, 0xfd, 0xf2, 0x0e, + 0x08, 0x05, 0x08, 0x03, 0xf8, 0xf9, 0xfb, 0xfd, 0x0e, 0x0e, 0xff, 0x02, + 0x04, 0x05, 0x26, 0x35, 0x2c, 0x1f, 0x16, 0x09, 0xf2, 0xfd, 0x03, 0xfa, + 0xfd, 0x02, 0xf1, 0xe8, 0xef, 0xf3, 0xf4, 0xf4, 0x06, 0x12, 0x16, 0x02, + 0x09, 0x18, 0x1b, 0x1b, 0x1f, 0x27, 0x1f, 0xff, 0xf3, 0x04, 0x00, 0xf7, + 0xf7, 0x0e, 0x1b, 0x06, 0x07, 0xff, 0xfc, 0x19, 0x1d, 0x11, 0x1b, 0x18, + 0xff, 0x03, 0x13, 0x0d, 0x0e, 0x09, 0xff, 0x00, 0x09, 0xff, 0xee, 0xfb, + 0x07, 0x0e, 0x09, 0x03, 0x14, 0x13, 0x1b, 0x10, 0x07, 0x0d, 0x16, 0x04, + 0xf2, 0x06, 0x1a, 0x10, 0x0f, 0x18, 0x09, 0x03, 0x11, 0x13, 0x13, 0x13, + 0x22, 0x27, 0x1d, 0x13, 0x0f, 0x16, 0x14, 0xfd, 0xf0, 0x03, 0x09, 0x02, + 0xf7, 0x07, 0x13, 0x1a, 0x14, 0x08, 0x08, 0x14, 0x16, 0x13, 0x18, 0x13, + 0x05, 0xf4, 0xf8, 0x06, 0x04, 0xfc, 0x01, 0x0e, 0x09, 0x03, 0x02, 0x04, + 0x16, 0x09, 0xfd, 0x08, 0x00, 0x07, 0x05, 0xfb, 0xf7, 0xfb, 0xf1, 0xe1, + 0xea, 0xf1, 0xed, 0x06, 0x0c, 0x08, 0x08, 0x02, 0x0c, 0x05, 0x01, 0x09, + 0x04, 0xf3, 0xf4, 0xfc, 0xfe, 0xff, 0xf3, 0xea, 0xe6, 0xe3, 0xd9, 0xd9, + 0xe6, 0xe7, 0xea, 0xfa, 0x07, 0x00, 0xf3, 0xf8, 0xf9, 0xe8, 0xd9, 0xdb, + 0xe6, 0xe8, 0xe4, 0xed, 0xf7, 0xf2, 0xf8, 0xf0, 0xe3, 0xea, 0xea, 0xdf, + 0xf4, 0xfd, 0xf4, 0xff, 0xf8, 0xef, 0xf0, 0xef, 0xea, 0xe6, 0xe3, 0xe2, + 0xe4, 0xe8, 0xe1, 0xd9, 0xec, 0xf2, 0xf9, 0xfa, 0xf9, 0xfb, 0x09, 0x08, + 0xfa, 0xfa, 0xfa, 0xea, 0xee, 0xfa, 0xec, 0xd9, 0xe1, 0xde, 0xde, 0xdf, + 0xee, 0xff, 0xf7, 0xf7, 0xfd, 0xfb, 0x07, 0x09, 0xf3, 0xea, 0xf9, 0xfc, + 0xef, 0xf1, 0xe7, 0xf3, 0xf1, 0xec, 0xfa, 0xf4, 0xe5, 0xf0, 0xf9, 0xfd, + 0xf9, 0xf3, 0xfd, 0x00, 0xf8, 0xf1, 0xf7, 0xef, 0xe7, 0xdf, 0xdc, 0xe3, + 0xea, 0xec, 0xef, 0xef, 0xf4, 0xff, 0x0d, 0x19, 0x07, 0xfc, 0xfe, 0x09, + 0x0f, 0x07, 0x03, 0x03, 0x06, 0xfb, 0xe2, 0xf3, 0xe8, 0xdf, 0xef, 0xf0, + 0xf8, 0xfd, 0xff, 0x08, 0x14, 0x16, 0x06, 0x04, 0x0d, 0x02, 0xf4, 0xfa, + 0xfe, 0x03, 0x00, 0xf1, 0xf9, 0x01, 0xff, 0xf8, 0xf3, 0x00, 0x12, 0x13, + 0x07, 0x19, 0x10, 0x0c, 0x05, 0x10, 0x05, 0x01, 0x01, 0x00, 0xff, 0x00, + 0x05, 0x11, 0x0d, 0x03, 0x03, 0x08, 0x00, 0xf3, 0xf0, 0x00, 0xfe, 0xf7, + 0x07, 0x16, 0x13, 0x11, 0x07, 0x02, 0x0c, 0xfd, 0xf2, 0xfd, 0x04, 0x01, + 0x06, 0x05, 0x07, 0x09, 0x09, 0x14, 0x1f, 0x19, 0x10, 0x13, 0x1a, 0x22, + 0x1b, 0x19, 0x14, 0x0e, 0x0d, 0x0f, 0x0e, 0x0d, 0x08, 0x01, 0x00, 0x00, + 0xf9, 0x01, 0x0d, 0x0e, 0x13, 0x13, 0x0c, 0x0d, 0x0f, 0x0e, 0x12, 0x19, + 0x1a, 0x18, 0x1c, 0x24, 0x14, 0xfd, 0x05, 0x1c, 0x11, 0x05, 0x0c, 0x0c, + 0x06, 0x06, 0x03, 0x04, 0x02, 0x09, 0x16, 0x1a, 0x1d, 0x1f, 0x10, 0x06, + 0x07, 0x08, 0x04, 0xfd, 0xfb, 0x03, 0x0c, 0x12, 0x0d, 0xfe, 0x03, 0x11, + 0x1a, 0x16, 0x0d, 0x0c, 0x16, 0x12, 0x0d, 0x11, 0x0f, 0x0e, 0x13, 0x10, + 0x0d, 0x0c, 0x05, 0x00, 0x03, 0x00, 0x04, 0x13, 0x14, 0x11, 0x13, 0x0d, + 0x08, 0x08, 0x12, 0x05, 0x05, 0x11, 0x00, 0xfb, 0x02, 0x03, 0x05, 0x05, + 0x03, 0x03, 0x04, 0x02, 0xfe, 0xfe, 0xff, 0x09, 0x07, 0x04, 0x08, 0xff, + 0xfc, 0x02, 0x03, 0x08, 0x0c, 0xfa, 0xfa, 0xfe, 0xf1, 0xfe, 0xf0, 0xfd, + 0x05, 0xfa, 0xef, 0xf8, 0x04, 0x03, 0xfa, 0xff, 0x0e, 0x06, 0xfe, 0x07, + 0x03, 0xfb, 0xfb, 0x04, 0x03, 0xf8, 0xed, 0xea, 0xf9, 0xfe, 0xfc, 0xfb, + 0xf3, 0xff, 0x0c, 0xf9, 0xf8, 0xfb, 0xfe, 0xfc, 0xf4, 0xf8, 0x04, 0x02, + 0xfb, 0xfd, 0xee, 0xea, 0xf1, 0xe8, 0xe1, 0xed, 0xfa, 0xf1, 0xf2, 0xfb, + 0xfb, 0xfb, 0x00, 0xfb, 0xf0, 0xf4, 0xfb, 0xf8, 0xf4, 0xea, 0xe4, 0xea, + 0xef, 0xee, 0xed, 0xf4, 0xfc, 0xf4, 0xe7, 0xef, 0xfa, 0xf9, 0xf8, 0xfe, + 0x09, 0x01, 0xfa, 0xf7, 0xef, 0xe4, 0xe2, 0xe6, 0xe6, 0xf2, 0xf9, 0xea, + 0xfb, 0xfe, 0xf0, 0xf1, 0xf2, 0xf8, 0xf9, 0xf3, 0xef, 0xf1, 0xf2, 0xf2, + 0xfb, 0x00, 0xf2, 0xee, 0xed, 0xdc, 0xdc, 0xe5, 0xed, 0xee, 0xe4, 0xe4, + 0xee, 0xee, 0xe8, 0xf1, 0xf0, 0xe5, 0xe4, 0xe5, 0xe6, 0xe1, 0xed, 0xfa, + 0xfc, 0xfc, 0xfb, 0xf2, 0xee, 0xf0, 0xf2, 0xf1, 0xf4, 0xf3, 0xee, 0xea, + 0xe1, 0xdc, 0xe8, 0xea, 0xea, 0xf1, 0xf2, 0xec, 0xef, 0xfc, 0xfd, 0xff, + 0xff, 0x02, 0x01, 0xf2, 0xfa, 0xf4, 0xf3, 0xf2, 0xf1, 0xee, 0xea, 0xea, + 0xf0, 0xf2, 0xf7, 0xf9, 0xef, 0xf0, 0xee, 0xea, 0xf4, 0xfc, 0x03, 0x06, + 0x03, 0xfe, 0xfc, 0xfa, 0xf1, 0xec, 0xf2, 0xf2, 0xf7, 0xf4, 0xf7, 0xfe, + 0xff, 0xfb, 0xfe, 0x05, 0xfb, 0xfc, 0x07, 0x06, 0x09, 0x01, 0x04, 0x03, + 0xfc, 0xfc, 0xff, 0x00, 0xf8, 0xf2, 0xee, 0xed, 0xf1, 0xf3, 0xfe, 0x03, + 0x07, 0x0e, 0x0e, 0x0d, 0x0e, 0x05, 0x08, 0x19, 0x11, 0x02, 0x01, 0x00, + 0xfc, 0xfd, 0x07, 0x0c, 0xf9, 0xff, 0x03, 0x04, 0x08, 0x07, 0x06, 0x0f, + 0x16, 0x18, 0x16, 0x12, 0x03, 0xfe, 0xff, 0x00, 0xfe, 0xf7, 0xfa, 0x00, + 0xfe, 0x00, 0x05, 0x08, 0x0e, 0x0c, 0x0f, 0x0f, 0x04, 0x08, 0x13, 0x19, + 0x0d, 0x0c, 0x0c, 0x0c, 0x09, 0x10, 0x0e, 0x06, 0x0f, 0x12, 0x09, 0x04, + 0x10, 0x14, 0x0d, 0x0c, 0x0e, 0x01, 0x08, 0x19, 0x0d, 0x06, 0x19, 0x14, + 0x0d, 0x05, 0x10, 0x13, 0x19, 0x16, 0x0f, 0x0f, 0x10, 0x10, 0x07, 0x06, + 0x10, 0x0e, 0x06, 0x0c, 0x0f, 0x07, 0x0e, 0x0d, 0x07, 0x14, 0x16, 0x0f, + 0x10, 0x11, 0x10, 0x10, 0x0e, 0x07, 0x07, 0x0d, 0x11, 0x07, 0x0c, 0x09, + 0x05, 0x0d, 0x14, 0x1a, 0x1c, 0x18, 0x11, 0x10, 0x11, 0x19, 0x1f, 0x19, + 0x10, 0x0c, 0x09, 0x0f, 0x10, 0x10, 0x0f, 0x0d, 0x08, 0x0d, 0x18, 0x10, + 0x10, 0x13, 0x12, 0x10, 0x13, 0x12, 0x13, 0x16, 0x09, 0x05, 0x04, 0x01, + 0x05, 0x05, 0x01, 0x00, 0x05, 0x01, 0xf9, 0x01, 0x03, 0x08, 0x06, 0x00, + 0xff, 0x00, 0x00, 0x03, 0x03, 0x04, 0x09, 0x01, 0xfd, 0xf1, 0xf8, 0xfc, + 0xf7, 0xff, 0xff, 0xf9, 0xfd, 0x02, 0xfb, 0xf3, 0xfd, 0x01, 0xfe, 0x01, + 0xff, 0xfb, 0xfb, 0xfc, 0xff, 0xfa, 0xff, 0x03, 0xfc, 0xf8, 0xfa, 0xf7, + 0xf2, 0xfc, 0xfb, 0xf1, 0xf8, 0xee, 0xee, 0xf2, 0xf1, 0xec, 0xf1, 0xf3, + 0xf7, 0xfe, 0xfe, 0xf8, 0xf2, 0xef, 0xfd, 0xfe, 0xf2, 0xf1, 0xef, 0xf0, + 0xf1, 0xed, 0xee, 0xec, 0xf2, 0xf2, 0xe5, 0xee, 0xf8, 0xf1, 0xed, 0xee, + 0xf1, 0xef, 0xf0, 0xfb, 0xfb, 0xf4, 0xf2, 0xee, 0xf1, 0xf2, 0xe8, 0xed, + 0xf1, 0xe8, 0xee, 0xf3, 0xea, 0xf1, 0xfd, 0xf8, 0xf3, 0xf8, 0xf8, 0xfa, + 0xee, 0xf0, 0xef, 0xf0, 0xee, 0xef, 0xf2, 0xf2, 0xed, 0xef, 0xee, 0xed, + 0xf2, 0xf8, 0xee, 0xf0, 0xf3, 0xf1, 0xfa, 0xf9, 0xf9, 0xfb, 0xfc, 0xf4, + 0xf2, 0xf7, 0xfb, 0xfd, 0xf8, 0xf4, 0xf9, 0x00, 0x03, 0x02, 0xfe, 0xf8, + 0xf7, 0xfc, 0x00, 0x02, 0x05, 0x05, 0x05, 0xfe, 0xfd, 0xfc, 0xfe, 0x03, + 0x05, 0x07, 0xff, 0xf9, 0xfa, 0xff, 0x01, 0x01, 0x00, 0xfc, 0xfd, 0x04, + 0x09, 0x04, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfb, 0xfc, 0x04, 0x06, 0x01, + 0x02, 0x05, 0x03, 0x08, 0x08, 0x08, 0x01, 0xfb, 0xfb, 0xfd, 0xfd, 0xf8, + 0xf8, 0xfe, 0xfb, 0xfd, 0x07, 0x05, 0xfd, 0x00, 0x03, 0x05, 0x05, 0x08, + 0x03, 0x03, 0x08, 0x06, 0x06, 0x05, 0x00, 0x01, 0x04, 0x08, 0x0d, 0x0e, + 0x06, 0x00, 0xfe, 0x02, 0x02, 0x03, 0x02, 0xff, 0xfd, 0xf9, 0xf4, 0x03, + 0x00, 0xfd, 0x03, 0x08, 0x04, 0x03, 0x06, 0x07, 0x06, 0x00, 0x00, 0x04, + 0x01, 0x01, 0x07, 0x05, 0x02, 0x01, 0x00, 0xf9, 0xfa, 0xfe, 0xff, 0xfe, + 0xfc, 0x01, 0x03, 0x05, 0x06, 0x00, 0x05, 0x04, 0x01, 0x03, 0x00, 0xfe, + 0xff, 0x01, 0x01, 0xff, 0x01, 0xff, 0xf7, 0xfd, 0xff, 0x03, 0x04, 0x06, + 0x08, 0x05, 0x01, 0x02, 0x07, 0x08, 0x02, 0xfe, 0xfe, 0xfa, 0xfe, 0x02, + 0xfd, 0x00, 0x03, 0x04, 0x03, 0xfe, 0xf9, 0xfa, 0x01, 0x03, 0x04, 0x0c, + 0x07, 0xfd, 0xfa, 0xf8, 0xfb, 0xfe, 0xff, 0xff, 0xfd, 0xfb, 0xfc, 0xfd, + 0xff, 0x00, 0x00, 0xff, 0x03, 0x04, 0x04, 0x01, 0x01, 0x01, 0x00, 0xfd, + 0xff, 0x01, 0xfe, 0x00, 0x02, 0x01, 0xff, 0x03, 0x04, 0x02, 0x00, 0x01, + 0xfc, 0xfa, 0xfd, 0xfe, 0xff, 0xfe, 0xfc, 0xfd, 0xfe, 0x01, 0x06, 0x0d, + 0x09, 0x02, 0x03, 0x04, 0x02, 0xfd, 0xff, 0x03, 0x03, 0x04, 0x05, 0x00, + 0x02, 0x02, 0x03, 0x03, 0x03, 0x05, 0x04, 0x00, 0x01, 0x03, 0x02, 0x05, + 0x08, 0x0e, 0x08, 0x04, 0x04, 0x05, 0x05, 0x02, 0x07, 0x0c, 0x07, 0x07, + 0x07, 0x09, 0x09, 0x04, 0x02, 0x03, 0x09, 0x08, 0x0e, 0x10, 0x09, 0x09, + 0x06, 0x00, 0xfc, 0xfd, 0x03, 0x05, 0xfd, 0xfb, 0x02, 0x01, 0x06, 0x12, + 0x16, 0x0c, 0x05, 0x02, 0xff, 0xfc, 0xfb, 0xf9, 0xfd, 0x03, 0x01, 0x00, + 0x01, 0x03, 0x00, 0xfc, 0xfc, 0xfe, 0xff, 0x00, 0x04, 0x09, 0x05, 0x04, + 0x02, 0x02, 0x01, 0x01, 0x00, 0xfe, 0x04, 0x03, 0x00, 0x03, 0x02, 0x00, + 0x00, 0x02, 0x03, 0x03, 0xfe, 0xfe, 0x00, 0x02, 0x05, 0x01, 0x00, 0x00, + 0xfb, 0xfc, 0xfe, 0xfb, 0xfa, 0xfb, 0xfc, 0xff, 0x02, 0x01, 0x00, 0xff, + 0xfc, 0xf3, 0xf8, 0xfe, 0xfe, 0xff, 0xff, 0xfc, 0xf9, 0xf7, 0xf9, 0xf4, + 0xfb, 0xfc, 0xf9, 0xfa, 0xfb, 0xf9, 0xfb, 0xfd, 0xfb, 0xfc, 0xff, 0x01, + 0xfc, 0xf3, 0xf4, 0xfc, 0xff, 0xfd, 0xf7, 0xf9, 0xfb, 0xfb, 0xf8, 0xf4, + 0xf4, 0xfc, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xf8, 0xfa, 0xfc, 0xf9, 0xfc, + 0xfe, 0xf9, 0xf9, 0xfe, 0xfb, 0xf7, 0xfa, 0xfc, 0xfc, 0xf7, 0xf8, 0xf9, + 0xf9, 0xf9, 0xf9, 0xfd, 0xff, 0xfd, 0xfa, 0xf9, 0xf8, 0xf7, 0xf4, 0xf3, + 0xf7, 0xf8, 0xfc, 0xff, 0x00, 0xfe, 0xfb, 0xfa, 0xfb, 0xff, 0xfe, 0xfd, + 0xff, 0xfb, 0xf3, 0xf7, 0xf3, 0xf4, 0xf8, 0xfe, 0x04, 0x04, 0xfc, 0xf7, + 0xfa, 0xfe, 0xff, 0xfd, 0xfe, 0x00, 0xfd, 0xfe, 0xfc, 0xf8, 0xf3, 0xfa, + 0xfe, 0xfe, 0xfa, 0xfb, 0xfc, 0xfa, 0xfc, 0x01, 0xff, 0xfc, 0xf9, 0xfa, + 0xfc, 0xff, 0xfb, 0xf2, 0xf3, 0xf7, 0xfb, 0xfc, 0xfa, 0xfb, 0xf4, 0xf2, + 0xef, 0xf1, 0xf4, 0xf1, 0xea, 0xed, 0xf3, 0xfc, 0xfd, 0xfc, 0xff, 0xff, + 0xfc, 0xfd, 0xfc, 0xf4, 0xf8, 0xfc, 0xf9, 0xfa, 0xf4, 0xed, 0xf0, 0xfb, + 0xfb, 0xf1, 0xef, 0xfa, 0x04, 0x08, 0x07, 0x01, 0xfe, 0x01, 0x02, 0xfe, + 0xfc, 0xfd, 0xfc, 0xf7, 0xf2, 0xf8, 0xf8, 0xf9, 0xfa, 0xf7, 0xf9, 0xfb, + 0xfe, 0xfe, 0xff, 0xfe, 0x00, 0x03, 0x04, 0x03, 0x05, 0x00, 0xfc, 0xfc, + 0xff, 0xfd, 0xfc, 0xfd, 0x00, 0xff, 0xfe, 0xfd, 0xfd, 0xfd, 0xff, 0xfd, + 0xfd, 0xfe, 0xfe, 0xfd, 0xf9, 0xfc, 0x02, 0x05, 0x03, 0x01, 0xfd, 0xfc, + 0xfe, 0xfd, 0x04, 0x0c, 0x06, 0x08, 0x08, 0x07, 0x03, 0x02, 0x02, 0x01, + 0x01, 0xff, 0x00, 0x06, 0x04, 0x00, 0x06, 0x0d, 0x0e, 0x0e, 0x0e, 0x0c, + 0x08, 0x0c, 0x0e, 0x0d, 0x0e, 0x0f, 0x09, 0x05, 0x03, 0x04, 0x04, 0xfc, + 0x00, 0x08, 0x0c, 0x09, 0x0c, 0x11, 0x18, 0x18, 0x13, 0x14, 0x0f, 0x08, + 0x08, 0x08, 0x07, 0x06, 0x06, 0x06, 0x07, 0x07, 0x03, 0x03, 0x05, 0x08, + 0x0e, 0x11, 0x13, 0x12, 0x13, 0x12, 0x0f, 0x0e, 0x0c, 0x08, 0x07, 0x05, + 0x07, 0x07, 0x08, 0x06, 0x06, 0x04, 0x03, 0x05, 0x08, 0x05, 0x02, 0x08, + 0x0e, 0x09, 0x09, 0x0e, 0x0c, 0x10, 0x11, 0x0e, 0x0e, 0x0d, 0x09, 0x04, + 0x04, 0x07, 0x04, 0x01, 0x03, 0x06, 0x03, 0xfe, 0xfc, 0xfe, 0x01, 0x03, + 0x08, 0x0c, 0x0c, 0x08, 0x07, 0x06, 0x05, 0x03, 0x02, 0x02, 0x02, 0x01, + 0x01, 0xfe, 0xf8, 0xfc, 0xff, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x05, + 0x04, 0x00, 0xfc, 0xf8, 0xf4, 0xfb, 0xff, 0xfd, 0xf8, 0xfd, 0x01, 0x01, + 0x00, 0x00, 0x00, 0xfd, 0xfe, 0x00, 0x00, 0x03, 0x00, 0xfb, 0xfb, 0xfb, + 0xfa, 0xfc, 0xff, 0xfe, 0xfe, 0xfe, 0xff, 0xfd, 0xff, 0x00, 0x00, 0x00, + 0xfe, 0xfe, 0xfc, 0xfe, 0x00, 0x01, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0xfd, 0xff, 0x00, 0xfc, 0xfb, 0xfe, 0xff, 0x00, 0x02, 0x00, 0xfe, + 0xfe, 0xfb, 0xfb, 0xfc, 0xfb, 0xfd, 0xfe, 0xfe, 0x00, 0xff, 0xfb, 0xfc, + 0x00, 0x00, 0xff, 0xfc, 0xfc, 0xfe, 0xfe, 0xfb, 0xfc, 0x00, 0x03, 0x02, + 0x00, 0xfe, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xfe, 0xfd, 0xfb, + 0xfc, 0xfd, 0xf9, 0xf6, 0xf7, 0xf7, 0xf7, 0xfb, 0xfd, 0xfd, 0xfd, 0x00, + 0x02, 0x03, 0x03, 0x03, 0x03, 0x01, 0x00, 0xfd, 0xfd, 0xff, 0x00, 0x00, + 0x00, 0xfc, 0xfb, 0xfa, 0xfb, 0xfe, 0xff, 0xfe, 0xfe, 0xff, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xfd, 0xf8, 0xf5, 0xf7, 0xfa, 0xfd, 0xfe, 0xfe, 0xfd, + 0xfe, 0x00, 0x00, 0xfe, 0xfd, 0xfe, 0xfc, 0xff, 0x02, 0x02, 0x03, 0x04, + 0x00, 0xfe, 0xfe, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xff, 0x00, 0x00, 0xff, + 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xff, 0x01, 0x03, 0x01, 0x01, 0x04, 0x04, + 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x04, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0xff, + 0xfd, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x02, 0x05, 0x05, 0x05, 0x02, + 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x03, 0x04, 0x01, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x04, 0x07, 0x04, 0x01, 0x01, 0x01, + 0x00, 0xff, 0xff, 0xfd, 0xff, 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, + 0xfe, 0xfd, 0xfd, 0xff, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0xff, 0xfe, 0xfe, + 0xfe, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xff, + 0x00, 0xff, 0xff, 0xfe, 0xfe, 0xfc, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xfe, + 0xff, 0xff, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, + 0x01, 0x0a, 0x0e, 0x0b, 0x08, 0x06, 0x07, 0x06, 0xf8, 0x02, 0x09, 0x09, + 0x07, 0x0e, 0x0e, 0x09, 0x11, 0x06, 0x00, 0x0a, 0x0f, 0x09, 0xfd, 0xfa, + 0xfb, 0xfc, 0xf6, 0xf9, 0xfc, 0xfc, 0xfb, 0xff, 0xfb, 0xf8, 0xfc, 0xfc, + 0xff, 0x01, 0x04, 0x07, 0x04, 0x04, 0xff, 0x01, 0x00, 0xfb, 0x00, 0x05, + 0x09, 0x09, 0x03, 0x05, 0x0e, 0x11, 0x0d, 0x07, 0x04, 0x14, 0x03, 0xfd, + 0x07, 0x0d, 0x0d, 0x08, 0x00, 0xfb, 0x04, 0x0c, 0x02, 0xfe, 0xfd, 0xfd, + 0x00, 0xf8, 0xf7, 0xff, 0x07, 0x02, 0xfc, 0xfe, 0xf5, 0xfb, 0xfd, 0xfc, + 0x02, 0xfd, 0x01, 0x06, 0x03, 0x0d, 0x11, 0x01, 0xf6, 0xff, 0x11, 0x07, + 0x08, 0x03, 0xff, 0x10, 0x0e, 0x09, 0x05, 0x03, 0x02, 0xf5, 0xfa, 0x00, + 0xfc, 0x07, 0x05, 0x05, 0x07, 0x02, 0x03, 0x09, 0x06, 0x01, 0x06, 0xff, + 0xfa, 0xfc, 0x00, 0xfb, 0xfc, 0xf7, 0xfa, 0xfb, 0xfb, 0xf1, 0xf6, 0x03, + 0xfa, 0x05, 0x07, 0x07, 0x19, 0x0e, 0x0d, 0x0a, 0x07, 0x03, 0x10, 0x12, + 0x08, 0x08, 0x0b, 0x11, 0x15, 0x13, 0x09, 0x08, 0x0c, 0xff, 0x00, 0x00, + 0x01, 0x06, 0x08, 0x05, 0xf9, 0xf0, 0xf6, 0xfe, 0xfc, 0xfa, 0xf5, 0xfb, + 0xfe, 0xff, 0xf8, 0xef, 0xf6, 0xf9, 0xf9, 0xf5, 0xf4, 0xf5, 0xf5, 0xfc, + 0x00, 0x02, 0x04, 0x0a, 0x0d, 0x1e, 0x0c, 0xfb, 0x02, 0x10, 0x13, 0x0f, + 0x08, 0x01, 0x09, 0x11, 0x11, 0x0f, 0x09, 0x11, 0x0c, 0x01, 0xfb, 0xfe, + 0x02, 0x02, 0x07, 0x09, 0x02, 0x01, 0xfc, 0xfd, 0x03, 0x02, 0x01, 0x01, + 0x00, 0x02, 0xfc, 0xf7, 0xf5, 0xfe, 0xfd, 0xf3, 0xef, 0xfa, 0x0d, 0x04, + 0x08, 0x0c, 0x0a, 0x13, 0x0b, 0x07, 0x05, 0xf8, 0xf8, 0xfb, 0x06, 0x08, + 0xff, 0x04, 0x0f, 0x13, 0x10, 0x04, 0x0d, 0x0a, 0x01, 0xfa, 0xf7, 0xfc, + 0xfc, 0x00, 0xfe, 0xfb, 0x01, 0xfe, 0xfe, 0xfd, 0x03, 0x08, 0x09, 0x08, + 0x09, 0xfb, 0xf2, 0xf5, 0xf9, 0xf5, 0xf7, 0xf7, 0xf6, 0xfa, 0xfc, 0xf9, + 0x00, 0xfc, 0x0e, 0x0e, 0x0a, 0x05, 0x03, 0x08, 0x0f, 0x14, 0x18, 0x0e, + 0x03, 0x0b, 0x0e, 0x08, 0x0a, 0x03, 0x0e, 0x0d, 0x09, 0x09, 0x0e, 0x08, + 0x04, 0x05, 0x08, 0x03, 0x07, 0x06, 0x00, 0x00, 0x01, 0xfc, 0xfc, 0xfa, + 0xfd, 0xf7, 0xf5, 0xf2, 0x00, 0x02, 0xfd, 0xf9, 0xfd, 0xf7, 0xed, 0xf4, + 0xf8, 0x00, 0x11, 0x0d, 0x02, 0x02, 0xfd, 0x00, 0x0b, 0x12, 0x09, 0xff, + 0x01, 0x03, 0x0e, 0x0b, 0x08, 0x0e, 0x08, 0xfd, 0xfe, 0x02, 0x04, 0x00, + 0xfe, 0xfb, 0xf8, 0xfe, 0x02, 0x00, 0x04, 0x07, 0x08, 0x00, 0xfe, 0x06, + 0x07, 0xf8, 0xf9, 0x04, 0x00, 0x05, 0x05, 0xfb, 0xfe, 0x05, 0x04, 0xfb, + 0x08, 0x16, 0x0e, 0x10, 0x06, 0x04, 0x03, 0x00, 0xfb, 0x09, 0x0b, 0x07, + 0x0b, 0x0e, 0x07, 0x00, 0xf9, 0x01, 0xfe, 0x03, 0x03, 0x07, 0x05, 0x04, + 0x06, 0x02, 0x01, 0x01, 0xf7, 0xfb, 0x04, 0x0a, 0x09, 0x0a, 0xf5, 0xf6, + 0xf9, 0xf8, 0xfa, 0x06, 0x01, 0x05, 0xfd, 0x05, 0x08, 0x00, 0xfe, 0xfd, + 0x06, 0x10, 0x07, 0x00, 0xfa, 0x01, 0x06, 0x03, 0x08, 0x0c, 0x05, 0x0b, + 0x0c, 0x0d, 0x09, 0x06, 0x0f, 0x0a, 0x00, 0x00, 0x02, 0x04, 0x09, 0x09, + 0x03, 0xf9, 0xfe, 0x05, 0xf4, 0xe8, 0xf4, 0x02, 0x08, 0xff, 0x00, 0xfe, + 0xfc, 0xfd, 0xff, 0xef, 0xee, 0xf1, 0xee, 0xfb, 0xfc, 0xfa, 0xfc, 0x04, + 0x15, 0x13, 0x0c, 0x07, 0x05, 0x09, 0x14, 0x17, 0x14, 0x11, 0x0c, 0x14, + 0x1a, 0x0e, 0x07, 0x11, 0x11, 0x06, 0x06, 0x03, 0x01, 0x04, 0x06, 0xfa, + 0xfd, 0x04, 0xff, 0xff, 0xff, 0xf3, 0xf7, 0xfa, 0x03, 0x04, 0xfc, 0xef, + 0xf4, 0xef, 0xf0, 0xf9, 0xfc, 0xfa, 0xfc, 0x08, 0x02, 0x03, 0x01, 0x09, + 0x12, 0x08, 0xfe, 0xf9, 0xfe, 0x02, 0x00, 0x00, 0x0f, 0x12, 0x1b, 0x1a, + 0x0c, 0x0c, 0x0d, 0x12, 0x0b, 0x0a, 0x07, 0x00, 0xf9, 0xf3, 0xf4, 0xf5, + 0x02, 0x0f, 0xff, 0xf1, 0xec, 0xf7, 0xff, 0xfe, 0xfe, 0xf9, 0xf2, 0xfe, + 0xfb, 0xfa, 0xf6, 0xf7, 0xf9, 0xf9, 0x1a, 0x13, 0xff, 0xfe, 0xfe, 0x0e, + 0x17, 0x17, 0x13, 0x15, 0x0e, 0xff, 0x04, 0x0b, 0x07, 0x12, 0x18, 0x06, + 0x07, 0x08, 0x08, 0x0d, 0x0e, 0x09, 0x11, 0x13, 0x08, 0x04, 0x08, 0x04, + 0x08, 0x09, 0xff, 0xf9, 0xf5, 0xe3, 0xe5, 0xf3, 0xef, 0xef, 0xf4, 0xf3, + 0xf8, 0xf6, 0xef, 0xf2, 0xed, 0xea, 0x03, 0x01, 0xf9, 0xfe, 0x05, 0xff, + 0xfc, 0x09, 0x0c, 0x07, 0x0b, 0x06, 0x04, 0x0f, 0x0a, 0x0e, 0x19, 0x1f, + 0x18, 0x0d, 0x0c, 0x0f, 0x13, 0x0e, 0x04, 0x00, 0xfc, 0x00, 0xfe, 0xfb, + 0xf9, 0x02, 0x05, 0xff, 0xff, 0x05, 0x01, 0xfd, 0x04, 0x02, 0x00, 0x06, + 0x05, 0x00, 0xfe, 0xf5, 0xf7, 0x05, 0x10, 0x08, 0x03, 0x08, 0x15, 0x12, + 0x04, 0x02, 0x03, 0x07, 0x0e, 0x10, 0x07, 0x06, 0x02, 0xfe, 0x04, 0x0e, + 0x02, 0xff, 0xfb, 0xf8, 0x04, 0x0e, 0x05, 0xff, 0xfe, 0xfe, 0xf8, 0xfe, + 0xf9, 0xf4, 0xf1, 0xf0, 0xe3, 0xe7, 0xf2, 0xf5, 0xee, 0xf6, 0xf7, 0xfe, + 0xff, 0xfc, 0x03, 0xf6, 0xf2, 0x13, 0x1f, 0x19, 0x10, 0x0a, 0x0e, 0x13, + 0x10, 0x0e, 0x0a, 0x08, 0x06, 0x06, 0x0e, 0x12, 0x0d, 0x09, 0x0d, 0x0e, + 0x0b, 0x0d, 0x0e, 0x13, 0x15, 0x12, 0x08, 0x01, 0x09, 0x07, 0x00, 0xf7, + 0xf6, 0xf8, 0xfc, 0xfe, 0xfb, 0xee, 0xee, 0xfc, 0xfe, 0xf6, 0xed, 0xed, + 0xe6, 0xe5, 0xe3, 0xde, 0xed, 0x0b, 0x13, 0x15, 0x0c, 0x0a, 0x10, 0x09, + 0x09, 0x06, 0x08, 0x0f, 0x16, 0x1d, 0x1c, 0x1b, 0x14, 0x12, 0x0f, 0x12, + 0x0f, 0x0e, 0x16, 0x13, 0x0e, 0x02, 0xf9, 0xfb, 0xfa, 0xf9, 0xfb, 0xfc, + 0xf6, 0xf0, 0xf4, 0xf5, 0xef, 0xe6, 0xe8, 0xeb, 0xf5, 0xf3, 0xf8, 0xfd, + 0x01, 0xfd, 0xf7, 0xf9, 0x14, 0x28, 0x1a, 0x0b, 0x09, 0x07, 0x08, 0x00, + 0x00, 0x0a, 0x0d, 0x0e, 0x0e, 0x0d, 0x16, 0x17, 0x09, 0x07, 0x0d, 0x18, + 0x12, 0x06, 0x02, 0x04, 0x07, 0xfe, 0xf5, 0xf6, 0xf3, 0xf9, 0xf8, 0xf9, + 0xf8, 0xf0, 0xee, 0xee, 0xf4, 0xf9, 0xf8, 0xf4, 0xf2, 0xf8, 0xf8, 0xf0, + 0xf8, 0xf8, 0xed, 0xf8, 0x19, 0x19, 0x1a, 0x19, 0x12, 0x15, 0x13, 0x11, + 0x15, 0x18, 0x0a, 0x05, 0x06, 0x03, 0x1c, 0x1e, 0x0d, 0x0c, 0x0d, 0x15, + 0x16, 0x0e, 0x07, 0x0c, 0x0b, 0x05, 0x0a, 0x09, 0x06, 0x07, 0xfc, 0xf4, + 0xf4, 0xfc, 0xff, 0xf7, 0xee, 0xe8, 0xe3, 0xe5, 0xe7, 0xf4, 0xe5, 0xe2, + 0xe2, 0xde, 0xe3, 0xfc, 0x19, 0x0a, 0x02, 0x05, 0x05, 0x06, 0xfd, 0x00, + 0x04, 0x07, 0x09, 0x19, 0x1b, 0x1b, 0x32, 0x32, 0x25, 0x23, 0x21, 0x1c, + 0x0d, 0x0a, 0x02, 0x05, 0xfe, 0xfb, 0xfe, 0xfd, 0x01, 0x08, 0x06, 0xfe, + 0xf5, 0xf2, 0xf2, 0xf7, 0xf2, 0xed, 0xef, 0xf2, 0xf6, 0xf5, 0xf5, 0xf3, + 0xe8, 0xe7, 0xf2, 0x20, 0x23, 0x11, 0x07, 0x01, 0x0b, 0x14, 0x0d, 0x06, + 0x0b, 0x0a, 0x03, 0xfe, 0xf8, 0xfa, 0x15, 0x1e, 0x15, 0x10, 0x12, 0x0a, + 0x0b, 0x0e, 0x08, 0x04, 0xfc, 0xfc, 0x03, 0xfc, 0xf1, 0xea, 0xeb, 0xe7, + 0xef, 0xf2, 0xf7, 0x02, 0xff, 0x00, 0x03, 0xf9, 0xfc, 0xfc, 0xf9, 0xef, + 0xf0, 0xf1, 0x01, 0x1f, 0x15, 0x11, 0x0f, 0x0c, 0x13, 0x17, 0x10, 0x0f, + 0x0e, 0x10, 0x0d, 0x00, 0x02, 0x01, 0x11, 0x15, 0x0f, 0x19, 0x21, 0x10, + 0x01, 0xfd, 0x07, 0x0c, 0x10, 0x0c, 0x02, 0x01, 0x06, 0x08, 0xff, 0xf8, + 0xfb, 0x00, 0xfc, 0xf7, 0xf5, 0xf1, 0xe4, 0xde, 0xe5, 0xe4, 0xe3, 0xe3, + 0xea, 0xf1, 0x11, 0x0e, 0xff, 0xfa, 0xfc, 0x03, 0x07, 0x05, 0x04, 0x05, + 0x00, 0x05, 0x10, 0x0e, 0x0b, 0x0c, 0x1c, 0x1a, 0x10, 0x1a, 0x1d, 0x11, + 0x0f, 0x09, 0x00, 0xfb, 0xfc, 0x00, 0x0b, 0x0a, 0x04, 0x01, 0x00, 0xfc, + 0x02, 0xff, 0xf8, 0xfd, 0x02, 0xfa, 0xff, 0x07, 0xf7, 0xf1, 0xf3, 0xf7, + 0xfe, 0x0a, 0x21, 0x14, 0x10, 0x0b, 0x01, 0x07, 0x11, 0x12, 0x12, 0x10, + 0x08, 0x02, 0x00, 0xff, 0xfb, 0xff, 0x0e, 0x0a, 0x06, 0x05, 0xfc, 0xfb, + 0xfa, 0xf8, 0xf7, 0xf8, 0xf6, 0xf2, 0xf2, 0xf3, 0xf5, 0xf1, 0xec, 0xe6, + 0xea, 0xff, 0x17, 0x12, 0x01, 0xfa, 0xfa, 0xfa, 0xfd, 0xf8, 0xf1, 0xf9, + 0xff, 0x20, 0x27, 0x1d, 0x17, 0x1c, 0x14, 0x0e, 0x14, 0x12, 0x0f, 0x07, + 0x06, 0x0b, 0x0b, 0x06, 0x04, 0x08, 0x19, 0x1b, 0x1f, 0x13, 0x0d, 0x10, + 0x0b, 0x04, 0x01, 0x06, 0x06, 0x04, 0x01, 0xfd, 0xf4, 0xf0, 0xf7, 0xf7, + 0xf2, 0xf3, 0xf0, 0xee, 0xec, 0xe8, 0xe2, 0xdc, 0xda, 0xd7, 0xe7, 0xf8, + 0x05, 0x07, 0xfa, 0x00, 0x00, 0x04, 0x00, 0x04, 0x11, 0x0f, 0x05, 0x0e, + 0x27, 0x28, 0x21, 0x18, 0x0e, 0x11, 0x1e, 0x1f, 0x16, 0x0c, 0x0b, 0x0b, + 0x0e, 0x09, 0x04, 0x02, 0xff, 0x07, 0x0c, 0x04, 0xf9, 0xf7, 0xf7, 0xf7, + 0xfa, 0xef, 0xe7, 0xe6, 0xe7, 0xe8, 0xe3, 0xe7, 0xed, 0xe6, 0xe2, 0xf1, + 0x10, 0x08, 0x09, 0x0f, 0x09, 0x07, 0x0a, 0x2e, 0x33, 0x1f, 0x17, 0x1a, + 0x13, 0x0d, 0x0a, 0x0a, 0x06, 0x13, 0x23, 0x1c, 0x1a, 0x1a, 0x16, 0x0e, + 0x0c, 0x07, 0xff, 0xf7, 0xf6, 0xf9, 0xfd, 0xf5, 0xeb, 0xe9, 0xf0, 0x07, + 0x06, 0xf1, 0xf3, 0xf8, 0xf1, 0xea, 0xe6, 0xe5, 0xdf, 0xe4, 0xe8, 0x07, + 0x0d, 0x01, 0xf8, 0xfa, 0x00, 0x03, 0x01, 0x09, 0x14, 0x0f, 0x0a, 0x05, + 0xff, 0xfc, 0xfe, 0x19, 0x1b, 0x20, 0x2b, 0x23, 0x15, 0x10, 0x12, 0x17, + 0x08, 0x00, 0x04, 0x03, 0x06, 0x16, 0x15, 0x05, 0xfc, 0xfe, 0x02, 0xfc, + 0xf9, 0xee, 0xef, 0xef, 0xf2, 0xe9, 0xe6, 0xe4, 0xdf, 0xdf, 0xfc, 0x19, + 0x06, 0xfd, 0xfd, 0xfa, 0xfd, 0x06, 0x08, 0x12, 0x15, 0x0a, 0x10, 0x10, + 0x10, 0x12, 0x13, 0x0d, 0x0e, 0x1d, 0x23, 0x1d, 0x10, 0x07, 0x03, 0x15, + 0x21, 0x09, 0xf9, 0xfa, 0xff, 0xfb, 0xfb, 0xff, 0xf9, 0xfe, 0xfb, 0xf3, + 0xf0, 0xf4, 0x04, 0x01, 0xf8, 0xf5, 0xf6, 0xef, 0xea, 0xf1, 0x0e, 0x06, + 0xff, 0x03, 0x0a, 0x08, 0x0b, 0x0f, 0x0e, 0x13, 0x17, 0x11, 0x0a, 0x02, + 0xfb, 0xf9, 0xfa, 0xf9, 0xfa, 0x08, 0x02, 0xfc, 0x01, 0xfe, 0xf8, 0xf3, + 0xf5, 0xf6, 0xed, 0xea, 0xea, 0xe9, 0xea, 0xfc, 0x1b, 0x20, 0x1c, 0x0e, + 0x03, 0x02, 0x04, 0x09, 0xfb, 0xfa, 0xff, 0xfb, 0xff, 0x1b, 0x24, 0x28, + 0x1d, 0x16, 0x10, 0x11, 0x16, 0x27, 0x24, 0x27, 0x24, 0x19, 0x11, 0x09, + 0x03, 0xfc, 0xeb, 0xea, 0xfa, 0x11, 0x09, 0x09, 0x0a, 0x06, 0x03, 0xfd, + 0xfc, 0xfd, 0xf9, 0xf1, 0xef, 0xee, 0xea, 0xf0, 0xf1, 0xeb, 0xe9, 0xe4, + 0xdf, 0xde, 0xde, 0xe5, 0xfe, 0xfd, 0xf5, 0xf0, 0x03, 0x06, 0xfc, 0xfd, + 0xf9, 0xf4, 0xf0, 0xeb, 0xf6, 0x10, 0x11, 0x27, 0x32, 0x22, 0x17, 0x15, + 0x15, 0x12, 0x12, 0x16, 0x26, 0x17, 0x0d, 0x18, 0x1c, 0x18, 0x11, 0x10, + 0x09, 0xfd, 0x03, 0x06, 0x0a, 0x06, 0x08, 0x0a, 0x03, 0x02, 0x01, 0xf9, + 0xf6, 0xf7, 0xf6, 0xf0, 0xf4, 0xf6, 0xf4, 0x03, 0x13, 0x06, 0xf7, 0xf8, + 0x22, 0x1a, 0xfe, 0xf4, 0xfc, 0x0b, 0x03, 0x0e, 0x0d, 0x04, 0x05, 0x04, + 0xfb, 0xf7, 0xf5, 0x0d, 0x1f, 0x08, 0x01, 0x02, 0x06, 0xff, 0xfe, 0x01, + 0xf9, 0xf0, 0xe8, 0xe9, 0xea, 0xf5, 0x01, 0x03, 0xfe, 0xf9, 0xf2, 0xf6, + 0xf9, 0xf4, 0xf6, 0xf2, 0xe8, 0xe6, 0xf3, 0x0e, 0x08, 0x02, 0xf9, 0xfb, + 0xfc, 0xfb, 0xfe, 0xfc, 0x04, 0x0f, 0x0d, 0x15, 0x2a, 0x34, 0x2b, 0x20, + 0x15, 0x10, 0x14, 0x2a, 0x21, 0x11, 0x0f, 0x13, 0x1a, 0x18, 0x18, 0x1b, + 0x27, 0x1e, 0x14, 0x0d, 0x0b, 0x08, 0x04, 0xff, 0x03, 0x03, 0xf6, 0xea, + 0xe6, 0xe8, 0xd8, 0xcc, 0xd1, 0xd7, 0xef, 0xeb, 0xf6, 0xf4, 0xf0, 0xf0, + 0xeb, 0xe3, 0xe2, 0xea, 0xf3, 0x09, 0x16, 0x11, 0x0a, 0x09, 0x08, 0x07, + 0x03, 0xfc, 0x13, 0x18, 0x1e, 0x22, 0x1a, 0x1d, 0x1c, 0x17, 0x10, 0x0c, + 0x0b, 0x02, 0xfc, 0xfb, 0x02, 0x01, 0xfa, 0xfb, 0x0a, 0x06, 0xfb, 0xf8, + 0xf6, 0xed, 0xeb, 0xee, 0xf9, 0x16, 0x0d, 0x03, 0xfe, 0x02, 0x13, 0x0d, + 0x06, 0xfc, 0xfb, 0xfd, 0x03, 0x1b, 0x1e, 0x1b, 0x12, 0x0e, 0x0b, 0x05, + 0x04, 0x10, 0x1e, 0x0b, 0x05, 0xff, 0xff, 0x06, 0x06, 0x03, 0xfb, 0xf0, + 0x03, 0x0a, 0xf1, 0xf2, 0xfd, 0xfd, 0xf6, 0xfa, 0xfd, 0xf4, 0xef, 0xf0, + 0xef, 0xed, 0xee, 0xf2, 0x12, 0x1c, 0x09, 0x04, 0xfe, 0x01, 0xff, 0xff, + 0xff, 0xfd, 0x00, 0xfb, 0x04, 0x11, 0x17, 0x1e, 0x1c, 0x14, 0x0b, 0x03, + 0x05, 0x1c, 0x16, 0x0d, 0x05, 0xfe, 0xf9, 0x03, 0x0a, 0x0b, 0x08, 0x01, + 0xfa, 0xf5, 0xf5, 0xfb, 0xf6, 0xf0, 0xee, 0xf6, 0x08, 0x0c, 0x03, 0xfa, + 0xf5, 0xf3, 0xf0, 0x06, 0x10, 0x07, 0xfe, 0xfb, 0xfb, 0xfb, 0xf7, 0xfa, + 0x00, 0x11, 0x12, 0x13, 0x1b, 0x1d, 0x1f, 0x19, 0x15, 0x17, 0x15, 0x0c, + 0x14, 0x15, 0xfa, 0xfa, 0x06, 0x01, 0xf7, 0x00, 0x04, 0x03, 0x08, 0x06, + 0xfc, 0xf5, 0xf6, 0xf7, 0xf8, 0xf2, 0xf1, 0xfa, 0xf3, 0xf1, 0xee, 0xea, + 0xea, 0xeb, 0xfb, 0x03, 0x15, 0x19, 0x0f, 0x10, 0x16, 0x0d, 0x04, 0xfe, + 0x05, 0x08, 0xfb, 0xfc, 0x0d, 0x09, 0x10, 0x09, 0x07, 0x0f, 0x0b, 0x10, + 0x10, 0xfe, 0xf9, 0xf6, 0xf9, 0xfc, 0xff, 0x04, 0xfd, 0xf7, 0xf0, 0xec, + 0xfd, 0x13, 0x0c, 0x02, 0xff, 0xfc, 0xfe, 0x00, 0x01, 0xf7, 0xf7, 0xf3, + 0xfe, 0x18, 0x12, 0x0f, 0x0c, 0x07, 0x0a, 0x0b, 0x08, 0x00, 0x02, 0x00, + 0x12, 0x15, 0xfe, 0x03, 0x0d, 0x11, 0x15, 0x08, 0x0c, 0x0e, 0x15, 0x1d, + 0x0b, 0x07, 0x01, 0x00, 0x04, 0x0c, 0x13, 0x1a, 0x0d, 0x02, 0xfc, 0xf7, + 0xf6, 0xfe, 0xfe, 0xf5, 0xf2, 0xee, 0xea, 0xef, 0xf4, 0xf9, 0xf1, 0xe7, + 0xfb, 0xfd, 0xf8, 0xf3, 0xf6, 0xf9, 0xf3, 0xee, 0xe6, 0xe4, 0xe7, 0xf8, + 0xfc, 0xfa, 0xf9, 0x05, 0x02, 0x08, 0x0f, 0x0c, 0x1d, 0x2b, 0x30, 0x22, + 0x1c, 0x17, 0x11, 0x0e, 0x0d, 0x12, 0x1b, 0x1b, 0x12, 0x0c, 0x06, 0x04, + 0x0b, 0x1b, 0x17, 0x10, 0x09, 0x06, 0xff, 0x00, 0xfc, 0xfe, 0xfe, 0x0e, + 0x07, 0xf5, 0xe7, 0xe5, 0xf5, 0x07, 0x02, 0xf6, 0xef, 0xf0, 0xf3, 0xf1, + 0xf2, 0xf7, 0x02, 0xfd, 0xfc, 0x05, 0x05, 0xff, 0x05, 0x10, 0x06, 0xfe, + 0xfd, 0xf8, 0xf5, 0xf7, 0x0b, 0x12, 0x14, 0x08, 0x02, 0x06, 0x0d, 0x05, + 0x02, 0x06, 0x07, 0x07, 0x02, 0xfa, 0xfa, 0xf4, 0xec, 0xfd, 0x1a, 0x18, + 0x08, 0x04, 0x01, 0xfc, 0xfe, 0xff, 0xff, 0xfd, 0xfd, 0x00, 0xff, 0xf8, + 0xf5, 0x02, 0x10, 0x07, 0x04, 0x0c, 0x0c, 0x10, 0x19, 0x18, 0x1b, 0x15, + 0x10, 0x0d, 0x0a, 0x0c, 0x13, 0x1a, 0x16, 0x0b, 0x03, 0xff, 0xfc, 0xf7, + 0x10, 0x09, 0xf8, 0xf5, 0xf6, 0xf4, 0xf5, 0xf0, 0xed, 0xfc, 0xfd, 0xfb, + 0xf6, 0xf3, 0xee, 0xf6, 0xf8, 0x00, 0xfc, 0xf4, 0xfd, 0x03, 0x00, 0xf8, + 0xf8, 0x05, 0x00, 0xfa, 0x05, 0x07, 0x06, 0x12, 0x0e, 0x18, 0x1a, 0x13, + 0x0f, 0x09, 0x05, 0x01, 0x06, 0x09, 0x0b, 0x07, 0xfd, 0xf5, 0xf4, 0xf8, + 0xfc, 0xfe, 0xfe, 0xfb, 0xf4, 0xf4, 0xf2, 0xfb, 0x21, 0x1f, 0x15, 0x09, + 0x06, 0x04, 0x0a, 0x0e, 0x0a, 0x05, 0x01, 0x02, 0x0b, 0x0b, 0x06, 0x02, + 0x0d, 0x19, 0x15, 0x10, 0x11, 0x10, 0x1d, 0x15, 0x0f, 0x10, 0x03, 0xf9, + 0xfb, 0xed, 0xdf, 0xec, 0xf6, 0xf4, 0xfe, 0xff, 0xf7, 0xef, 0xef, 0xee, + 0xec, 0xeb, 0xf3, 0x00, 0xf9, 0xef, 0xeb, 0x01, 0x0a, 0x08, 0x05, 0xfe, + 0xfd, 0xfc, 0xfb, 0x04, 0x15, 0x0b, 0x09, 0x0d, 0x0c, 0x0b, 0x05, 0x09, + 0x0d, 0x0a, 0x06, 0x0f, 0x1c, 0x24, 0x1c, 0x14, 0x16, 0x15, 0x10, 0x0c, + 0x0e, 0x0c, 0x07, 0x0a, 0x08, 0x04, 0xfd, 0xf5, 0xf8, 0xf9, 0xf8, 0xf9, + 0xfa, 0xf3, 0xfa, 0xf8, 0xf1, 0xee, 0x01, 0x04, 0xfa, 0xf5, 0xf3, 0xfb, + 0xf9, 0xf9, 0xfb, 0xfe, 0xfd, 0x05, 0x0d, 0x07, 0x01, 0xfd, 0xfa, 0x06, + 0x0d, 0xfd, 0xfc, 0x17, 0x19, 0x0a, 0x0b, 0x19, 0x1c, 0x13, 0x0a, 0x08, + 0x04, 0x02, 0x09, 0x0e, 0x16, 0x0f, 0x07, 0x02, 0xfe, 0xfd, 0xf9, 0xfc, + 0x01, 0x01, 0xfd, 0xf1, 0xf1, 0x05, 0x09, 0x02, 0xff, 0xfa, 0x04, 0x08, + 0xff, 0xfd, 0xfe, 0xfd, 0xf8, 0xfa, 0xfa, 0x00, 0xfe, 0xf8, 0xfc, 0xf9, + 0xf6, 0xf7, 0x10, 0x13, 0x01, 0xfd, 0x01, 0x10, 0x19, 0x0f, 0x05, 0x01, + 0x07, 0x00, 0xff, 0x06, 0x09, 0x03, 0x04, 0x05, 0x01, 0xff, 0xfc, 0x07, + 0x19, 0x13, 0x0e, 0x06, 0x12, 0x1b, 0x14, 0x11, 0x0c, 0x04, 0xfc, 0xf8, + 0xf6, 0xeb, 0xeb, 0xf7, 0xfc, 0xf9, 0xf8, 0xfe, 0x01, 0x04, 0xf9, 0xf4, + 0xfb, 0x06, 0x0d, 0x07, 0x06, 0x07, 0x0c, 0x0d, 0x0d, 0x08, 0x08, 0x0a, + 0x03, 0x00, 0xfc, 0xfc, 0x0b, 0x06, 0x03, 0x01, 0x02, 0x02, 0xfb, 0xfb, + 0x03, 0xfe, 0xf9, 0x08, 0x0e, 0x06, 0x02, 0x0a, 0x08, 0xfc, 0xf2, 0xef, + 0xf2, 0xf6, 0x04, 0x07, 0xff, 0xfc, 0xfb, 0x00, 0x01, 0xf8, 0xf2, 0xfe, + 0x09, 0x13, 0x11, 0x09, 0x06, 0x0b, 0x14, 0x11, 0x0d, 0x08, 0x08, 0x06, + 0x08, 0x0f, 0x09, 0x06, 0x08, 0x04, 0x04, 0x06, 0xfd, 0xf3, 0xf1, 0x02, + 0x18, 0x01, 0x00, 0x0d, 0x09, 0x09, 0x09, 0x08, 0x03, 0x02, 0xff, 0xfa, + 0xf8, 0xfb, 0x06, 0x0a, 0x06, 0x08, 0x0b, 0x0c, 0x04, 0x03, 0x07, 0x03, + 0x0a, 0x0c, 0x02, 0xfb, 0xfc, 0xff, 0xfa, 0xfb, 0xfe, 0xfd, 0xfc, 0xfa, + 0xfd, 0x00, 0xfb, 0xf7, 0xf9, 0xfa, 0xf8, 0xf4, 0xed, 0xec, 0xed, 0xee, + 0xf2, 0xfd, 0x10, 0x0d, 0x07, 0x03, 0xfd, 0xfd, 0x0d, 0x0d, 0x08, 0xfd, + 0x05, 0x0b, 0x0c, 0x0b, 0x04, 0x08, 0x0d, 0x10, 0x18, 0x1a, 0x20, 0x21, + 0x27, 0x20, 0x1a, 0x1b, 0x24, 0x21, 0x1c, 0x11, 0x0a, 0x0d, 0x07, 0x07, + 0x01, 0xec, 0xe0, 0xec, 0xf6, 0xf9, 0xfc, 0xfc, 0xf3, 0xec, 0xef, 0xea, + 0xee, 0xfe, 0xf9, 0xf6, 0xf3, 0xf4, 0xf2, 0xe6, 0xea, 0xed, 0xe6, 0xf2, + 0x06, 0x00, 0xf5, 0xf5, 0x0c, 0x13, 0x0a, 0x10, 0x0b, 0x03, 0x02, 0x08, + 0x12, 0x11, 0x0e, 0x14, 0x1c, 0x1f, 0x22, 0x1c, 0x0f, 0x09, 0x07, 0x07, + 0x08, 0x00, 0x00, 0x00, 0x02, 0x02, 0xff, 0xfb, 0xf5, 0xf1, 0xef, 0xf4, + 0x0f, 0x17, 0x16, 0x10, 0x0b, 0x03, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xfe, + 0x04, 0x04, 0x09, 0x08, 0x09, 0x0d, 0x0f, 0x08, 0x05, 0x01, 0xfe, 0x0a, + 0x14, 0x0f, 0xfe, 0x01, 0xff, 0xfd, 0xff, 0x03, 0x02, 0x02, 0x03, 0x08, + 0x00, 0x06, 0x03, 0xfe, 0xfd, 0xfa, 0xf5, 0xef, 0xed, 0xf0, 0xef, 0xfe, + 0x17, 0x0d, 0x06, 0x05, 0x03, 0xfc, 0xf3, 0xef, 0xf2, 0xfa, 0xff, 0xff, + 0x00, 0x00, 0x05, 0x03, 0x0d, 0x10, 0x05, 0x00, 0x01, 0x04, 0x16, 0x14, + 0x10, 0x0f, 0x0e, 0x11, 0x0e, 0x0b, 0x05, 0x02, 0x0b, 0x16, 0x0e, 0x05, + 0x00, 0xff, 0xfc, 0x00, 0x02, 0x02, 0xff, 0xfd, 0x05, 0x05, 0x05, 0x18, + 0x18, 0x0d, 0x02, 0x03, 0x02, 0xfc, 0xf0, 0xed, 0xf5, 0xfd, 0x05, 0x06, + 0x09, 0x02, 0xf2, 0xfa, 0xfc, 0xff, 0x00, 0x02, 0x01, 0x05, 0x0b, 0x00, + 0xf9, 0xfe, 0x03, 0x01, 0xff, 0xff, 0x09, 0x08, 0xfd, 0xf6, 0xf9, 0xfc, + 0xfb, 0xf7, 0xf7, 0xf8, 0xfd, 0x07, 0x06, 0x00, 0xfc, 0xfc, 0x0e, 0x15, + 0x10, 0x08, 0x0a, 0x10, 0x18, 0x0f, 0x02, 0xff, 0x02, 0x01, 0x01, 0x07, + 0x0d, 0x0e, 0x19, 0x11, 0x0b, 0x05, 0x04, 0x01, 0x02, 0x0a, 0x03, 0xfd, + 0xff, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x00, 0x02, 0x03, 0xfd, 0xfa, + 0xf8, 0xf4, 0xfd, 0x01, 0xfb, 0xef, 0xec, 0xf4, 0xf4, 0xfc, 0x04, 0x03, + 0x0d, 0x19, 0x10, 0x02, 0xf9, 0xf4, 0xf5, 0xf6, 0xf7, 0xfb, 0x05, 0x11, + 0x24, 0x1f, 0x17, 0x0f, 0x0b, 0x09, 0x09, 0x09, 0x17, 0x12, 0x0c, 0x14, + 0x11, 0x0b, 0x08, 0x0c, 0x0d, 0x08, 0x01, 0x00, 0x06, 0x00, 0xf9, 0xf9, + 0xf9, 0xf8, 0xfa, 0xf5, 0xf0, 0xe6, 0xe0, 0xe2, 0xeb, 0xfa, 0xf9, 0x05, + 0x02, 0x00, 0xff, 0xfb, 0xf4, 0xf1, 0xef, 0xf1, 0xfd, 0x0c, 0x15, 0x13, + 0x11, 0x0b, 0x07, 0x05, 0x06, 0x09, 0x09, 0x1c, 0x28, 0x23, 0x1c, 0x1d, + 0x1d, 0x15, 0x11, 0x16, 0x0f, 0x07, 0x01, 0x06, 0x08, 0x04, 0x01, 0x05, + 0x01, 0x04, 0xff, 0xf7, 0xf0, 0xed, 0xf1, 0xf6, 0x06, 0x08, 0x06, 0x06, + 0x01, 0xf9, 0xf3, 0xee, 0xef, 0xec, 0xf3, 0xff, 0xfe, 0x01, 0x01, 0x02, + 0x09, 0x03, 0xfd, 0xfc, 0xfc, 0xfb, 0x13, 0x1a, 0x0c, 0x07, 0x04, 0x00, + 0xfc, 0xfe, 0x02, 0x0c, 0x08, 0x08, 0x0f, 0x14, 0x0b, 0x06, 0x02, 0xfc, + 0xfd, 0xfb, 0xfd, 0xfb, 0xfa, 0xf6, 0xee, 0xf8, 0x03, 0x03, 0x0f, 0x0a, + 0x06, 0x02, 0xfe, 0xfb, 0xfa, 0xff, 0x02, 0xff, 0x04, 0x0f, 0x0a, 0x06, + 0x08, 0x09, 0x0f, 0x18, 0x12, 0x12, 0x1c, 0x19, 0x16, 0x0f, 0x0d, 0x0c, + 0x0b, 0x0a, 0x18, 0x10, 0x04, 0xff, 0xfc, 0xfe, 0xfa, 0xf8, 0xfc, 0x06, + 0x06, 0xf9, 0xf6, 0xf5, 0xf1, 0xeb, 0xec, 0xf9, 0xf6, 0xf8, 0xf6, 0xf7, + 0xfb, 0xf9, 0xf6, 0xf7, 0xfc, 0x02, 0x05, 0xfd, 0x03, 0x02, 0xff, 0xfe, + 0xff, 0x05, 0x02, 0xfc, 0xfa, 0x05, 0x07, 0x06, 0x03, 0x08, 0x11, 0x1a, + 0x12, 0x0a, 0x05, 0x09, 0x0b, 0x04, 0x02, 0xfe, 0xf9, 0xf7, 0xfe, 0x0b, + 0x09, 0x02, 0x00, 0xfd, 0xf9, 0xfa, 0x09, 0x1a, 0x1b, 0x1d, 0x18, 0x16, + 0x19, 0x15, 0x0f, 0x0b, 0x04, 0xfb, 0xfa, 0x08, 0x0e, 0x0d, 0x0c, 0x05, + 0x0c, 0x14, 0x0f, 0x04, 0x05, 0x00, 0xff, 0xfd, 0xfa, 0xfe, 0xfc, 0xfb, + 0xf8, 0xf2, 0xf1, 0xf1, 0xf3, 0xf8, 0xfa, 0x04, 0xfd, 0xf7, 0xf1, 0xf2, + 0xf3, 0xee, 0xe6, 0xe2, 0xe1, 0xe5, 0xf9, 0x0b, 0x12, 0x0f, 0x08, 0x02, + 0x07, 0x06, 0xfe, 0x06, 0x07, 0x01, 0x08, 0x10, 0x0e, 0x0c, 0x0b, 0x0c, + 0x10, 0x14, 0x19, 0x26, 0x25, 0x20, 0x23, 0x1c, 0x18, 0x12, 0x0e, 0x09, + 0x07, 0x04, 0x02, 0x06, 0x00, 0xfb, 0xfc, 0xfc, 0x00, 0x00, 0xfe, 0xfa, + 0xf7, 0xf1, 0xf0, 0xf8, 0xf0, 0xee, 0xf2, 0xf7, 0xff, 0x00, 0xfe, 0xfe, + 0x02, 0xfd, 0xfa, 0xfc, 0x01, 0x00, 0x07, 0x05, 0x00, 0xfd, 0xff, 0x06, + 0x08, 0x09, 0x11, 0x0f, 0x0d, 0x0d, 0x14, 0x0e, 0x0b, 0x07, 0x00, 0x01, + 0x03, 0x04, 0x0e, 0x0a, 0x06, 0x04, 0x00, 0xfe, 0xfd, 0xfa, 0xfa, 0xf9, + 0xf1, 0xec, 0xeb, 0xeb, 0xf3, 0x02, 0x02, 0x05, 0x03, 0x02, 0x0c, 0x15, + 0x11, 0x09, 0x02, 0xfc, 0xfc, 0x0b, 0x0b, 0x02, 0xf8, 0xf9, 0xf8, 0xf8, + 0x0b, 0x23, 0x1b, 0x11, 0x0a, 0x0b, 0x0b, 0x10, 0x13, 0x12, 0x0e, 0x0b, + 0x08, 0x09, 0x09, 0x0e, 0x12, 0x01, 0xfd, 0x00, 0x00, 0xfc, 0x02, 0x02, + 0xf7, 0xf2, 0xf2, 0xf2, 0xfd, 0x00, 0xfa, 0x03, 0x00, 0xfe, 0x00, 0xff, + 0xfa, 0xef, 0xf0, 0xf1, 0xfb, 0xff, 0x00, 0x05, 0x00, 0x01, 0xfb, 0xff, + 0x1b, 0x1f, 0x18, 0x16, 0x0e, 0x0c, 0x0d, 0x06, 0x06, 0x0f, 0x0e, 0x09, + 0x02, 0x04, 0x02, 0x03, 0x08, 0x09, 0x07, 0x01, 0xfa, 0xf9, 0xf6, 0xf0, + 0xee, 0xec, 0xea, 0xec, 0xfc, 0x03, 0x12, 0x16, 0x0a, 0x04, 0x00, 0xfc, + 0xfa, 0xf8, 0xfb, 0x09, 0x0b, 0x01, 0xfe, 0xfd, 0xfe, 0xf9, 0xff, 0x13, + 0x1b, 0x1b, 0x1f, 0x29, 0x1f, 0x15, 0x0f, 0x06, 0x01, 0x08, 0x0c, 0x09, + 0x08, 0x02, 0x01, 0xff, 0xff, 0x07, 0x04, 0xf8, 0xfc, 0xfd, 0xf9, 0xfa, + 0xf7, 0xf4, 0xf4, 0xf7, 0x06, 0x0b, 0x0c, 0x05, 0x00, 0x03, 0xff, 0xfd, + 0xff, 0xfe, 0x06, 0x12, 0x0a, 0x03, 0xff, 0xfd, 0xfb, 0xfe, 0x0c, 0x09, + 0x07, 0x07, 0xfe, 0xfd, 0x02, 0x02, 0xfc, 0xfb, 0xfb, 0x00, 0x05, 0x08, + 0x05, 0x05, 0x04, 0x03, 0x01, 0x03, 0xfd, 0xf3, 0xec, 0xe7, 0xe5, 0xe3, + 0xe2, 0xed, 0xf9, 0x0d, 0x1e, 0x19, 0x0b, 0x06, 0x13, 0x15, 0x0e, 0x0b, + 0x08, 0x05, 0x0e, 0x11, 0x0b, 0x05, 0x06, 0x06, 0x0e, 0x24, 0x28, 0x28, + 0x2a, 0x26, 0x1e, 0x1a, 0x18, 0x14, 0x10, 0x06, 0xff, 0x02, 0xfd, 0xfb, + 0xf9, 0xf3, 0xf2, 0xf6, 0xf7, 0xf2, 0xf9, 0xfb, 0xec, 0xe8, 0xe4, 0xe0, + 0xe1, 0xe1, 0xe6, 0x00, 0x00, 0xfa, 0xf4, 0xf2, 0xf3, 0xef, 0xf3, 0xfe, + 0xfe, 0x04, 0x0c, 0x05, 0x00, 0x08, 0x0b, 0x0c, 0x15, 0x0d, 0x07, 0x0e, + 0x14, 0x11, 0x10, 0x17, 0x16, 0x18, 0x1b, 0x17, 0x11, 0x0d, 0x09, 0x05, + 0xff, 0x05, 0x06, 0x03, 0x02, 0xfe, 0xf9, 0xf3, 0xf6, 0xf9, 0xf3, 0xf2, + 0xf9, 0xfd, 0x16, 0x28, 0x1b, 0x12, 0x0c, 0x06, 0xff, 0xfd, 0xff, 0xff, + 0xfe, 0x07, 0x06, 0xff, 0xfe, 0x01, 0x03, 0x16, 0x15, 0x08, 0x01, 0x03, + 0x02, 0x07, 0x09, 0x05, 0x02, 0x01, 0xfd, 0xfc, 0xf9, 0xf5, 0xf9, 0xfc, + 0xff, 0x08, 0x0a, 0x08, 0x00, 0xfa, 0xf4, 0xeb, 0xe4, 0xe7, 0xf0, 0xed, + 0xee, 0xfb, 0x04, 0x06, 0x03, 0x00, 0xff, 0xfd, 0xfc, 0xfc, 0x04, 0x0d, + 0x09, 0x0a, 0x05, 0x05, 0x05, 0x08, 0x18, 0x17, 0x0e, 0x0c, 0x0d, 0x10, + 0x0d, 0x0f, 0x12, 0x12, 0x1b, 0x1d, 0x12, 0x0e, 0x0b, 0x0b, 0x11, 0x0e, + 0x0d, 0x07, 0x04, 0x02, 0xfd, 0xf8, 0xf7, 0xf4, 0xf0, 0xf2, 0xfa, 0xfc, + 0x07, 0x05, 0x08, 0x03, 0xfc, 0xfe, 0xfe, 0xfd, 0xfc, 0xf4, 0xf3, 0xf3, + 0xf5, 0xfa, 0xf5, 0xf0, 0xf0, 0x03, 0x14, 0x11, 0x0a, 0x08, 0x0c, 0x09, + 0x07, 0x0d, 0x09, 0x06, 0x05, 0x07, 0x06, 0x04, 0x02, 0xff, 0xfb, 0xfa, + 0xfc, 0x05, 0x05, 0xfe, 0xf9, 0xf9, 0xfb, 0x02, 0xfe, 0xf9, 0xfe, 0x07, + 0x01, 0xff, 0x0a, 0x0a, 0x0b, 0x11, 0x11, 0x06, 0x03, 0x0c, 0x07, 0x00, + 0x03, 0x05, 0x03, 0xfe, 0x0a, 0x13, 0x0d, 0x0a, 0x04, 0x04, 0x05, 0x01, + 0x04, 0x06, 0x14, 0x16, 0x12, 0x0e, 0x0f, 0x0d, 0x06, 0x00, 0xf8, 0xf9, + 0xfe, 0x01, 0xfe, 0xf5, 0xf6, 0xf3, 0xf1, 0xf6, 0xf4, 0xfc, 0x08, 0x02, + 0xf2, 0xee, 0xfb, 0x02, 0x03, 0xfd, 0xf8, 0xf9, 0xfb, 0xfa, 0xfb, 0xfb, + 0x03, 0x0c, 0x0f, 0x15, 0x1a, 0x18, 0x13, 0x12, 0x10, 0x10, 0x0d, 0x0d, + 0x0e, 0x0f, 0x10, 0x10, 0x0d, 0x0a, 0x0b, 0x07, 0x04, 0x03, 0x0c, 0x0f, + 0x08, 0xff, 0xf6, 0xf3, 0xf4, 0xf5, 0xec, 0xe1, 0xea, 0xf2, 0xf9, 0xf4, + 0xf1, 0xf7, 0xfa, 0xf6, 0xf8, 0xf6, 0xf8, 0x03, 0x03, 0x00, 0xf8, 0xfe, + 0x0f, 0x0c, 0x0d, 0x15, 0x0c, 0x0e, 0x16, 0x11, 0x13, 0x25, 0x21, 0x14, + 0x14, 0x17, 0x17, 0x16, 0x0d, 0x0b, 0x0d, 0x0c, 0x0a, 0x06, 0x06, 0x02, + 0xf3, 0xe8, 0xea, 0xed, 0xec, 0xeb, 0xf9, 0x07, 0x04, 0x08, 0x03, 0xfb, + 0xf6, 0x05, 0x03, 0xff, 0xfa, 0xfa, 0x00, 0x05, 0x06, 0xff, 0xf8, 0xf8, + 0xf8, 0xfd, 0x0c, 0x0a, 0x0c, 0x0a, 0x07, 0x06, 0x08, 0x08, 0x0b, 0x08, + 0x02, 0x02, 0x06, 0x03, 0x07, 0x10, 0x09, 0x04, 0x00, 0xff, 0xfd, 0xff, + 0xfe, 0xf5, 0xf4, 0xf6, 0xf6, 0xfc, 0x01, 0x04, 0x03, 0xfd, 0xf6, 0xf4, + 0xf7, 0x01, 0x0a, 0x10, 0x09, 0x0b, 0x10, 0x0f, 0x07, 0x08, 0x08, 0x01, + 0x02, 0x13, 0x14, 0x0f, 0x0f, 0x0e, 0x0f, 0x17, 0x15, 0x15, 0x14, 0x10, + 0x07, 0x07, 0x04, 0x06, 0x04, 0x03, 0x04, 0x02, 0xfb, 0xfa, 0xfb, 0xf9, + 0xf7, 0xfc, 0xfc, 0xf6, 0xfb, 0xfb, 0xf7, 0xfa, 0xf6, 0xf0, 0xed, 0xeb, + 0xee, 0xf4, 0xf9, 0xf9, 0xfe, 0xff, 0xfe, 0xf9, 0xf4, 0xf5, 0xfc, 0x0e, + 0x1a, 0x16, 0x0d, 0x11, 0x15, 0x10, 0x0f, 0x09, 0x07, 0x0a, 0x07, 0x06, + 0x0b, 0x0b, 0x0a, 0x0b, 0x08, 0x03, 0x02, 0x00, 0x03, 0x04, 0x06, 0x02, + 0xfd, 0xfb, 0xf8, 0x02, 0x02, 0xfe, 0x05, 0x0f, 0x0d, 0x0c, 0x0f, 0x06, + 0x07, 0x0c, 0x0b, 0x0c, 0x12, 0x0d, 0x06, 0x00, 0x00, 0xfe, 0xfe, 0x0a, + 0x0f, 0x00, 0xfa, 0xf4, 0xf7, 0x00, 0x02, 0x09, 0x06, 0x07, 0x05, 0x03, + 0x03, 0x00, 0x00, 0xfe, 0xfe, 0xfd, 0xfa, 0xf8, 0xfb, 0xfa, 0xfa, 0xf8, + 0xf5, 0xfa, 0x01, 0xfe, 0xfb, 0xfa, 0xfd, 0xff, 0xfb, 0xfa, 0xf8, 0xf2, + 0xf6, 0x09, 0x0e, 0x11, 0x0b, 0x06, 0x07, 0x03, 0xff, 0x01, 0x00, 0x14, + 0x12, 0x0b, 0x06, 0x05, 0x0e, 0x13, 0x14, 0x16, 0x10, 0x0e, 0x0d, 0x0a, + 0x0d, 0x0b, 0x0f, 0x18, 0x17, 0x0e, 0x09, 0x0b, 0x0c, 0x07, 0x05, 0xfc, + 0x02, 0x00, 0xfa, 0xf6, 0xf6, 0xf6, 0xf6, 0xf9, 0xf5, 0xf4, 0xed, 0xe7, + 0xef, 0xf7, 0xf7, 0xfb, 0xf9, 0xf2, 0xed, 0xe8, 0xeb, 0xf3, 0x0d, 0x16, + 0x10, 0x11, 0x16, 0x17, 0x14, 0x10, 0x09, 0x08, 0x0c, 0x0c, 0x09, 0x08, + 0x07, 0x09, 0x08, 0x0a, 0x06, 0x02, 0x02, 0x03, 0xfe, 0xff, 0x03, 0x13, + 0x12, 0x06, 0xff, 0xff, 0x01, 0x01, 0xff, 0x00, 0xfe, 0xfa, 0xf3, 0xf6, + 0x02, 0x0d, 0x09, 0x05, 0x02, 0xfe, 0xfd, 0xfb, 0xf9, 0xff, 0x06, 0x00, + 0x00, 0x0b, 0x0d, 0x07, 0x07, 0x08, 0x15, 0x11, 0x09, 0x0c, 0x0d, 0x0e, + 0x0c, 0x0c, 0x09, 0x07, 0xff, 0xfc, 0xfd, 0xfc, 0xfe, 0x01, 0x0b, 0x08, + 0x08, 0xfb, 0xf7, 0xf8, 0xf5, 0xee, 0xec, 0xf5, 0xfc, 0xf4, 0xf3, 0xfc, + 0x09, 0x0b, 0x06, 0x02, 0x00, 0xfd, 0xfe, 0xff, 0x02, 0x0e, 0x09, 0x05, + 0x07, 0x0c, 0x10, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0e, 0x0e, 0x12, 0x0e, + 0x0b, 0x13, 0x14, 0x0a, 0x06, 0x04, 0x03, 0x00, 0x05, 0x08, 0xfd, 0xf7, + 0xf3, 0xf3, 0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xef, 0xe8, 0xe9, 0xf1, 0xf7, + 0xfa, 0x00, 0xfd, 0xfd, 0x06, 0x04, 0x00, 0x03, 0x18, 0x17, 0x09, 0x10, + 0x1f, 0x1c, 0x13, 0x14, 0x15, 0x10, 0x0b, 0x0a, 0x0c, 0x0f, 0x11, 0x0e, + 0x0d, 0x07, 0xfe, 0xfb, 0xfa, 0xf6, 0xf5, 0xff, 0x04, 0x08, 0x03, 0xfc, + 0xfd, 0x06, 0xff, 0xfb, 0xff, 0xfe, 0xfd, 0xf9, 0xf4, 0xf9, 0xfd, 0xff, + 0x05, 0x07, 0x03, 0x00, 0xff, 0xfc, 0xfc, 0x03, 0x09, 0x02, 0xff, 0x07, + 0x13, 0x19, 0x0b, 0x07, 0x08, 0x07, 0x07, 0x04, 0x03, 0x04, 0x04, 0x04, + 0xff, 0xff, 0xfe, 0xfd, 0xf8, 0xf6, 0x06, 0x08, 0x01, 0xfc, 0x01, 0x01, + 0xfb, 0xf9, 0xf7, 0xf9, 0xff, 0x05, 0xfe, 0xfc, 0x05, 0x09, 0x05, 0x06, + 0x07, 0x0e, 0x06, 0x05, 0x06, 0x02, 0x04, 0x0e, 0x0d, 0x0e, 0x0f, 0x13, + 0x14, 0x10, 0x05, 0x04, 0x07, 0x06, 0x0a, 0x09, 0x07, 0x14, 0x0f, 0x0b, + 0x0a, 0x09, 0x07, 0x01, 0xfe, 0x04, 0x06, 0x00, 0xfb, 0xfb, 0xfa, 0xf8, + 0xf6, 0xf5, 0xf4, 0xf3, 0xf1, 0xef, 0xef, 0xf6, 0xf9, 0xf3, 0xf1, 0xef, + 0xfd, 0x0a, 0xfb, 0xfa, 0x01, 0x05, 0x0d, 0x11, 0x09, 0x0d, 0x10, 0x11, + 0x0b, 0x07, 0x07, 0x09, 0x0b, 0x0c, 0x09, 0x06, 0x06, 0x0a, 0x0a, 0x05, + 0x02, 0x00, 0x00, 0x00, 0x06, 0x12, 0x0f, 0x08, 0x08, 0x09, 0x07, 0x04, + 0x02, 0x01, 0x01, 0x04, 0x01, 0x02, 0x08, 0x07, 0x01, 0xfd, 0xfd, 0x02, + 0x07, 0x08, 0xff, 0xf8, 0xf4, 0xf6, 0x02, 0x06, 0x0a, 0x04, 0x02, 0x05, + 0x0e, 0x0a, 0x06, 0x08, 0x05, 0x00, 0x01, 0x03, 0x01, 0xfe, 0xfe, 0xfd, + 0xfc, 0xfd, 0xfd, 0x07, 0x09, 0x01, 0xfb, 0xfa, 0xfe, 0x01, 0x00, 0x00, + 0xfc, 0xff, 0x00, 0xf9, 0xfb, 0xff, 0x00, 0xfe, 0xfe, 0xfd, 0x00, 0x02, + 0x00, 0x00, 0xfb, 0xfc, 0xfe, 0x09, 0x16, 0x13, 0x0c, 0x09, 0x09, 0x0a, + 0x0d, 0x0c, 0x0c, 0x0c, 0x14, 0x17, 0x18, 0x1b, 0x19, 0x12, 0x0f, 0x0e, + 0x0c, 0x06, 0x09, 0x0a, 0x06, 0x01, 0x02, 0xff, 0xfb, 0xfc, 0xfd, 0xfc, + 0xfb, 0xf5, 0xf0, 0xe8, 0xe6, 0xea, 0xec, 0xee, 0xee, 0xeb, 0xf4, 0xf3, + 0xf8, 0xf9, 0xfc, 0x00, 0x06, 0x19, 0x0f, 0x0e, 0x0f, 0x0a, 0x10, 0x0e, + 0x0f, 0x0e, 0x0e, 0x0d, 0x0b, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0b, 0x04, + 0x06, 0x0c, 0x06, 0x0a, 0x0b, 0x09, 0x09, 0x05, 0x01, 0x01, 0xfb, 0xf7, + 0xf6, 0xf6, 0xf7, 0xfb, 0xfe, 0xfb, 0xf9, 0xfa, 0xfa, 0xfa, 0xf7, 0xf5, + 0xfa, 0xf6, 0xf5, 0xfd, 0x0f, 0x11, 0x0a, 0x10, 0x08, 0x03, 0x09, 0x0c, + 0x0f, 0x0d, 0x0e, 0x10, 0x13, 0x11, 0x0d, 0x06, 0x04, 0x04, 0x01, 0xfe, + 0x06, 0x0d, 0x09, 0x05, 0xf9, 0xf2, 0xf5, 0xfa, 0xff, 0x05, 0x00, 0x00, + 0xff, 0xfc, 0xfe, 0x03, 0xfe, 0xfc, 0xf7, 0xf3, 0xf4, 0xf6, 0xf8, 0xfd, + 0xfd, 0xf8, 0xff, 0x0c, 0x1b, 0x19, 0x12, 0x09, 0x03, 0x06, 0x08, 0x0b, + 0x0e, 0x0d, 0x04, 0x0b, 0x1d, 0x14, 0x0c, 0x0b, 0x10, 0x0a, 0x07, 0x0c, + 0x10, 0x05, 0x03, 0xfe, 0xfa, 0xf9, 0xf7, 0xf7, 0xf5, 0xf5, 0xf2, 0xf3, + 0xf4, 0xf5, 0xfa, 0xfb, 0xfc, 0xfc, 0xf6, 0xf7, 0xf1, 0xf3, 0xf9, 0x00, + 0xff, 0x01, 0x07, 0x0a, 0x12, 0x0c, 0x12, 0x13, 0x0f, 0x11, 0x0e, 0x0a, + 0x11, 0x14, 0x11, 0x10, 0x0b, 0xfd, 0xf7, 0xfe, 0x03, 0xff, 0xff, 0x06, + 0x0f, 0x0c, 0x07, 0x07, 0x05, 0xff, 0xfe, 0x02, 0x02, 0x04, 0x00, 0xfe, + 0xfc, 0xfe, 0x02, 0x03, 0x02, 0xfe, 0xfb, 0xfb, 0xfb, 0xfb, 0xfe, 0x00, + 0x06, 0x11, 0x07, 0x11, 0x12, 0x0b, 0x0b, 0x09, 0x09, 0x07, 0x05, 0x02, + 0x02, 0x02, 0x04, 0x01, 0xff, 0xfd, 0xfa, 0xf7, 0xf4, 0xf9, 0x05, 0x03, + 0xfc, 0xf8, 0xf6, 0xf8, 0xfb, 0xfb, 0x00, 0xf7, 0xfa, 0x0c, 0x09, 0x04, + 0x04, 0x02, 0x04, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x05, + 0x0d, 0x0b, 0x0a, 0x1d, 0x1c, 0x15, 0x05, 0x05, 0x07, 0x11, 0x16, 0x15, + 0x15, 0x13, 0x0e, 0x0f, 0x0a, 0x08, 0x09, 0x05, 0x00, 0x07, 0x0b, 0x02, + 0x00, 0xfe, 0xf9, 0xf7, 0xf7, 0xf9, 0xfc, 0xfd, 0xfd, 0xf7, 0xed, 0xef, + 0xf5, 0xf2, 0xf1, 0xea, 0xe5, 0xef, 0xf8, 0xf5, 0xf1, 0xf5, 0xfd, 0x02, + 0xfe, 0xff, 0x0a, 0x14, 0x0b, 0x11, 0x11, 0x0e, 0x0b, 0x0b, 0x08, 0x0b, + 0x0f, 0x11, 0x0f, 0x0e, 0x0e, 0x15, 0x1b, 0x11, 0x08, 0x10, 0x10, 0x10, + 0x0c, 0x07, 0x08, 0x05, 0x01, 0xff, 0xff, 0x00, 0x02, 0x00, 0xfa, 0xfa, + 0xfe, 0x01, 0x01, 0x01, 0xfe, 0xf9, 0xf0, 0xe6, 0xe8, 0xf0, 0xfc, 0xf7, + 0xf5, 0xfa, 0x14, 0x1c, 0x0d, 0x06, 0x0d, 0x0d, 0x08, 0x09, 0x0d, 0x0f, + 0x0a, 0x06, 0x02, 0x00, 0x00, 0x00, 0xfe, 0xfd, 0x0b, 0x0d, 0x04, 0x02, + 0x01, 0x05, 0x0e, 0x05, 0x00, 0x01, 0x01, 0x07, 0x03, 0xfd, 0xfc, 0xfe, + 0xfc, 0xfb, 0xfa, 0xf5, 0xf4, 0xf4, 0xf2, 0xef, 0xf0, 0xff, 0x01, 0xfd, + 0x00, 0x04, 0x11, 0x0f, 0x09, 0x0c, 0x0b, 0x03, 0x00, 0x0d, 0x14, 0x22, + 0x1d, 0x14, 0x15, 0x14, 0x10, 0x0b, 0x0d, 0x12, 0x16, 0x0f, 0x0a, 0x06, + 0x01, 0x02, 0x03, 0xfd, 0xfd, 0x01, 0x05, 0xfb, 0xef, 0xef, 0x00, 0x05, + 0xfd, 0xf5, 0xef, 0xe8, 0xe9, 0xe7, 0xe8, 0xf2, 0xfb, 0x00, 0xfa, 0xf7, + 0xf8, 0xfd, 0x0e, 0x08, 0x0a, 0x0f, 0x0f, 0x11, 0x16, 0x16, 0x10, 0x09, + 0x07, 0x05, 0x04, 0x01, 0xfa, 0xfd, 0x03, 0x14, 0x1e, 0x17, 0x0e, 0x07, + 0x02, 0x02, 0x02, 0xff, 0x03, 0x04, 0x01, 0xfc, 0xfb, 0xfe, 0xfe, 0xfb, + 0xfc, 0xf7, 0xf9, 0xfd, 0xfd, 0xfe, 0x04, 0x11, 0x0d, 0x07, 0x04, 0x01, + 0x00, 0x0d, 0x17, 0x11, 0x11, 0x0f, 0x0d, 0x0c, 0x09, 0x06, 0x06, 0x03, + 0xfd, 0xfa, 0xfb, 0xfc, 0xfa, 0xfa, 0x02, 0x09, 0x02, 0xf0, 0xeb, 0xec, + 0xf1, 0xf2, 0xf7, 0xfa, 0x03, 0x10, 0x0b, 0x05, 0x02, 0x03, 0x00, 0xff, + 0xff, 0xfb, 0xfb, 0xfc, 0xfe, 0xfc, 0x01, 0x0a, 0x0b, 0x07, 0x07, 0x06, + 0x04, 0x17, 0x20, 0x24, 0x20, 0x16, 0x17, 0x14, 0x0f, 0x15, 0x0f, 0x0a, + 0x06, 0x06, 0x05, 0x03, 0x00, 0xfe, 0x05, 0x0c, 0x04, 0xfa, 0xf5, 0xf4, + 0xf8, 0xf9, 0xf9, 0xfe, 0xf7, 0xf2, 0xf4, 0xf3, 0xef, 0xed, 0xee, 0xf0, + 0xef, 0xf8, 0xff, 0xfd, 0xf6, 0xf5, 0x00, 0x04, 0x02, 0xfe, 0xfc, 0xfe, + 0x04, 0x17, 0x14, 0x14, 0x1e, 0x21, 0x1c, 0x18, 0x14, 0x0f, 0x0c, 0x0d, + 0x13, 0x14, 0x0f, 0x0b, 0x02, 0x02, 0x13, 0x12, 0x06, 0x02, 0x04, 0x02, + 0x01, 0xfe, 0x00, 0xfe, 0xfa, 0xf8, 0xf9, 0xfc, 0x00, 0xfd, 0xfa, 0xf9, + 0xf4, 0xf3, 0xf3, 0xf2, 0xf3, 0xf8, 0xf9, 0xfe, 0x01, 0xfd, 0x01, 0x07, + 0x08, 0x17, 0x13, 0x0c, 0x0e, 0x08, 0x08, 0x0a, 0x0a, 0x05, 0x00, 0x00, + 0xfe, 0xfc, 0xfc, 0xfd, 0xf9, 0xfe, 0x10, 0x14, 0x09, 0x08, 0x07, 0x04, + 0x02, 0x04, 0x06, 0x0c, 0x0c, 0x05, 0x00, 0x00, 0x00, 0xfe, 0xfc, 0xf8, + 0xf8, 0xf5, 0xf1, 0xf3, 0xfb, 0x07, 0x08, 0x08, 0x02, 0xfd, 0xfe, 0xfc, + 0xf8, 0x09, 0x0b, 0x0c, 0x12, 0x0d, 0x09, 0x11, 0x1a, 0x15, 0x0f, 0x0c, + 0x09, 0x04, 0x02, 0x06, 0x09, 0x0b, 0x12, 0x0b, 0x06, 0x08, 0x07, 0x05, + 0x03, 0x01, 0xfa, 0xfc, 0x02, 0x02, 0x03, 0xfd, 0xf8, 0xf4, 0xf5, 0xf2, + 0xf0, 0xe7, 0xe6, 0xe7, 0xef, 0xf8, 0xfb, 0xfc, 0xf9, 0xf5, 0xf3, 0xf4, + 0xfa, 0x0f, 0x15, 0x1a, 0x16, 0x0f, 0x0c, 0x08, 0x09, 0x04, 0x04, 0x04, + 0x09, 0x07, 0x03, 0x05, 0x11, 0x21, 0x1f, 0x12, 0x0c, 0x0a, 0x08, 0x08, + 0x0b, 0x05, 0x00, 0x00, 0x02, 0x02, 0x08, 0x0a, 0x00, 0xfc, 0xfd, 0xfc, + 0x01, 0xfd, 0xf7, 0x07, 0x0a, 0x06, 0x06, 0x05, 0x03, 0x03, 0xfa, 0xf6, + 0x04, 0x19, 0x13, 0x0c, 0x09, 0x05, 0x01, 0x02, 0x01, 0xfd, 0xfe, 0xfc, + 0xf7, 0xf5, 0xf3, 0xf1, 0xf4, 0x00, 0x06, 0xfb, 0xfa, 0xfb, 0xf9, 0xf9, + 0xf7, 0xff, 0x0b, 0x0a, 0x06, 0xfd, 0xfd, 0xff, 0xfd, 0xff, 0xfe, 0xf9, + 0xf5, 0xf7, 0xff, 0x0a, 0x0b, 0x09, 0x06, 0x06, 0x0e, 0x12, 0x06, 0x05, + 0x1a, 0x2c, 0x29, 0x24, 0x23, 0x1c, 0x12, 0x0b, 0x07, 0x08, 0x0a, 0x0a, + 0x07, 0x03, 0x02, 0x02, 0x02, 0x07, 0x0b, 0x0a, 0x05, 0x00, 0x00, 0xff, + 0xfb, 0xf7, 0xed, 0xe4, 0xea, 0xf2, 0xf4, 0xec, 0xe8, 0xe8, 0xed, 0xf7, + 0xf3, 0xef, 0xf3, 0xf9, 0xfd, 0xff, 0x02, 0x02, 0xfd, 0xfa, 0xff, 0x08, + 0x13, 0x1d, 0x18, 0x1d, 0x1b, 0x1e, 0x1b, 0x13, 0x0d, 0x16, 0x11, 0x0d, + 0x0b, 0x05, 0x04, 0x06, 0x00, 0x04, 0x0b, 0x0b, 0x0a, 0x05, 0x00, 0xff, + 0xfd, 0xf9, 0xfd, 0xfe, 0xfa, 0xfc, 0xfa, 0xf6, 0xf8, 0xf6, 0xf1, 0xeb, + 0xf1, 0xf8, 0x06, 0x0b, 0x03, 0x04, 0x05, 0x08, 0x10, 0x08, 0x04, 0x06, + 0x0e, 0x1a, 0x12, 0x0e, 0x0e, 0x0b, 0x09, 0x09, 0x05, 0x05, 0x04, 0xff, + 0xfb, 0xfe, 0x03, 0x02, 0xf4, 0x00, 0x15, 0x0d, 0x08, 0x05, 0x02, 0x00, + 0xfc, 0xf5, 0xf8, 0x04, 0x04, 0x01, 0xfc, 0xf6, 0xf7, 0xf6, 0xf5, 0xf4, + 0xf3, 0xfa, 0x07, 0x02, 0x03, 0x07, 0x06, 0xfd, 0xfa, 0x01, 0x06, 0x03, + 0x09, 0x12, 0x0a, 0x0a, 0x10, 0x16, 0x0c, 0x0c, 0x0a, 0x09, 0x0a, 0x05, + 0x04, 0x05, 0x08, 0x07, 0x08, 0x0d, 0x14, 0x0a, 0x07, 0x08, 0x06, 0x03, + 0xff, 0xfe, 0x00, 0x07, 0x0b, 0x04, 0xfe, 0xfc, 0xfb, 0xf3, 0xe7, 0xe8, + 0xee, 0xf7, 0xfc, 0xf9, 0xf7, 0xff, 0x01, 0xfb, 0xfc, 0x02, 0x03, 0x02, + 0x0a, 0x13, 0x13, 0x13, 0x0c, 0x07, 0xff, 0x00, 0x02, 0x01, 0xff, 0xfd, + 0xfe, 0x02, 0x0f, 0x0d, 0x0b, 0x11, 0x18, 0x0f, 0x08, 0x08, 0x07, 0x04, + 0x02, 0x04, 0x01, 0x00, 0x03, 0x03, 0xff, 0xff, 0x06, 0x02, 0xfd, 0xfe, + 0x08, 0x0d, 0x0a, 0x0a, 0x09, 0x03, 0xff, 0xfc, 0xff, 0x01, 0x00, 0xff, + 0x06, 0x10, 0x0b, 0x07, 0x04, 0x02, 0x02, 0xfc, 0xfb, 0xfb, 0xf6, 0xf3, + 0xf1, 0xf0, 0xf4, 0xf6, 0xf8, 0x02, 0x0d, 0x04, 0xfd, 0xfb, 0x01, 0x0b, + 0x04, 0x00, 0x06, 0x04, 0x01, 0x00, 0x00, 0x01, 0x00, 0xff, 0xfe, 0x00, + 0x05, 0x0a, 0x10, 0x10, 0x14, 0x19, 0x13, 0x07, 0x07, 0x08, 0x0c, 0x0d, + 0x1c, 0x1f, 0x13, 0x11, 0x11, 0x0d, 0x0b, 0x07, 0x03, 0x00, 0x04, 0x06, + 0x02, 0x02, 0x00, 0xfc, 0xfc, 0x04, 0x0d, 0xff, 0xf8, 0xfa, 0xf8, 0xf7, + 0xf5, 0xf9, 0xf1, 0xea, 0xef, 0xeb, 0xe8, 0xef, 0xf7, 0xee, 0xee, 0xf1, + 0xf1, 0xf8, 0x01, 0xff, 0xff, 0x04, 0x05, 0x07, 0x0b, 0x06, 0x03, 0x05, + 0x17, 0x1d, 0x1f, 0x1d, 0x19, 0x0f, 0x12, 0x1a, 0x11, 0x0e, 0x10, 0x0d, + 0x0d, 0x0e, 0x0a, 0x06, 0x07, 0x14, 0x12, 0x03, 0x00, 0x04, 0x02, 0x00, + 0xfe, 0xfc, 0xfb, 0x00, 0xff, 0xfb, 0xfb, 0xf8, 0xed, 0xeb, 0xf5, 0xf9, + 0xf7, 0xfb, 0xff, 0xff, 0x04, 0x0e, 0x0a, 0x0a, 0x04, 0x00, 0x00, 0x04, + 0x15, 0x13, 0x0e, 0x0e, 0x0b, 0x07, 0x04, 0x01, 0xfd, 0xfd, 0xff, 0x04, + 0x02, 0xfc, 0xfa, 0x00, 0x03, 0x0c, 0x08, 0xfe, 0x00, 0x03, 0x00, 0xf8, + 0xf1, 0xf5, 0x00, 0x00, 0xfe, 0xfc, 0xfc, 0xfb, 0xf6, 0xf6, 0xf8, 0xfc, + 0x01, 0x06, 0x10, 0x0c, 0x05, 0x03, 0x06, 0x06, 0x00, 0xfd, 0x01, 0x09, + 0x1c, 0x20, 0x23, 0x16, 0x11, 0x0e, 0x0d, 0x08, 0x08, 0x0d, 0x0e, 0x0e, + 0x0a, 0x0c, 0x0a, 0x09, 0x08, 0x0f, 0x07, 0x01, 0x0c, 0x07, 0xf8, 0xf5, + 0xff, 0x00, 0xfc, 0xfc, 0xfd, 0xfb, 0xf8, 0xf2, 0xeb, 0xec, 0xee, 0xee, + 0xee, 0xf6, 0xfe, 0xf9, 0xfa, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfc, 0x03, + 0x12, 0x0c, 0x0a, 0x08, 0x08, 0x00, 0xfc, 0xfe, 0xfd, 0x00, 0x0e, 0x11, + 0x08, 0x08, 0x0c, 0x0a, 0x10, 0x14, 0x0c, 0x02, 0x04, 0x0a, 0x0a, 0x06, + 0x04, 0xff, 0xff, 0x07, 0x0b, 0x07, 0x00, 0xff, 0x02, 0x0b, 0x09, 0x07, + 0x09, 0x11, 0x14, 0x0e, 0x07, 0x03, 0x02, 0xfe, 0xff, 0x01, 0x01, 0x13, + 0x15, 0x08, 0x05, 0x06, 0x04, 0x00, 0xfb, 0xf9, 0xf9, 0xf9, 0xf3, 0xe9, + 0xe8, 0xed, 0xec, 0xec, 0xfe, 0x00, 0xf8, 0x04, 0x06, 0x01, 0xfd, 0xfa, + 0xfb, 0x00, 0xff, 0x01, 0x00, 0x00, 0x05, 0x05, 0x02, 0x01, 0x00, 0x03, + 0x06, 0x05, 0x11, 0x15, 0x13, 0x18, 0x11, 0x09, 0x09, 0x0d, 0x16, 0x25, + 0x19, 0x0d, 0x0a, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x05, 0x04, 0x04, 0x02, + 0x00, 0x00, 0x00, 0x04, 0x0c, 0x04, 0xfc, 0xf5, 0xf0, 0xf4, 0xf6, 0xf5, + 0xf3, 0xf2, 0xf4, 0xfa, 0x04, 0x00, 0xfb, 0xf6, 0xf4, 0xf4, 0xf2, 0xf2, + 0xf8, 0xfd, 0x07, 0x0f, 0x10, 0x0c, 0x06, 0x00, 0x01, 0x04, 0x0b, 0x13, + 0x0c, 0x14, 0x1c, 0x15, 0x0e, 0x10, 0x10, 0x12, 0x12, 0x0e, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x0c, 0x0e, 0x05, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0xfe, 0xfa, 0xfa, 0xfa, 0xfa, 0xf8, 0xf4, 0xf0, 0xf0, 0xf0, 0xf2, 0xf6, + 0x00, 0x0a, 0x0a, 0x0a, 0x0b, 0x0c, 0x05, 0x00, 0x00, 0x05, 0x15, 0x1a, + 0x16, 0x10, 0x0c, 0x08, 0x06, 0x04, 0x00, 0xff, 0x00, 0x00, 0x02, 0x06, + 0x01, 0x00, 0x06, 0x16, 0x10, 0x0a, 0xfe, 0xf6, 0xf6, 0xfc, 0xf8, 0xf9, + 0x00, 0x00, 0xfe, 0x00, 0x00, 0x02, 0x02, 0x02, 0xfd, 0xf9, 0xfb, 0x00, + 0xf8, 0xec, 0xf6, 0x00, 0x04, 0x04, 0x00, 0x00, 0x02, 0x16, 0x29, 0x20, + 0x18, 0x12, 0x0e, 0x0c, 0x08, 0x0a, 0x0d, 0x0b, 0x0a, 0x0b, 0x0a, 0x04, + 0x00, 0x00, 0x08, 0x07, 0x02, 0x00, 0x00, 0x03, 0x00, 0x06, 0x04, 0x00, + 0xff, 0x00, 0xf8, 0xf6, 0xf6, 0xf3, 0xf0, 0xec, 0xee, 0xf0, 0xf5, 0xf9, + 0xf6, 0xf6, 0x00, 0x08, 0x08, 0x01, 0xfc, 0xfd, 0xfe, 0x0a, 0x12, 0x0a, + 0x02, 0x07, 0x08, 0x06, 0x08, 0x12, 0x1c, 0x14, 0x0e, 0x0c, 0x07, 0x00, + 0x00, 0x07, 0x13, 0x12, 0x10, 0x0a, 0x0a, 0x0c, 0x08, 0x06, 0x04, 0x00, + 0x00, 0xf8, 0xf0, 0x04, 0x0e, 0x0b, 0x04, 0x00, 0x00, 0x03, 0x04, 0x00, + 0xff, 0xfa, 0x00, 0x03, 0x02, 0x00, 0x00, 0xfe, 0x02, 0x14, 0x10, 0x0a, + 0x06, 0x02, 0x00, 0xfe, 0xfc, 0xfa, 0xf4, 0xee, 0xe8, 0xea, 0xed, 0xec, + 0xf2, 0x02, 0x08, 0x0b, 0x00, 0xfc, 0xff, 0x00, 0xff, 0xff, 0x02, 0x05, + 0x04, 0x01, 0x05, 0x0c, 0x0d, 0x04, 0x00, 0xff, 0x00, 0x02, 0x04, 0x04, + 0x0c, 0x0e, 0x1a, 0x1e, 0x17, 0x16, 0x12, 0x10, 0x18, 0x23, 0x14, 0x0e, + 0x0c, 0x0a, 0x0c, 0x0c, 0x0c, 0x0a, 0x06, 0x08, 0x08, 0x04, 0xfc, 0xf8, + 0x00, 0x04, 0xf8, 0xea, 0xe9, 0xec, 0xf3, 0xf4, 0xf2, 0xf6, 0xf8, 0x05, + 0x01, 0xfa, 0xfa, 0xfa, 0xf6, 0xf2, 0xf0, 0xf0, 0xf0, 0xf6, 0xf8, 0xfc, + 0x01, 0xff, 0x00, 0xfe, 0x00, 0x05, 0x04, 0x02, 0x15, 0x1f, 0x24, 0x1c, + 0x16, 0x16, 0x12, 0x10, 0x0e, 0x0e, 0x0a, 0x04, 0x02, 0x00, 0xfe, 0x04, + 0x12, 0x0a, 0x08, 0x06, 0x02, 0x04, 0x06, 0x02, 0x00, 0x00, 0xfc, 0xfc, + 0xfa, 0xf9, 0xf5, 0xf5, 0xfd, 0xfb, 0xf9, 0x04, 0x0f, 0x07, 0x01, 0x03, + 0x04, 0x01, 0x05, 0x05, 0x03, 0x05, 0x05, 0x12, 0x23, 0x1d, 0x11, 0x04, + 0x01, 0x03, 0x02, 0xf5, 0xfd, 0x01, 0x07, 0x0b, 0x00, 0xf9, 0xfe, 0x0d, + 0x05, 0xfb, 0xf9, 0xf5, 0xf5, 0xfb, 0xfb, 0xf7, 0xfd, 0x07, 0x02, 0xff, + 0xfc, 0xfd, 0x01, 0x00, 0xfd, 0xf9, 0xf9, 0xf6, 0xf1, 0xed, 0xf1, 0xef, + 0xf7, 0x01, 0x09, 0x09, 0x17, 0x19, 0x15, 0x24, 0x21, 0x17, 0x11, 0x0d, + 0x0c, 0x0b, 0x0d, 0x12, 0x13, 0x0f, 0x0b, 0x03, 0xfd, 0x04, 0x11, 0x0d, + 0x0f, 0x0d, 0x09, 0x0d, 0x07, 0x05, 0x03, 0x03, 0x05, 0x01, 0xfd, 0xfb, + 0xf5, 0xf8, 0xfb, 0xf7, 0xf3, 0xf1, 0xf1, 0xf5, 0xf7, 0xfb, 0xf9, 0xf5, + 0xef, 0xf5, 0xfb, 0xee, 0xe3, 0xee, 0x01, 0x0f, 0x13, 0x13, 0x0b, 0x07, + 0x0f, 0x19, 0x15, 0x14, 0x0b, 0x07, 0x03, 0x00, 0x00, 0x0b, 0x0b, 0x09, + 0x08, 0x0b, 0x0b, 0x07, 0x05, 0x03, 0x03, 0x07, 0x06, 0x03, 0xfe, 0x01, + 0x0a, 0x0d, 0x07, 0x05, 0x03, 0xfc, 0xfd, 0x01, 0x00, 0xfd, 0xff, 0xfd, + 0xfd, 0x04, 0x05, 0x00, 0xfc, 0x02, 0x17, 0x14, 0x0e, 0x0a, 0x05, 0x00, + 0xfb, 0x00, 0x00, 0xfe, 0xf6, 0xf0, 0xf6, 0xf8, 0x0a, 0x16, 0x0a, 0x04, + 0x00, 0xfd, 0xfc, 0xfa, 0xfa, 0xfa, 0x00, 0x0e, 0x0e, 0x08, 0x00, 0x00, + 0x05, 0x02, 0x00, 0xfe, 0xfa, 0x00, 0x02, 0x02, 0x0a, 0x0e, 0x04, 0x02, + 0x06, 0x12, 0x0c, 0x08, 0x08, 0x17, 0x21, 0x16, 0x10, 0x0c, 0x08, 0x06, + 0x08, 0x0c, 0x08, 0x02, 0x00, 0xfe, 0x00, 0x06, 0xfa, 0xf4, 0xf3, 0xf2, + 0xf0, 0xf2, 0xf4, 0xf7, 0xf6, 0x00, 0x0a, 0x08, 0x00, 0xf9, 0xf6, 0xf8, + 0xfa, 0xfa, 0xf6, 0xf7, 0xfb, 0xfd, 0xff, 0xfd, 0xfc, 0xfc, 0xf8, 0xf8, + 0x06, 0x10, 0x06, 0x08, 0x10, 0x26, 0x28, 0x24, 0x1c, 0x18, 0x12, 0x0e, + 0x12, 0x10, 0x0c, 0x07, 0x04, 0x0a, 0x16, 0x10, 0x08, 0x04, 0x00, 0x00, + 0x06, 0x06, 0x01, 0xfd, 0xf8, 0xed, 0xf6, 0xf6, 0xf2, 0xf0, 0xf6, 0x00, + 0xfe, 0xff, 0x07, 0x02, 0x00, 0xff, 0xfe, 0xfe, 0xfc, 0xfa, 0xf5, 0xf8, + 0x05, 0x04, 0x00, 0xfa, 0x0a, 0x16, 0x12, 0x05, 0x08, 0x0a, 0x05, 0x07, + 0x04, 0x02, 0x04, 0x00, 0x06, 0x14, 0x0b, 0x02, 0xfc, 0xfc, 0xfa, 0xf9, + 0xf8, 0xfa, 0xfc, 0xfa, 0xfc, 0x0a, 0x0c, 0x02, 0xfe, 0xfc, 0xfe, 0x00, + 0x00, 0xfc, 0xf8, 0xfc, 0xff, 0xfe, 0xfa, 0xfe, 0xfe, 0xfe, 0x0d, 0x18, + 0x1a, 0x14, 0x0e, 0x14, 0x1f, 0x1a, 0x14, 0x0e, 0x13, 0x12, 0x0e, 0x0e, + 0x0a, 0x06, 0x04, 0x0a, 0x1a, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, + 0x00, 0xfe, 0xfc, 0xf8, 0xff, 0x00, 0xfc, 0xf6, 0xee, 0xef, 0xf8, 0xfc, + 0xf9, 0xf6, 0xf5, 0xf6, 0xf6, 0xf8, 0xf0, 0xe8, 0xe8, 0xe6, 0xe7, 0xf4, + 0xf6, 0xf0, 0xf5, 0x12, 0x1b, 0x16, 0x1c, 0x1f, 0x14, 0x10, 0x10, 0x0c, + 0x0a, 0x08, 0x11, 0x12, 0x0f, 0x13, 0x0b, 0x06, 0x04, 0x01, 0x06, 0x0e, + 0x14, 0x10, 0x0c, 0x0e, 0x0e, 0x08, 0x08, 0x02, 0xfe, 0x01, 0x0c, 0x08, + 0x02, 0x00, 0xfe, 0xfb, 0xfe, 0xfc, 0xfe, 0x00, 0xfd, 0xfa, 0xfe, 0x00, + 0x00, 0xfe, 0x0d, 0x0f, 0x08, 0x00, 0xf6, 0xf9, 0xf8, 0xf8, 0xf9, 0xfa, + 0x00, 0x10, 0x14, 0x14, 0x05, 0x00, 0x00, 0xfe, 0xf8, 0xf6, 0xf7, 0xf3, + 0xf6, 0xfc, 0x00, 0x08, 0x06, 0x03, 0xfc, 0xfa, 0xfe, 0x05, 0x04, 0x02, + 0x01, 0xfd, 0x00, 0x08, 0x06, 0x03, 0x04, 0x01, 0x00, 0x06, 0x10, 0x08, + 0x06, 0x13, 0x18, 0x12, 0x13, 0x15, 0x12, 0x0b, 0x0a, 0x0a, 0x06, 0x06, + 0x0f, 0x0b, 0x07, 0x03, 0x01, 0xfd, 0xfb, 0xf8, 0xf8, 0xfb, 0xfe, 0x05, + 0xff, 0x03, 0x09, 0x03, 0x00, 0xfe, 0xfa, 0xf7, 0xf8, 0xfd, 0x00, 0x01, + 0xff, 0xfb, 0xfc, 0x02, 0xfb, 0xf7, 0xee, 0xef, 0xf4, 0xfe, 0x00, 0x02, + 0x0d, 0x1e, 0x1f, 0x18, 0x14, 0x14, 0x10, 0x08, 0x02, 0x00, 0x0b, 0x12, + 0x11, 0x10, 0x0a, 0x06, 0x04, 0x00, 0xf8, 0xf8, 0xfc, 0xfd, 0xf7, 0xf7, + 0xf9, 0xfc, 0xf6, 0xfc, 0xfc, 0xfe, 0x00, 0x08, 0x02, 0x00, 0x01, 0x00, + 0xfa, 0xfa, 0xfc, 0xfb, 0xf9, 0xfe, 0x01, 0x00, 0x05, 0x01, 0x07, 0x0f, + 0x1c, 0x14, 0x11, 0x11, 0x15, 0x13, 0x0c, 0x06, 0x08, 0x19, 0x17, 0x14, + 0x0d, 0x0a, 0x06, 0x01, 0xfc, 0xf8, 0xf5, 0xf8, 0xf9, 0xf6, 0xf3, 0xf8, + 0x06, 0x07, 0x02, 0x00, 0xfc, 0xf8, 0xec, 0xed, 0xf0, 0xf3, 0xf4, 0xf3, + 0xf5, 0xfc, 0x06, 0x0e, 0x08, 0x04, 0x07, 0x12, 0x0e, 0x06, 0x0a, 0x1c, + 0x15, 0x0f, 0x11, 0x13, 0x13, 0x0b, 0x11, 0x0f, 0x14, 0x0d, 0x08, 0x06, + 0x08, 0x06, 0x04, 0x03, 0x03, 0x00, 0x00, 0xfc, 0xf9, 0xf2, 0xf3, 0xfb, + 0xfa, 0xf5, 0xf2, 0xf2, 0xf7, 0xfa, 0xf9, 0x01, 0xfe, 0xfe, 0xfa, 0xf2, + 0xf0, 0xf2, 0xf4, 0xf6, 0xf4, 0xf4, 0xfc, 0xfa, 0xf3, 0xf8, 0x17, 0x30, + 0x28, 0x1d, 0x19, 0x1b, 0x19, 0x13, 0x19, 0x17, 0x13, 0x0e, 0x0b, 0x0d, + 0x11, 0x1a, 0x1c, 0x12, 0x0a, 0x04, 0xfb, 0xfa, 0xf9, 0xfc, 0x02, 0x02, + 0x07, 0x04, 0x03, 0x00, 0x00, 0xfe, 0xfe, 0xfc, 0xf8, 0xf4, 0xf1, 0xed, + 0xef, 0xf6, 0xf8, 0xf6, 0xf1, 0xf8, 0xfc, 0xf6, 0xf0, 0xff, 0x04, 0xff, + 0x00, 0x00, 0x00, 0x03, 0x08, 0x15, 0x15, 0x1e, 0x17, 0x0c, 0x04, 0x02, + 0x04, 0x02, 0x00, 0xfa, 0xf6, 0xf8, 0xfa, 0xf7, 0xfd, 0x0f, 0x13, 0x0e, + 0x0a, 0x07, 0x06, 0x03, 0xfe, 0x00, 0x04, 0x02, 0x03, 0xff, 0xfd, 0xff, + 0x05, 0x07, 0x05, 0x04, 0x0e, 0x0d, 0x05, 0x01, 0x11, 0x15, 0x0e, 0x0f, + 0x0e, 0x0c, 0x10, 0x18, 0x1b, 0x09, 0xfc, 0xfa, 0xf9, 0xf9, 0xfa, 0xfc, + 0xfe, 0xfe, 0xfe, 0x08, 0x0c, 0x09, 0xfe, 0xf5, 0xf6, 0xf8, 0xfb, 0xfc, + 0xf8, 0xf8, 0xfd, 0xfa, 0xff, 0x03, 0x02, 0x03, 0xfa, 0xf5, 0xf1, 0xf2, + 0xf2, 0xf4, 0xf7, 0x02, 0x09, 0x00, 0xfc, 0x0c, 0x1a, 0x12, 0x0a, 0x08, + 0x06, 0x08, 0x15, 0x13, 0x0d, 0x06, 0x06, 0x07, 0x06, 0x05, 0x09, 0x0a, + 0x0a, 0x07, 0x03, 0x01, 0xff, 0xfd, 0xfc, 0xfb, 0xf8, 0xfd, 0x02, 0x12, + 0x16, 0x0f, 0x07, 0x04, 0x08, 0x04, 0x00, 0x00, 0xfc, 0xf9, 0xfa, 0x04, + 0x08, 0x03, 0x0a, 0x11, 0x0c, 0x00, 0x00, 0x08, 0x02, 0x00, 0xfe, 0x05, + 0x15, 0x21, 0x19, 0x11, 0x0b, 0x08, 0x02, 0x00, 0x00, 0xfa, 0xf7, 0xf8, + 0xf6, 0xf1, 0xed, 0xec, 0xec, 0xee, 0xf7, 0xfc, 0xf6, 0xf4, 0xf5, 0xf4, + 0xf3, 0xf4, 0xf7, 0xfd, 0xfe, 0xfa, 0xfe, 0x0b, 0x0a, 0x05, 0x04, 0x03, + 0x06, 0x0d, 0x0b, 0x08, 0x03, 0x0e, 0x1b, 0x23, 0x22, 0x18, 0x13, 0x1d, + 0x25, 0x20, 0x1b, 0x15, 0x0f, 0x09, 0x02, 0x03, 0x07, 0x09, 0x0b, 0x06, + 0x02, 0xff, 0xff, 0xfe, 0xfe, 0xf4, 0xef, 0xef, 0xf1, 0xf4, 0xf9, 0xfc, + 0xf8, 0xf5, 0xfb, 0x00, 0xfd, 0xf3, 0xe8, 0xe8, 0xe6, 0xe9, 0xeb, 0xee, + 0xf8, 0xf9, 0xfc, 0x0c, 0x19, 0x2a, 0x22, 0x18, 0x14, 0x0b, 0x0b, 0x15, + 0x18, 0x12, 0x0b, 0x10, 0x0d, 0x09, 0x08, 0x09, 0x0c, 0x0b, 0x0c, 0x0c, + 0x0a, 0x04, 0x04, 0x05, 0x02, 0x00, 0x00, 0xfc, 0xfc, 0xfb, 0xf9, 0xf8, + 0xf7, 0xf5, 0xf6, 0xf6, 0xf7, 0xf5, 0xf2, 0xf4, 0xf8, 0xf8, 0xf9, 0x00, + 0xfc, 0xfc, 0xf8, 0x04, 0x0f, 0x07, 0x02, 0x00, 0xff, 0x12, 0x1d, 0x2a, + 0x26, 0x1e, 0x17, 0x11, 0x0d, 0x0b, 0x06, 0x03, 0x02, 0x00, 0x02, 0x0a, + 0x08, 0x06, 0x03, 0x04, 0x0b, 0xfe, 0xf1, 0xf2, 0xf2, 0xf5, 0xfa, 0x00, + 0xfd, 0xff, 0x04, 0x01, 0xfe, 0xf8, 0xf7, 0xfb, 0xff, 0x03, 0x03, 0xff, + 0xfd, 0xfa, 0x00, 0x0b, 0x06, 0x01, 0x03, 0x05, 0x0b, 0x13, 0x0e, 0x0d, + 0x09, 0x08, 0x02, 0xff, 0xfe, 0x00, 0x04, 0x13, 0x11, 0x0a, 0x07, 0x07, + 0x09, 0x00, 0xf9, 0xf2, 0xee, 0xeb, 0xf4, 0x06, 0x08, 0x02, 0x02, 0x02, + 0x01, 0x01, 0x03, 0x03, 0xfe, 0xfb, 0xfd, 0xff, 0x02, 0xff, 0x00, 0xfc, + 0xfc, 0x07, 0x1b, 0x16, 0x11, 0x09, 0x04, 0x0d, 0x14, 0x12, 0x10, 0x10, + 0x0e, 0x0a, 0x04, 0x00, 0x00, 0xfc, 0xf8, 0xfd, 0x02, 0x01, 0x00, 0xff, + 0xfe, 0xfa, 0xfd, 0x09, 0x05, 0xff, 0x05, 0x05, 0x04, 0x02, 0xff, 0x00, + 0xfe, 0xfc, 0xf7, 0xfe, 0xfe, 0xf9, 0xfe, 0x09, 0x05, 0x03, 0x01, 0xfe, + 0x01, 0x13, 0x10, 0x08, 0x07, 0x08, 0x11, 0x1b, 0x14, 0x0d, 0x06, 0x03, + 0x01, 0xfc, 0xf7, 0xf5, 0xf6, 0xf9, 0xfa, 0xfa, 0xfb, 0xfd, 0xfa, 0xf7, + 0xf7, 0xfb, 0xf8, 0xf8, 0xf7, 0xf2, 0xf4, 0xf5, 0xf8, 0xf8, 0x01, 0x15, + 0x16, 0x10, 0x0d, 0x0a, 0x09, 0x0e, 0x14, 0x12, 0x0c, 0x05, 0x05, 0x15, + 0x24, 0x1b, 0x15, 0x15, 0x17, 0x12, 0x13, 0x13, 0x12, 0x15, 0x15, 0x0d, + 0x09, 0x04, 0x00, 0xfe, 0x00, 0x00, 0x00, 0x03, 0x01, 0xf8, 0xf3, 0xec, + 0xed, 0xe9, 0xe4, 0xe1, 0xe6, 0xee, 0xec, 0xea, 0xe9, 0xf0, 0xf6, 0xf7, + 0xf5, 0xf5, 0xf7, 0xf8, 0xfb, 0xfb, 0x00, 0x0d, 0x07, 0x01, 0x06, 0x1c, + 0x1a, 0x12, 0x0d, 0x0d, 0x0f, 0x19, 0x1c, 0x1f, 0x18, 0x14, 0x13, 0x12, + 0x0e, 0x0e, 0x0a, 0x0b, 0x0e, 0x14, 0x16, 0x0f, 0x0b, 0x08, 0x00, 0xff, + 0x00, 0xfc, 0xfb, 0xfd, 0xfc, 0xf4, 0xf3, 0xf5, 0xf9, 0xfe, 0x01, 0xff, + 0xfc, 0xfb, 0x00, 0x01, 0xfe, 0xf1, 0xeb, 0xf0, 0xf1, 0xf5, 0x06, 0x02, + 0xff, 0xff, 0xfe, 0x14, 0x26, 0x25, 0x1d, 0x16, 0x13, 0x0d, 0x06, 0x02, + 0xff, 0xfe, 0xfb, 0x00, 0x03, 0x01, 0xff, 0x00, 0xfa, 0xfa, 0x00, 0x01, + 0x00, 0x02, 0xff, 0xfe, 0xfd, 0xf8, 0xf8, 0xfc, 0xff, 0xfb, 0xfa, 0xfc, + 0xfc, 0xfc, 0x04, 0x02, 0xfc, 0xfe, 0x01, 0xfd, 0xfc, 0x0e, 0x0d, 0x06, + 0x06, 0x03, 0x08, 0x15, 0x17, 0x10, 0x12, 0x11, 0x0c, 0x08, 0x07, 0x17, + 0x16, 0x14, 0x16, 0x16, 0x10, 0x0c, 0x0a, 0x03, 0xfc, 0xfa, 0xfb, 0xfd, + 0xfc, 0xfa, 0xfd, 0x00, 0xfa, 0xec, 0xea, 0xf4, 0xff, 0x02, 0xfd, 0xfd, + 0x00, 0x04, 0x03, 0xfe, 0xfb, 0xf6, 0xf1, 0xf6, 0x08, 0x0f, 0x04, 0x00, + 0xfe, 0xfe, 0x08, 0x10, 0x09, 0x09, 0x05, 0x03, 0x01, 0x02, 0x00, 0xff, + 0x00, 0x06, 0x07, 0x07, 0x07, 0x04, 0x02, 0x0c, 0x0d, 0x09, 0x05, 0x01, + 0xfe, 0xff, 0xff, 0xfc, 0xfa, 0xfb, 0xfe, 0x03, 0x09, 0x06, 0x06, 0x03, + 0x0d, 0x0f, 0x08, 0x03, 0x04, 0x06, 0xff, 0x0b, 0x13, 0x0a, 0x04, 0x01, + 0x03, 0x0c, 0x1a, 0x15, 0x10, 0x09, 0x06, 0x00, 0xfe, 0xfe, 0x01, 0xfd, + 0xff, 0x02, 0x03, 0x02, 0x00, 0xf2, 0xe4, 0xed, 0xf6, 0xf5, 0xf2, 0xf2, + 0xf7, 0xf8, 0xf8, 0x04, 0x08, 0x05, 0x03, 0x06, 0x06, 0x01, 0x05, 0x0e, + 0x0e, 0x0a, 0x06, 0x00, 0x02, 0x01, 0x0a, 0x16, 0x0d, 0x09, 0x05, 0x05, + 0x13, 0x27, 0x25, 0x1d, 0x19, 0x13, 0x0e, 0x09, 0x03, 0x05, 0x04, 0x05, + 0x02, 0xfc, 0xfc, 0xfa, 0xf7, 0xef, 0xee, 0xee, 0xed, 0xec, 0xec, 0xea, + 0xf2, 0xfa, 0xf2, 0xf1, 0xeb, 0xeb, 0xf2, 0xf5, 0xf7, 0xfb, 0x02, 0x0c, + 0x16, 0x10, 0x0d, 0x08, 0x00, 0x04, 0x20, 0x1e, 0x14, 0x0d, 0x0e, 0x13, + 0x1f, 0x28, 0x25, 0x1f, 0x16, 0x09, 0xfc, 0xfe, 0x07, 0x16, 0x18, 0x13, + 0x0c, 0x09, 0x09, 0x06, 0x00, 0xfc, 0xf9, 0xf7, 0xf2, 0xee, 0xf2, 0xf2, + 0xf3, 0xf3, 0xf4, 0xee, 0xe7, 0xed, 0xf2, 0xf5, 0xf9, 0x05, 0x02, 0xfb, + 0xfd, 0xfc, 0xfa, 0xf2, 0xf5, 0x08, 0x08, 0x0d, 0x13, 0x09, 0x0c, 0x12, + 0x1c, 0x18, 0x12, 0x10, 0x0c, 0x05, 0x03, 0x01, 0x04, 0x10, 0x0c, 0x06, + 0x01, 0x01, 0x01, 0xfb, 0xfd, 0x0a, 0x09, 0x05, 0x01, 0x00, 0xff, 0xfc, + 0xfd, 0xfe, 0xfe, 0xfc, 0xf6, 0xf2, 0xfb, 0x01, 0x07, 0x09, 0x06, 0x02, + 0x03, 0x03, 0x03, 0x00, 0x0e, 0x0f, 0xfc, 0xfa, 0xfd, 0x01, 0x02, 0x09, + 0x17, 0x13, 0x11, 0x18, 0x1f, 0x15, 0x11, 0x10, 0x13, 0x10, 0x09, 0x04, + 0x02, 0x00, 0xfb, 0xf6, 0xee, 0xf3, 0xf6, 0xf3, 0xf5, 0xf4, 0xef, 0xf4, + 0xfc, 0x00, 0xfb, 0xf9, 0xf9, 0xfb, 0xfb, 0xfd, 0x02, 0x01, 0xfd, 0xfc, + 0xf8, 0xf1, 0xf3, 0x04, 0x15, 0x09, 0x03, 0x04, 0x03, 0x04, 0x02, 0x0d, + 0x16, 0x12, 0x0d, 0x0a, 0x05, 0x03, 0x06, 0x0f, 0x12, 0x09, 0x06, 0x0b, + 0x1c, 0x13, 0x0c, 0x0b, 0x0b, 0x05, 0xfe, 0xfe, 0x03, 0x02, 0x00, 0x01, + 0x02, 0x01, 0x05, 0x04, 0xff, 0xff, 0xfc, 0x01, 0x06, 0x0a, 0x05, 0x02, + 0x03, 0x00, 0x03, 0x0f, 0x09, 0x03, 0x01, 0xff, 0xfb, 0xf4, 0xfc, 0x0c, + 0x09, 0x02, 0x00, 0xfa, 0xfb, 0xf6, 0xf7, 0xfd, 0xfd, 0xfa, 0xf6, 0xf7, + 0xf6, 0xf2, 0xf6, 0x00, 0x00, 0xfd, 0xfc, 0xfc, 0x05, 0x09, 0x07, 0x07, + 0x02, 0x00, 0xff, 0xfd, 0xfc, 0x00, 0x0c, 0x0e, 0x09, 0x06, 0x03, 0x09, + 0x0a, 0x09, 0x16, 0x16, 0x13, 0x11, 0x13, 0x12, 0x10, 0x0f, 0x13, 0x1c, + 0x18, 0x15, 0x11, 0x0f, 0x0c, 0x0a, 0x0d, 0x09, 0x02, 0x00, 0x00, 0xfb, + 0xf6, 0xf5, 0xf6, 0xf4, 0xf0, 0xed, 0xe7, 0xe2, 0xe7, 0xec, 0xf3, 0xf2, + 0xf2, 0xf5, 0xfc, 0xf7, 0xf9, 0x09, 0x0e, 0x07, 0x04, 0x02, 0x00, 0xfb, + 0xfb, 0x07, 0x1b, 0x18, 0x0f, 0x08, 0x01, 0xff, 0x09, 0x0a, 0x10, 0x16, + 0x13, 0x13, 0x14, 0x11, 0x11, 0x13, 0x10, 0x0f, 0x09, 0x06, 0x06, 0x02, + 0xfe, 0xfc, 0xf9, 0xf9, 0xf7, 0xf5, 0xf3, 0xf4, 0xf7, 0xf6, 0xf4, 0xf6, + 0xf8, 0xfa, 0xfb, 0xfa, 0xff, 0x04, 0x08, 0x04, 0x01, 0x02, 0x03, 0xfc, + 0x00, 0x1d, 0x21, 0x16, 0x0d, 0x0c, 0x0b, 0x08, 0x06, 0x04, 0x0f, 0x15, + 0x12, 0x0c, 0x07, 0x06, 0x07, 0x0c, 0x07, 0xfc, 0xfa, 0xfe, 0xff, 0xfe, + 0xfe, 0x07, 0x04, 0x01, 0xfe, 0xf8, 0xf8, 0xff, 0xfb, 0xf6, 0xf4, 0xf2, + 0xf2, 0xf3, 0xf6, 0xf9, 0xfc, 0x01, 0x04, 0x00, 0xfc, 0xfc, 0xf8, 0xf9, + 0x08, 0x18, 0x10, 0x0a, 0x04, 0x05, 0x0c, 0x0c, 0x06, 0x0d, 0x1e, 0x20, + 0x18, 0x16, 0x14, 0x17, 0x17, 0x0f, 0x05, 0xff, 0x02, 0x00, 0xf9, 0xf7, + 0xf4, 0xf7, 0xfc, 0xf9, 0xfb, 0xf7, 0xfb, 0x02, 0xfb, 0xf9, 0xfc, 0xfa, + 0xfb, 0xfc, 0xfc, 0xfc, 0x02, 0x07, 0x04, 0xfe, 0xf9, 0xf6, 0xf6, 0x00, + 0x1d, 0x1b, 0x0e, 0x08, 0x04, 0x06, 0x09, 0x03, 0xfa, 0xfc, 0x09, 0x0d, + 0x0b, 0x0a, 0x11, 0x16, 0x0f, 0x0b, 0x11, 0x10, 0x09, 0x07, 0x04, 0x00, + 0x02, 0x00, 0xfa, 0xf6, 0xf8, 0xfa, 0xfb, 0xf8, 0xf8, 0xf2, 0xf5, 0x01, + 0x02, 0x04, 0x05, 0x10, 0x11, 0x07, 0x06, 0x00, 0xfc, 0xfc, 0x00, 0x0b, + 0x14, 0x0c, 0x02, 0xfd, 0xfd, 0xfc, 0xfb, 0xf9, 0xf8, 0xfd, 0x0a, 0x06, + 0x00, 0x02, 0x07, 0x06, 0x03, 0x00, 0xfe, 0xfa, 0xfa, 0xf9, 0xfd, 0x05, + 0x05, 0x02, 0x05, 0x08, 0x05, 0x0c, 0x0a, 0x08, 0x05, 0x03, 0x02, 0xfe, + 0xfe, 0x01, 0x04, 0x10, 0x0a, 0x06, 0x03, 0x03, 0x07, 0x03, 0x09, 0x1b, + 0x1e, 0x16, 0x10, 0x0b, 0x08, 0x06, 0x05, 0x06, 0x07, 0x07, 0x0d, 0x0a, + 0x06, 0x08, 0x08, 0x05, 0x01, 0x00, 0xfc, 0xf4, 0xef, 0xf1, 0xf4, 0xf0, + 0xf1, 0xf3, 0xf2, 0xf2, 0xf2, 0xf0, 0xf4, 0xf4, 0xf4, 0xf9, 0xfc, 0x05, + 0x02, 0x01, 0x04, 0x08, 0x05, 0x05, 0x00, 0xfb, 0xfe, 0x01, 0x0d, 0x1c, + 0x13, 0x0a, 0x06, 0x0a, 0x0c, 0x13, 0x12, 0x10, 0x0d, 0x0f, 0x13, 0x16, + 0x11, 0x15, 0x16, 0x15, 0x0f, 0x0d, 0x09, 0x01, 0x00, 0x00, 0xfd, 0xfb, + 0xfd, 0xfe, 0xfe, 0xfe, 0xf9, 0xf2, 0xf5, 0xff, 0x01, 0xf7, 0xf1, 0xf5, + 0xfa, 0xfd, 0x05, 0x08, 0x00, 0x00, 0xfc, 0xfe, 0x0a, 0x07, 0x15, 0x12, + 0x0b, 0x07, 0x05, 0x01, 0xfc, 0xfb, 0xfa, 0xfa, 0xf8, 0xf9, 0x07, 0x0a, + 0x03, 0x03, 0x08, 0x09, 0x06, 0x06, 0x03, 0xfc, 0xfb, 0xfd, 0x00, 0x03, + 0x04, 0x03, 0x05, 0xfc, 0xf9, 0xfa, 0xfd, 0xfb, 0xfa, 0xfb, 0xfe, 0xff, + 0xfe, 0xf9, 0xfe, 0x04, 0x09, 0x0b, 0x06, 0x07, 0x05, 0x0a, 0x1c, 0x14, + 0x0d, 0x0f, 0x0e, 0x0d, 0x15, 0x16, 0x15, 0x10, 0x0f, 0x10, 0x14, 0x18, + 0x16, 0x12, 0x0b, 0x07, 0x04, 0x00, 0xfa, 0xf7, 0xf7, 0xf6, 0xef, 0xf1, + 0xfa, 0xfe, 0xfe, 0xf7, 0xf5, 0xf6, 0xf2, 0xef, 0xf1, 0xfa, 0xfe, 0xf8, + 0xf1, 0xed, 0xf2, 0xf6, 0xfa, 0xfa, 0xfb, 0xfb, 0xfa, 0x0c, 0x0f, 0x0b, + 0x0e, 0x10, 0x0e, 0x07, 0x05, 0x05, 0x06, 0x05, 0x05, 0x07, 0x0f, 0x12, + 0x14, 0x1e, 0x1b, 0x14, 0x0e, 0x0a, 0x05, 0x02, 0x04, 0x03, 0xff, 0xfd, + 0xff, 0x01, 0xfe, 0xfd, 0x00, 0xfe, 0xfc, 0xfb, 0x04, 0x09, 0x07, 0x05, + 0x06, 0x02, 0x05, 0x08, 0x07, 0x06, 0x07, 0x03, 0x01, 0x0e, 0x0d, 0x05, + 0x04, 0x05, 0x01, 0x00, 0xfc, 0xf8, 0xfa, 0xf8, 0xf8, 0x02, 0x0e, 0x01, + 0xfe, 0xfa, 0xfe, 0x02, 0xff, 0xfb, 0xf5, 0xf2, 0xfc, 0x09, 0x0f, 0x0b, + 0x0a, 0x03, 0xff, 0xff, 0xfe, 0xfc, 0xf8, 0xf9, 0xfb, 0xff, 0xff, 0xfd, + 0xfa, 0xfd, 0x02, 0x01, 0x03, 0x10, 0x0e, 0x08, 0x12, 0x1e, 0x17, 0x0f, + 0x0e, 0x0e, 0x11, 0x0e, 0x0a, 0x04, 0x04, 0x03, 0x02, 0x06, 0x12, 0x11, + 0x0c, 0x06, 0x05, 0x00, 0xfc, 0xf8, 0xfb, 0xfe, 0xfe, 0xfc, 0xfb, 0xfd, + 0xf9, 0xfa, 0xf6, 0xf7, 0xfa, 0xf9, 0x00, 0x02, 0x00, 0x00, 0xff, 0xfc, + 0xfa, 0xfa, 0xfd, 0x00, 0x03, 0x02, 0xff, 0x03, 0x14, 0x13, 0x10, 0x0b, + 0x02, 0x03, 0x0c, 0x0c, 0x0b, 0x0c, 0x0c, 0x06, 0x00, 0x06, 0x12, 0x12, + 0x0c, 0x07, 0x03, 0x02, 0xff, 0xfd, 0xfe, 0xff, 0xfe, 0xfc, 0xfc, 0xff, + 0x00, 0x00, 0x00, 0x02, 0xfb, 0xf5, 0xf4, 0xfa, 0x00, 0x00, 0xfe, 0xfd, + 0xfd, 0xfe, 0x06, 0x16, 0x11, 0x07, 0x02, 0x04, 0x14, 0x12, 0x09, 0x05, + 0x05, 0x04, 0x04, 0x04, 0xff, 0xfe, 0xf9, 0xf3, 0xf6, 0x03, 0x11, 0x14, + 0x0d, 0x04, 0x01, 0x04, 0x03, 0xfe, 0xfb, 0x06, 0x0c, 0x07, 0x0a, 0x06, + 0x02, 0x01, 0x00, 0x00, 0xfb, 0xfb, 0xfc, 0xfd, 0xff, 0xfe, 0xfa, 0xfa, + 0xfa, 0xf2, 0xfc, 0x06, 0x0b, 0x08, 0x05, 0x07, 0x13, 0x10, 0x0f, 0x13, + 0x1c, 0x14, 0x0a, 0x06, 0x03, 0x01, 0xff, 0x00, 0x05, 0x10, 0x12, 0x10, + 0x09, 0x07, 0x01, 0xfa, 0xf9, 0xf3, 0xf2, 0xfe, 0x01, 0xff, 0xfc, 0xfa, + 0xfc, 0xfc, 0xf9, 0xf7, 0xfa, 0xf6, 0xf3, 0xf2, 0xf8, 0xfa, 0xf6, 0xf4, + 0xf5, 0xf2, 0xfd, 0x05, 0x04, 0xfe, 0x00, 0x0e, 0x1a, 0x18, 0x13, 0x11, + 0x11, 0x0f, 0x10, 0x0c, 0x09, 0x06, 0x05, 0x05, 0x15, 0x23, 0x16, 0x11, + 0x0d, 0x0b, 0x0e, 0x0b, 0x09, 0x07, 0x05, 0x04, 0x03, 0x06, 0x03, 0xfe, + 0xfa, 0xf8, 0xef, 0xf0, 0x01, 0x03, 0xff, 0xfb, 0xf8, 0xf8, 0xfe, 0xfd, + 0xff, 0x00, 0xff, 0x03, 0x01, 0xfd, 0xfc, 0x05, 0x08, 0x03, 0x05, 0x04, + 0x00, 0xff, 0x00, 0xfc, 0xf7, 0xf5, 0xf3, 0xf4, 0x05, 0x0d, 0x05, 0x03, + 0x01, 0x01, 0xfe, 0xfd, 0xff, 0x07, 0x0d, 0x0e, 0x0d, 0x0b, 0x0a, 0x0a, + 0x0b, 0x06, 0x03, 0x02, 0x00, 0xfe, 0xfd, 0xfc, 0xfa, 0xf7, 0xf9, 0xf9, + 0x04, 0x0b, 0x0b, 0x15, 0x11, 0x07, 0x08, 0x1d, 0x21, 0x1b, 0x15, 0x0d, + 0x09, 0x09, 0x09, 0x05, 0x02, 0x01, 0x03, 0x07, 0x13, 0x0c, 0x08, 0x07, + 0x04, 0xff, 0xfb, 0xf8, 0xef, 0xf6, 0xfd, 0xfd, 0x01, 0xf9, 0xf4, 0xf7, + 0xf7, 0xf6, 0xfe, 0xfd, 0xf7, 0xf2, 0xf2, 0xf8, 0xfb, 0xf6, 0xf4, 0xf3, + 0xf5, 0xf8, 0xfd, 0x01, 0x00, 0xfb, 0x06, 0x17, 0x17, 0x1b, 0x14, 0x10, + 0x0b, 0x06, 0x03, 0x04, 0x09, 0x0a, 0x09, 0x13, 0x13, 0x0b, 0x07, 0x08, + 0x08, 0x05, 0x05, 0x07, 0x04, 0x04, 0x05, 0x05, 0x05, 0x04, 0xff, 0xff, + 0x03, 0x00, 0x03, 0x04, 0x07, 0x07, 0x01, 0xfd, 0xfd, 0xfb, 0xfb, 0x05, + 0x07, 0x02, 0x04, 0x0b, 0x0d, 0x08, 0x0c, 0x15, 0x0b, 0x01, 0x00, 0xfe, + 0xfb, 0xf9, 0xf8, 0xf4, 0xf6, 0xf8, 0x05, 0x0d, 0x05, 0xfe, 0xf7, 0xfa, + 0xfe, 0x02, 0x05, 0x01, 0xff, 0x00, 0x05, 0x08, 0x01, 0xff, 0x03, 0x05, + 0x04, 0x03, 0x00, 0xfb, 0xfc, 0xfc, 0xfb, 0xf8, 0xf4, 0xf4, 0xf4, 0xfe, + 0x04, 0x04, 0x07, 0x0e, 0x0d, 0x09, 0x0b, 0x18, 0x1b, 0x18, 0x13, 0x10, + 0x0e, 0x0b, 0x09, 0x06, 0x04, 0x04, 0x0e, 0x0a, 0x07, 0x05, 0x08, 0x06, + 0x04, 0x03, 0x07, 0x06, 0x09, 0x04, 0x01, 0xff, 0xfa, 0xfa, 0x06, 0x07, + 0xff, 0xfb, 0xfa, 0xf7, 0xf8, 0xfa, 0xf9, 0xf6, 0xf0, 0xee, 0xf0, 0xf6, + 0xf4, 0xf9, 0x02, 0x05, 0xff, 0x05, 0x0e, 0x14, 0x15, 0x14, 0x0f, 0x06, + 0x01, 0x00, 0x00, 0x01, 0x00, 0x13, 0x18, 0x10, 0x0c, 0x07, 0x08, 0x09, + 0x07, 0x03, 0x02, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00, 0x01, 0x0a, 0x09, + 0x03, 0xfe, 0xfb, 0xfc, 0xfc, 0xfc, 0xff, 0x04, 0x00, 0xfd, 0x04, 0x00, + 0xfc, 0x02, 0x07, 0x05, 0x04, 0x02, 0x02, 0x0b, 0x05, 0x01, 0x03, 0xfe, + 0xfd, 0xf9, 0xf8, 0xfe, 0x08, 0x12, 0x0b, 0x06, 0x03, 0xff, 0xfc, 0xfa, + 0xf9, 0xfb, 0x0c, 0x0d, 0x0c, 0x10, 0x11, 0x0f, 0x0d, 0x0b, 0x02, 0xfd, + 0xfb, 0xfd, 0x00, 0x00, 0xfd, 0xfd, 0x00, 0x00, 0xf7, 0xfb, 0x00, 0xfc, + 0xff, 0x00, 0x09, 0x15, 0x15, 0x0d, 0x0c, 0x14, 0x0f, 0x0e, 0x0a, 0x01, + 0x00, 0x00, 0x02, 0x02, 0x0a, 0x0a, 0x06, 0x05, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xfc, 0xfd, 0xfe, 0xfd, 0xfd, 0xfd, 0xfc, 0xfb, 0xfb, 0xfd, 0x03, + 0x05, 0x01, 0xfe, 0xfc, 0xfc, 0xf9, 0xef, 0xee, 0xf1, 0xf4, 0xf6, 0xfc, + 0xff, 0xfe, 0x09, 0x13, 0x0c, 0x0e, 0x19, 0x21, 0x19, 0x12, 0x0c, 0x09, + 0x08, 0x0e, 0x0d, 0x12, 0x13, 0x0e, 0x09, 0x07, 0x06, 0x08, 0x06, 0x03, + 0x00, 0x02, 0x05, 0x05, 0x03, 0x04, 0x03, 0x06, 0x08, 0x01, 0xfa, 0xfa, + 0xf9, 0xf9, 0xf9, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0x06, 0x0d, 0x08, 0x01, + 0xfc, 0xfb, 0x00, 0xff, 0xfa, 0xfb, 0x06, 0x12, 0x08, 0xfb, 0xfe, 0x03, + 0x00, 0x01, 0x09, 0x06, 0x03, 0xff, 0xfe, 0x02, 0x00, 0x06, 0x08, 0x04, + 0x05, 0x03, 0x03, 0x01, 0x08, 0x10, 0x0d, 0x09, 0x06, 0x03, 0xfe, 0xfc, + 0xfd, 0xfe, 0xfc, 0xff, 0xfe, 0xfd, 0xfe, 0x02, 0x08, 0x07, 0x06, 0x03, + 0xff, 0x02, 0x0c, 0x08, 0x04, 0x0f, 0x1c, 0x1f, 0x14, 0x0b, 0x06, 0x00, + 0x00, 0x06, 0x08, 0x0b, 0x0d, 0x08, 0x08, 0x0e, 0x0f, 0x0c, 0x09, 0xfc, + 0xf6, 0xf6, 0xf8, 0xfe, 0x01, 0x02, 0x06, 0x06, 0x02, 0xff, 0xfb, 0xf6, + 0xf6, 0xf6, 0xf2, 0xed, 0xef, 0xf3, 0xf8, 0xfa, 0xf1, 0xeb, 0xed, 0xf5, + 0xfb, 0xfe, 0x05, 0x05, 0x05, 0x07, 0x14, 0x17, 0x0c, 0x09, 0x07, 0x05, + 0x0c, 0x0e, 0x17, 0x16, 0x0f, 0x0a, 0x07, 0x05, 0x07, 0x07, 0x06, 0x09, + 0x09, 0x04, 0x07, 0x0e, 0x11, 0x0d, 0x0c, 0x09, 0x05, 0x02, 0x01, 0x03, + 0x00, 0xfb, 0xfc, 0x02, 0x03, 0x04, 0x08, 0x04, 0x02, 0x00, 0x00, 0xfb, + 0xf8, 0xfd, 0x00, 0x00, 0xfe, 0xfc, 0x03, 0x08, 0x03, 0x04, 0x06, 0x0f, + 0xfe, 0xf5, 0xf8, 0xfa, 0xfe, 0xfe, 0xfe, 0xff, 0xfe, 0xfb, 0xfa, 0x09, + 0x0a, 0x01, 0xfd, 0xff, 0x04, 0x07, 0x0a, 0x07, 0xff, 0xfa, 0x01, 0x06, + 0x02, 0x00, 0xfd, 0xf9, 0xfe, 0x05, 0x04, 0x06, 0x06, 0x06, 0x07, 0x08, + 0x0d, 0x13, 0x12, 0x0e, 0x09, 0x07, 0x10, 0x11, 0x0a, 0x09, 0x0d, 0x0a, + 0x07, 0x04, 0x01, 0x01, 0x02, 0x06, 0x0b, 0x0d, 0x08, 0x03, 0x02, 0x02, + 0xfe, 0xfe, 0xfc, 0xfd, 0xff, 0xf9, 0xf5, 0xf8, 0x01, 0x07, 0xfe, 0xf5, + 0xf2, 0xf2, 0xf0, 0xf5, 0x00, 0xff, 0x03, 0x04, 0x01, 0x02, 0x01, 0xff, + 0xfb, 0xfe, 0x00, 0x05, 0x06, 0x0a, 0x15, 0x15, 0x17, 0x1e, 0x18, 0x11, + 0x0f, 0x0d, 0x05, 0x01, 0x02, 0x07, 0x0b, 0x08, 0x01, 0xfc, 0x00, 0x02, + 0x01, 0x00, 0x02, 0x05, 0x04, 0x03, 0xff, 0xfb, 0xfa, 0xfd, 0xfb, 0xf9, + 0xf9, 0xf9, 0xf7, 0xff, 0x03, 0x0a, 0x08, 0x02, 0x00, 0xfc, 0xf9, 0xfc, + 0x01, 0x02, 0x09, 0x06, 0x01, 0x02, 0x0f, 0x14, 0x16, 0x0b, 0x08, 0x0b, + 0x0d, 0x06, 0x00, 0xfb, 0x03, 0x0b, 0x0b, 0x04, 0x03, 0x03, 0x07, 0x04, + 0x02, 0x01, 0x02, 0x00, 0x03, 0x06, 0x04, 0xff, 0xfc, 0xfd, 0xff, 0x00, + 0xfb, 0xfb, 0x02, 0xfc, 0xf5, 0xfa, 0x03, 0x04, 0x04, 0xff, 0xff, 0x03, + 0x03, 0x03, 0x09, 0x04, 0xff, 0x01, 0x14, 0x13, 0x0a, 0x08, 0x0f, 0x0e, + 0x0a, 0x08, 0x04, 0x00, 0x05, 0x08, 0x07, 0x08, 0x09, 0x05, 0x07, 0x02, + 0x02, 0x04, 0x02, 0x06, 0x06, 0x07, 0x04, 0xfe, 0xfa, 0xf7, 0xf4, 0xf3, + 0xf0, 0xf5, 0xfd, 0xfa, 0xf5, 0xf5, 0xfb, 0xfd, 0xfe, 0xfa, 0xfc, 0x02, + 0xfe, 0xfe, 0x02, 0x01, 0x06, 0x14, 0x19, 0x0e, 0x08, 0x08, 0x0f, 0x16, + 0x0f, 0x07, 0x05, 0x0a, 0x0f, 0x11, 0x10, 0x0d, 0x0c, 0x10, 0x14, 0x0c, + 0x00, 0xfd, 0x03, 0x0a, 0x02, 0xfe, 0x00, 0xfc, 0xfd, 0x01, 0x00, 0x00, + 0x06, 0x0a, 0x05, 0x01, 0xfd, 0xfd, 0xf8, 0xf3, 0xf1, 0xf4, 0xfa, 0xf8, + 0xf4, 0xf4, 0xf9, 0xfa, 0x05, 0x10, 0x0e, 0x06, 0x02, 0x01, 0x00, 0xff, + 0xff, 0xfa, 0xfc, 0xfd, 0xfe, 0xfb, 0x00, 0x05, 0x08, 0x06, 0x09, 0x04, + 0x03, 0x08, 0x07, 0x0b, 0x0d, 0x09, 0x04, 0xfe, 0xfe, 0x00, 0x02, 0x0a, + 0x14, 0x10, 0x0b, 0x03, 0x04, 0x09, 0x07, 0x04, 0x07, 0x0d, 0x0b, 0x08, + 0x05, 0x05, 0x05, 0x08, 0x08, 0x12, 0x0e, 0x09, 0x08, 0x08, 0x09, 0x04, + 0xfd, 0x00, 0x04, 0x01, 0x00, 0xfd, 0xf6, 0xf8, 0x00, 0x05, 0x03, 0xfc, + 0xf7, 0xf9, 0xf7, 0xf7, 0x01, 0xfb, 0xf1, 0xf2, 0xfb, 0xfb, 0xfc, 0x03, + 0x00, 0xfb, 0xfa, 0xf7, 0xf9, 0xfb, 0xfa, 0xfe, 0x08, 0x07, 0x02, 0xfc, + 0xfb, 0x07, 0x0f, 0x12, 0x1b, 0x20, 0x19, 0x17, 0x15, 0x12, 0x0f, 0x07, + 0x03, 0x00, 0x00, 0x04, 0x07, 0x06, 0x06, 0x05, 0x05, 0x08, 0x09, 0x06, + 0x01, 0xff, 0xfe, 0xfe, 0xfd, 0xfd, 0xf7, 0xf6, 0xf3, 0xf8, 0xff, 0x00, + 0x03, 0x0c, 0x08, 0x08, 0x0e, 0x0a, 0x06, 0x06, 0x05, 0x02, 0xff, 0x00, + 0x07, 0x06, 0x03, 0x07, 0x14, 0x13, 0x09, 0x03, 0x02, 0x02, 0x05, 0x07, + 0x02, 0xfe, 0x01, 0x05, 0x02, 0xfb, 0xf9, 0xf7, 0xf4, 0xf5, 0xfb, 0xfa, + 0xf8, 0xfa, 0x01, 0x04, 0xfc, 0xf9, 0xf8, 0xfb, 0x00, 0x04, 0x07, 0x03, + 0x01, 0xff, 0x02, 0x00, 0xff, 0xfe, 0x04, 0x03, 0x00, 0x02, 0x13, 0x1a, + 0x16, 0x0f, 0x09, 0x0a, 0x13, 0x11, 0x0d, 0x0c, 0x0d, 0x09, 0x0c, 0x0f, + 0x0e, 0x0d, 0x0a, 0x05, 0x04, 0x05, 0x09, 0x06, 0x06, 0x09, 0x08, 0x05, + 0x04, 0x00, 0x00, 0xfc, 0xf8, 0xf7, 0xf7, 0xf7, 0xfa, 0xfe, 0x02, 0xfd, + 0xf8, 0xf8, 0xf7, 0xf6, 0xfa, 0xfd, 0xfc, 0xf2, 0xf2, 0xfb, 0xfd, 0xfe, + 0xfb, 0xfb, 0x02, 0x07, 0x08, 0x04, 0x12, 0x1e, 0x14, 0x11, 0x0b, 0x05, + 0x05, 0x05, 0x02, 0x01, 0x04, 0x07, 0x05, 0x07, 0x09, 0x0a, 0x09, 0x02, + 0xff, 0xfe, 0x03, 0x01, 0x01, 0x01, 0x04, 0x08, 0x07, 0x0b, 0x0a, 0x07, + 0x02, 0xfd, 0xf9, 0xfb, 0xff, 0x04, 0x03, 0x05, 0x08, 0x00, 0xfd, 0xfd, + 0xfe, 0x00, 0x01, 0x09, 0x07, 0x05, 0x06, 0x02, 0x01, 0xfe, 0xfb, 0xfa, + 0xfc, 0xfc, 0x06, 0x12, 0x10, 0x0d, 0x06, 0x02, 0x03, 0x04, 0x01, 0xf9, + 0xf9, 0x04, 0x0a, 0x09, 0x0b, 0x0b, 0x0b, 0x05, 0x00, 0x03, 0x07, 0x08, + 0x08, 0x04, 0x01, 0x05, 0x07, 0x03, 0x08, 0x05, 0x00, 0xfd, 0xfa, 0xf8, + 0xf9, 0xfd, 0x07, 0x0e, 0x04, 0x02, 0x00, 0xff, 0x01, 0x01, 0xff, 0xfe, + 0xfc, 0xf8, 0xfa, 0xff, 0xff, 0xfe, 0xfc, 0xfd, 0xfd, 0x00, 0x04, 0x07, + 0x0a, 0x09, 0x08, 0x02, 0x02, 0x05, 0x00, 0xfd, 0xfe, 0x04, 0x07, 0x0c, + 0x0a, 0x07, 0x05, 0x02, 0x02, 0x0a, 0x09, 0x05, 0x05, 0x03, 0x03, 0x04, + 0x08, 0x0f, 0x1c, 0x1b, 0x12, 0x11, 0x0d, 0x06, 0x09, 0x0b, 0x08, 0x01, + 0xfc, 0xff, 0xff, 0xfd, 0xfd, 0xfd, 0xff, 0x03, 0xff, 0xf8, 0xf7, 0xf8, + 0xf9, 0xf5, 0xf2, 0xf2, 0xfb, 0xfd, 0x00, 0x00, 0x06, 0x07, 0x08, 0x04, + 0x02, 0x04, 0x05, 0x08, 0x0d, 0x02, 0x01, 0x07, 0x08, 0x05, 0x01, 0xff, + 0xff, 0x06, 0x10, 0x0a, 0x0a, 0x07, 0x08, 0x07, 0x07, 0x07, 0x04, 0x00, + 0xfd, 0xfd, 0xfc, 0xf7, 0xf8, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xfc, + 0x00, 0x02, 0x00, 0x04, 0x06, 0x03, 0x01, 0x04, 0x08, 0x02, 0xff, 0x04, + 0x09, 0x0f, 0x12, 0x15, 0x14, 0x15, 0x12, 0x10, 0x0e, 0x0a, 0x08, 0x05, + 0x00, 0x0b, 0x11, 0x17, 0x18, 0x15, 0x0d, 0x06, 0x05, 0x03, 0xfe, 0xfc, + 0xfb, 0xff, 0xfd, 0xfd, 0xfa, 0xfc, 0xfc, 0xf7, 0xf4, 0xf7, 0xfa, 0xf8, + 0xf3, 0xf6, 0xf9, 0xfa, 0xfb, 0xf7, 0xf1, 0xf2, 0xfc, 0xf9, 0xf8, 0xfb, + 0xfd, 0xfe, 0x02, 0x00, 0xfb, 0xfc, 0xfc, 0xfd, 0xfb, 0x00, 0x05, 0x09, + 0x11, 0x25, 0x1f, 0x18, 0x16, 0x13, 0x0e, 0x0b, 0x07, 0x08, 0x06, 0x0c, + 0x10, 0x0a, 0x03, 0x02, 0x04, 0x06, 0x07, 0x07, 0x07, 0x07, 0x02, 0x00, + 0x05, 0x0c, 0x0e, 0x0b, 0x04, 0xfe, 0xfe, 0x02, 0x05, 0x06, 0x08, 0x02, + 0x05, 0x0c, 0x09, 0x03, 0xfe, 0xfd, 0xfd, 0xfc, 0xfb, 0xfa, 0xf5, 0xf7, + 0x01, 0xff, 0xfe, 0xfe, 0xfd, 0x00, 0xff, 0xff, 0xfc, 0x03, 0x02, 0xfc, + 0xfa, 0xf8, 0xf8, 0xf9, 0xf7, 0xf6, 0xfa, 0xff, 0x01, 0x03, 0x04, 0x03, + 0x0c, 0x11, 0x0c, 0x08, 0x02, 0x01, 0x02, 0x0a, 0x11, 0x0e, 0x0c, 0x0c, + 0x12, 0x10, 0x0c, 0x09, 0x07, 0x09, 0x05, 0x02, 0xff, 0x00, 0x04, 0x0a, + 0x0b, 0x05, 0x02, 0x02, 0x01, 0x00, 0xff, 0xfd, 0x01, 0x02, 0x00, 0x02, + 0x00, 0x05, 0x05, 0x01, 0xfd, 0x04, 0x0a, 0x04, 0x02, 0x05, 0x01, 0x02, + 0x08, 0x05, 0x00, 0x00, 0x03, 0x04, 0x08, 0x0e, 0x0f, 0x08, 0x02, 0x01, + 0x01, 0xfe, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xfb, 0xfb, 0x01, 0x09, 0x0f, + 0x0b, 0x07, 0x04, 0x03, 0x00, 0x02, 0x03, 0x01, 0x00, 0xf9, 0xf5, 0xf6, + 0xf8, 0xf9, 0xfa, 0xfa, 0xfb, 0xff, 0xff, 0xff, 0x00, 0x04, 0x02, 0x0b, + 0x09, 0x08, 0x0d, 0x07, 0x03, 0x02, 0x09, 0x0a, 0x08, 0x08, 0x0f, 0x14, + 0x12, 0x0a, 0x08, 0x0c, 0x0b, 0x05, 0x04, 0x04, 0x01, 0x02, 0x12, 0x14, + 0x0c, 0x07, 0x06, 0x06, 0x09, 0x0b, 0x05, 0x00, 0xff, 0xfe, 0xf9, 0xf5, + 0xf5, 0xf4, 0xf7, 0xf6, 0xf5, 0xf6, 0xf7, 0xf7, 0xfd, 0xfe, 0x03, 0xff, + 0xfd, 0xfb, 0xf6, 0xf7, 0x02, 0x0b, 0x07, 0x02, 0x01, 0x0a, 0x12, 0x12, + 0x09, 0x04, 0x0a, 0x0c, 0x07, 0x06, 0x09, 0x06, 0x08, 0x0f, 0x15, 0x11, + 0x0a, 0x08, 0x07, 0x03, 0x00, 0x01, 0x00, 0x03, 0x06, 0x03, 0x01, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0xfb, 0xf8, 0xf8, 0xfa, 0xfb, 0x00, 0x03, 0xfe, + 0xfa, 0xf4, 0xf6, 0xff, 0xfe, 0xfb, 0xf8, 0xfa, 0x02, 0x08, 0x08, 0x05, + 0x02, 0x0b, 0x0b, 0x03, 0x04, 0x06, 0x0c, 0x12, 0x12, 0x1a, 0x18, 0x16, + 0x0d, 0x0c, 0x0e, 0x0b, 0x0c, 0x0b, 0x0f, 0x0f, 0x0b, 0x06, 0x03, 0xfc, + 0xf7, 0xfa, 0xfb, 0xff, 0xff, 0xfd, 0xfc, 0xfc, 0x01, 0x07, 0x06, 0x02, + 0xff, 0xfe, 0xfc, 0xf9, 0xf8, 0xf7, 0xf8, 0x04, 0x09, 0x05, 0x00, 0xfb, + 0xfa, 0xfb, 0xfc, 0xfc, 0xf8, 0xf8, 0xfa, 0xff, 0x08, 0x0a, 0x0d, 0x09, + 0x04, 0x03, 0x0a, 0x10, 0x08, 0x02, 0xff, 0x02, 0x01, 0x00, 0xfa, 0xf7, + 0xf9, 0xff, 0x00, 0xff, 0x01, 0x00, 0x06, 0x06, 0x0f, 0x12, 0x11, 0x0f, + 0x10, 0x10, 0x09, 0x07, 0x07, 0x07, 0x0c, 0x16, 0x14, 0x0c, 0x09, 0x0a, + 0x09, 0x07, 0x09, 0x07, 0x02, 0x00, 0x00, 0x0b, 0x0a, 0x06, 0x02, 0xf9, + 0xf2, 0xf6, 0xf3, 0xf2, 0xf6, 0xfb, 0x01, 0x00, 0xff, 0xfd, 0xf8, 0xfe, + 0xfa, 0xf7, 0xf6, 0xf8, 0xfa, 0xfc, 0xfb, 0x04, 0x06, 0x08, 0x09, 0x09, + 0x05, 0x04, 0x03, 0xfe, 0xfb, 0xfd, 0x08, 0x0e, 0x09, 0x09, 0x04, 0x03, + 0x06, 0x06, 0x04, 0x04, 0x08, 0x08, 0x0d, 0x12, 0x0d, 0x0a, 0x04, 0xff, + 0x00, 0x00, 0xfe, 0xfd, 0xfe, 0xfd, 0x00, 0xfe, 0xfd, 0xfc, 0xfc, 0xfe, + 0xff, 0x03, 0x0a, 0x08, 0x07, 0x04, 0x08, 0x17, 0x12, 0x0b, 0x0d, 0x0b, + 0x0a, 0x04, 0xff, 0xfe, 0xff, 0x0e, 0x19, 0x14, 0x0f, 0x09, 0x09, 0x03, + 0xff, 0xff, 0xfc, 0xf8, 0xf9, 0x01, 0x07, 0x03, 0x01, 0xff, 0xfc, 0xfb, + 0xff, 0x02, 0xff, 0xfb, 0xf4, 0xf0, 0xf3, 0xf8, 0xf8, 0xf3, 0xef, 0xef, + 0xef, 0xf3, 0xf6, 0xf6, 0xf5, 0xf6, 0x03, 0x09, 0x0b, 0x0c, 0x0d, 0x0d, + 0x0c, 0x08, 0x07, 0x0b, 0x0d, 0x13, 0x14, 0x11, 0x12, 0x11, 0x0d, 0x0c, + 0x0d, 0x0f, 0x14, 0x0d, 0x0b, 0x12, 0x14, 0x10, 0x0e, 0x0c, 0x09, 0x05, + 0x04, 0x02, 0x03, 0x06, 0x04, 0xff, 0xfe, 0x00, 0x01, 0xfe, 0xfe, 0xff, + 0xfc, 0xf4, 0xf1, 0xf3, 0xf3, 0xf9, 0x02, 0x01, 0xff, 0x02, 0x03, 0xfc, + 0xf2, 0xee, 0xec, 0xec, 0xf2, 0x01, 0x02, 0x03, 0x05, 0x04, 0x02, 0x08, + 0x05, 0x02, 0x03, 0x03, 0x0f, 0x12, 0x0f, 0x10, 0x0e, 0x0b, 0x0a, 0x06, + 0x04, 0x03, 0x05, 0x04, 0x03, 0x03, 0x06, 0x06, 0x05, 0x03, 0x01, 0x05, + 0x02, 0x00, 0x03, 0x02, 0x00, 0x0b, 0x11, 0x11, 0x05, 0x00, 0xfb, 0xf8, + 0xf6, 0xf6, 0xf7, 0xfb, 0x07, 0x0e, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0xff, 0x0b, 0x15, 0x0d, 0x08, 0x10, 0x0f, 0x08, 0x07, 0x08, + 0x07, 0x07, 0xfe, 0xfb, 0xfc, 0xfd, 0x02, 0x04, 0xfe, 0xfb, 0xfc, 0xfe, + 0xfb, 0xff, 0xfe, 0xfc, 0x02, 0x0c, 0x0d, 0x09, 0x05, 0x02, 0xfe, 0xfc, + 0xfb, 0xfc, 0xfe, 0x05, 0x0e, 0x0a, 0x06, 0x08, 0x09, 0x06, 0x03, 0x02, + 0x04, 0x04, 0x0a, 0x0b, 0x04, 0xfe, 0xfe, 0xfe, 0xfd, 0xfc, 0xfb, 0xfe, + 0x03, 0x06, 0x04, 0x0c, 0x0e, 0x07, 0x04, 0x00, 0xfe, 0xfc, 0xf8, 0xf9, + 0xfc, 0xfd, 0xfd, 0x00, 0x0a, 0x0d, 0x06, 0x06, 0x09, 0x0b, 0x0d, 0x0a, + 0x03, 0x02, 0x02, 0x09, 0x10, 0x0b, 0x04, 0x06, 0x06, 0x04, 0x05, 0x0c, + 0x0b, 0x0e, 0x0f, 0x09, 0x05, 0x03, 0x02, 0x04, 0x06, 0x02, 0xff, 0xfa, + 0xf6, 0xf5, 0xf2, 0xf2, 0xf5, 0xf8, 0xfb, 0xfd, 0xfb, 0xfb, 0x00, 0x0b, + 0x08, 0x02, 0xfe, 0x02, 0x0f, 0x0e, 0x06, 0x02, 0x02, 0x03, 0x02, 0xfe, + 0x03, 0x01, 0x02, 0x08, 0x0f, 0x0d, 0x0c, 0x0c, 0x09, 0x04, 0x01, 0x04, + 0x0c, 0x0c, 0x06, 0x02, 0x04, 0x05, 0x02, 0x01, 0x01, 0xff, 0xfd, 0xf8, + 0xf7, 0xf7, 0xf4, 0xf4, 0xf8, 0xfa, 0xf9, 0xf7, 0xf7, 0xfb, 0xff, 0xf8, + 0xf8, 0xfd, 0x01, 0x13, 0x16, 0x0e, 0x0e, 0x19, 0x15, 0x0f, 0x0c, 0x0c, + 0x0e, 0x0d, 0x0b, 0x0a, 0x12, 0x16, 0x10, 0x0b, 0x0e, 0x0e, 0x0b, 0x0e, + 0x0e, 0x09, 0x06, 0x09, 0x09, 0x05, 0xff, 0xfb, 0xfb, 0xf9, 0xf9, 0xf9, + 0xf7, 0xf7, 0xf6, 0xf7, 0xf9, 0xf6, 0xf7, 0xf5, 0xf4, 0xf3, 0xf2, 0xf2, + 0xf1, 0xf3, 0xfe, 0x05, 0x02, 0xff, 0xfa, 0xf7, 0xfc, 0x00, 0xfe, 0x00, + 0x00, 0xfd, 0xfc, 0x13, 0x1d, 0x15, 0x0e, 0x0b, 0x0f, 0x0c, 0x0e, 0x11, + 0x0d, 0x11, 0x0f, 0x0b, 0x0a, 0x0f, 0x0a, 0x08, 0x08, 0x05, 0x06, 0x07, + 0x07, 0x06, 0x04, 0x08, 0x0a, 0x07, 0x04, 0x09, 0x06, 0xff, 0xfe, 0xff, + 0xff, 0x03, 0x0f, 0x0e, 0x04, 0xfe, 0xfe, 0xfe, 0x00, 0xff, 0xfb, 0xf6, + 0xf4, 0xf3, 0xf3, 0xfe, 0x02, 0xfe, 0xfc, 0xfc, 0xf9, 0x00, 0x04, 0x08, + 0x08, 0x08, 0x07, 0x0a, 0x04, 0x01, 0x01, 0x00, 0xff, 0xfe, 0xfc, 0xf9, + 0xf7, 0xfc, 0x00, 0xfd, 0xfb, 0xfe, 0x06, 0x09, 0x04, 0x02, 0x01, 0x02, + 0x05, 0x09, 0x12, 0x11, 0x0d, 0x0a, 0x08, 0x07, 0x04, 0xfd, 0xfb, 0x01, + 0xff, 0xff, 0x07, 0x12, 0x11, 0x0b, 0x07, 0x08, 0x0f, 0x11, 0x08, 0x02, + 0x00, 0x04, 0x06, 0x05, 0x04, 0x04, 0x04, 0x0a, 0x06, 0x08, 0x09, 0x08, + 0x08, 0x06, 0x04, 0xfe, 0xfb, 0xff, 0xf7, 0xf3, 0xf2, 0xf3, 0xfa, 0xfa, + 0xfc, 0x02, 0x08, 0x03, 0x07, 0x07, 0x04, 0x04, 0x00, 0xf8, 0xf9, 0xfa, + 0xf7, 0xf7, 0xf9, 0x02, 0x04, 0x04, 0x0a, 0x0f, 0x0e, 0x08, 0x09, 0x07, + 0x06, 0x08, 0x05, 0x01, 0x02, 0x01, 0xff, 0xfd, 0xfb, 0xfb, 0xfb, 0x01, + 0x05, 0x02, 0x05, 0x0f, 0x0d, 0x09, 0x0c, 0x0e, 0x05, 0xfe, 0xfa, 0xff, + 0x03, 0x0c, 0x0d, 0x03, 0x02, 0x03, 0x04, 0x09, 0x08, 0x08, 0x05, 0x02, + 0x00, 0x03, 0x09, 0x0e, 0x0d, 0x07, 0x0a, 0x10, 0x09, 0x05, 0x03, 0x01, + 0x02, 0x00, 0x02, 0x03, 0x01, 0xff, 0xfe, 0xfb, 0xfa, 0xfa, 0xf8, 0xf1, + 0xf0, 0xf2, 0xf6, 0xf5, 0xf8, 0xfd, 0xfc, 0xf9, 0xf9, 0xf7, 0x00, 0x0a, + 0x05, 0x0c, 0x0f, 0x11, 0x13, 0x0c, 0x03, 0x01, 0x02, 0x01, 0x05, 0x05, + 0x02, 0x03, 0x08, 0x11, 0x19, 0x19, 0x18, 0x15, 0x0e, 0x0a, 0x0b, 0x0c, + 0x0b, 0x0b, 0x07, 0x04, 0x03, 0x04, 0x04, 0xfe, 0xf7, 0xf3, 0xf6, 0xf7, + 0xf9, 0x00, 0xfb, 0xf7, 0xf5, 0xf4, 0xf4, 0xf2, 0xf1, 0xf3, 0xf7, 0xfb, + 0xfc, 0x04, 0x03, 0x03, 0x04, 0x00, 0x02, 0x0d, 0x09, 0x09, 0x0a, 0x04, + 0x04, 0x0c, 0x0e, 0x13, 0x1b, 0x1d, 0x17, 0x0e, 0x03, 0x02, 0x06, 0x02, + 0x06, 0x0c, 0x07, 0x05, 0x05, 0x05, 0x05, 0x04, 0x01, 0x02, 0x06, 0x09, + 0x04, 0xfb, 0xfb, 0xfd, 0xfa, 0xf6, 0xf6, 0xf7, 0xfa, 0xff, 0x02, 0x00, + 0x06, 0x0b, 0x07, 0x05, 0x04, 0xfe, 0xfd, 0xfc, 0xfa, 0xfa, 0xfa, 0xf6, + 0xf9, 0xfd, 0x02, 0x12, 0x1a, 0x19, 0x11, 0x08, 0x01, 0x03, 0x06, 0x01, + 0x01, 0x01, 0xff, 0xfa, 0xfc, 0xfc, 0xfe, 0xfe, 0xfd, 0x04, 0x0c, 0x05, + 0x03, 0x05, 0x03, 0x02, 0x03, 0x03, 0x00, 0x03, 0x04, 0x06, 0x07, 0x07, + 0x0d, 0x0e, 0x09, 0x06, 0x05, 0x0a, 0x08, 0x07, 0x08, 0x02, 0xfb, 0xfa, + 0xfb, 0xfa, 0x03, 0x10, 0x0f, 0x0c, 0x08, 0x05, 0x03, 0x03, 0x05, 0x0b, + 0x0b, 0x0c, 0x06, 0x00, 0xff, 0x00, 0xfd, 0x00, 0xfe, 0xfd, 0xf9, 0xf6, + 0xf4, 0xf6, 0xf7, 0xf6, 0xf7, 0xfa, 0xfe, 0x00, 0xfd, 0xfe, 0x01, 0x04, + 0x0d, 0x0a, 0x04, 0x03, 0x05, 0x06, 0x01, 0xfe, 0xff, 0xfb, 0xfb, 0xff, + 0x01, 0x07, 0x15, 0x18, 0x13, 0x0e, 0x0a, 0x07, 0x07, 0x06, 0x08, 0x05, + 0x04, 0x06, 0x05, 0x04, 0x03, 0x02, 0x07, 0x14, 0x16, 0x11, 0x0e, 0x0a, + 0x02, 0x02, 0x00, 0x00, 0x06, 0x02, 0xfe, 0xfc, 0xff, 0x06, 0xfe, 0xfa, + 0x03, 0x00, 0xfc, 0x06, 0x07, 0x02, 0x00, 0xff, 0xfc, 0xf9, 0xf6, 0xf5, + 0xfa, 0x09, 0x09, 0x05, 0x01, 0x00, 0xff, 0xf8, 0xf7, 0xfd, 0xff, 0xfe, + 0x01, 0xff, 0xfd, 0xfd, 0xff, 0x05, 0x08, 0x05, 0x01, 0x00, 0x02, 0x04, + 0x01, 0x02, 0x03, 0x0d, 0x0f, 0x09, 0x05, 0x05, 0x06, 0x0a, 0x07, 0x07, + 0x0e, 0x0a, 0x05, 0x02, 0x02, 0x02, 0x07, 0x02, 0x00, 0xff, 0xff, 0x04, + 0x11, 0x14, 0x17, 0x1a, 0x12, 0x0c, 0x07, 0x05, 0x06, 0x0a, 0x09, 0x06, + 0x04, 0x01, 0x00, 0x00, 0x02, 0x05, 0x00, 0xfe, 0xff, 0xfc, 0xf8, 0xee, + 0xeb, 0xf0, 0xf2, 0xf5, 0xf7, 0xf2, 0xef, 0xf5, 0xfb, 0xfc, 0xff, 0x09, + 0x0f, 0x0a, 0x04, 0x02, 0xff, 0x00, 0x01, 0xfd, 0xfb, 0xfe, 0x00, 0x05, + 0x0c, 0x0b, 0x10, 0x10, 0x0e, 0x0a, 0x08, 0x07, 0x08, 0x0f, 0x10, 0x0f, + 0x0b, 0x09, 0x08, 0x0b, 0x11, 0x0b, 0x06, 0x03, 0x02, 0x01, 0xff, 0xfe, + 0xff, 0x00, 0xff, 0x00, 0x01, 0xfb, 0xfb, 0xfe, 0x03, 0x03, 0xfe, 0x03, + 0x10, 0x06, 0x04, 0x06, 0xff, 0xf9, 0xfa, 0x04, 0x06, 0x02, 0x04, 0x09, + 0x09, 0x0e, 0x0d, 0x08, 0x04, 0xff, 0xfd, 0xfd, 0xff, 0xfe, 0xfd, 0xfc, + 0xf7, 0xf3, 0xf6, 0xff, 0xff, 0x00, 0x05, 0x07, 0x08, 0x03, 0x00, 0x00, + 0x00, 0x05, 0x03, 0x00, 0xfe, 0xf8, 0xf5, 0xfb, 0x01, 0x00, 0x00, 0x09, + 0x10, 0x0b, 0x0b, 0x0c, 0x09, 0x03, 0x02, 0x05, 0x06, 0x0a, 0x13, 0x0d, + 0x0a, 0x11, 0x14, 0x1e, 0x15, 0x0a, 0x08, 0x09, 0x0b, 0x0a, 0x07, 0x03, + 0x01, 0x00, 0x05, 0x05, 0xfe, 0xf5, 0xf3, 0xf4, 0xf4, 0xf4, 0xf4, 0xf6, + 0xf8, 0xf8, 0xfb, 0xff, 0xf9, 0xf8, 0xfa, 0xfa, 0xfd, 0x03, 0x02, 0x06, + 0x09, 0x02, 0x01, 0x01, 0x02, 0x03, 0x05, 0x07, 0x0a, 0x10, 0x10, 0x0c, + 0x0b, 0x0e, 0x08, 0x02, 0x03, 0x04, 0x07, 0x07, 0x06, 0x04, 0x04, 0x0e, + 0x14, 0x16, 0x10, 0x08, 0x05, 0x04, 0xff, 0xfb, 0xfc, 0xf9, 0xfc, 0x01, + 0x03, 0xff, 0xfc, 0xf8, 0xf5, 0xfb, 0x00, 0x01, 0x05, 0x02, 0x03, 0x08, + 0x10, 0x0e, 0x0b, 0x04, 0xfd, 0xfb, 0xfc, 0xfd, 0x04, 0x04, 0x00, 0x00, + 0x07, 0x07, 0x04, 0x00, 0x00, 0xff, 0xfa, 0xfe, 0xfd, 0xfb, 0xfb, 0xfe, + 0x08, 0x0b, 0x0b, 0x01, 0x01, 0x03, 0x05, 0x0a, 0x0c, 0x0b, 0x0b, 0x08, + 0x06, 0x06, 0x02, 0xff, 0xff, 0xfd, 0x00, 0x04, 0x0b, 0x06, 0x05, 0x0a, + 0x06, 0x02, 0x06, 0x01, 0xf8, 0xf8, 0xfb, 0x00, 0x05, 0x0a, 0x0c, 0x0e, + 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x01, 0xfe, 0xfc, 0xfd, 0xff, 0xff, 0x03, + 0x07, 0x02, 0x01, 0xff, 0xfe, 0xfb, 0xfa, 0xfb, 0x00, 0x05, 0x07, 0x01, + 0xfd, 0xfa, 0xf8, 0xfd, 0x01, 0x02, 0xfd, 0xfd, 0x02, 0x00, 0x00, 0x09, + 0x09, 0x01, 0xfe, 0xfd, 0x05, 0x09, 0x05, 0x05, 0x02, 0xfd, 0x01, 0x0e, + 0x10, 0x0a, 0x08, 0x03, 0x02, 0x06, 0x0c, 0x0e, 0x0e, 0x0b, 0x0e, 0x14, + 0x0e, 0x04, 0x02, 0x02, 0x00, 0xff, 0x00, 0x01, 0x04, 0x07, 0x08, 0x07, + 0x02, 0xfc, 0xfb, 0xfc, 0x00, 0xff, 0xfd, 0x01, 0x00, 0xff, 0xfc, 0x08, + 0x0b, 0x0b, 0x07, 0x04, 0xff, 0xfd, 0x00, 0x02, 0xfd, 0xfa, 0xfb, 0xfd, + 0xff, 0x03, 0x02, 0xfe, 0xf9, 0xf8, 0xf7, 0xf8, 0xfb, 0x02, 0x07, 0x06, + 0x03, 0x01, 0x01, 0x07, 0x0e, 0x09, 0x08, 0x09, 0x04, 0x02, 0x02, 0xff, + 0x00, 0x00, 0xff, 0x02, 0x02, 0x03, 0x06, 0x06, 0x03, 0x00, 0x01, 0x0e, + 0x0e, 0x10, 0x0e, 0x05, 0x02, 0x04, 0x09, 0x0e, 0x0c, 0x10, 0x15, 0x10, + 0x0e, 0x0f, 0x0e, 0x0c, 0x08, 0x04, 0x01, 0xff, 0x02, 0x0a, 0x09, 0x04, + 0xfe, 0xf9, 0xf5, 0xf3, 0xf2, 0xf8, 0xf8, 0xf4, 0xf5, 0xf7, 0xf3, 0xf1, + 0xfc, 0xfd, 0xfe, 0xff, 0xf9, 0xf6, 0xf6, 0xf6, 0xf0, 0xf1, 0xfb, 0x07, + 0x05, 0x03, 0x05, 0x0b, 0x0b, 0x0c, 0x10, 0x0b, 0x0d, 0x11, 0x12, 0x10, + 0x11, 0x10, 0x0d, 0x12, 0x15, 0x11, 0x0f, 0x0c, 0x10, 0x0f, 0x0c, 0x0d, + 0x0b, 0x05, 0xfe, 0xfa, 0xfa, 0x00, 0x01, 0xfe, 0xfb, 0xfa, 0xf8, 0xf5, + 0xf6, 0xfe, 0x00, 0xf9, 0xf9, 0xfb, 0x00, 0xfe, 0xfe, 0x06, 0x0c, 0x0f, + 0x07, 0x03, 0x01, 0xfc, 0xfc, 0x05, 0x09, 0x04, 0x05, 0x03, 0x04, 0x05, + 0x05, 0x03, 0xff, 0x02, 0x04, 0x01, 0xff, 0x01, 0xff, 0x00, 0x00, 0x00, + 0x04, 0x02, 0x09, 0x0c, 0x07, 0x02, 0x05, 0x05, 0x00, 0xfe, 0xfb, 0xf6, + 0xf6, 0xfd, 0x01, 0x03, 0x03, 0x01, 0x02, 0xfb, 0xf9, 0xfe, 0x0a, 0x10, + 0x0d, 0x0b, 0x08, 0x04, 0x08, 0x10, 0x0f, 0x0f, 0x0e, 0x0a, 0x07, 0x0a, + 0x0a, 0x06, 0x05, 0x07, 0x06, 0x04, 0x04, 0x09, 0x05, 0xff, 0xff, 0x00, + 0x03, 0x02, 0x00, 0xfa, 0xfa, 0xfe, 0xfe, 0xfc, 0x00, 0xfd, 0xfe, 0x01, + 0xfe, 0xf9, 0xf9, 0xfd, 0x00, 0xfe, 0xfa, 0xf5, 0xf7, 0xfe, 0x09, 0x08, + 0x03, 0x04, 0x03, 0x00, 0x05, 0x05, 0x05, 0x0d, 0x0a, 0x06, 0x03, 0x06, + 0x05, 0x09, 0x13, 0x17, 0x0f, 0x07, 0x0a, 0x07, 0x03, 0x00, 0xff, 0x04, + 0x00, 0x02, 0x04, 0x00, 0x00, 0x01, 0x01, 0x04, 0x07, 0x06, 0x03, 0x05, + 0x04, 0x04, 0x00, 0xfd, 0x07, 0x08, 0x00, 0x04, 0x05, 0x00, 0x06, 0x07, + 0x04, 0x01, 0xff, 0x01, 0x05, 0x00, 0x05, 0xff, 0xf9, 0xfb, 0xfc, 0xfb, + 0xfa, 0xf8, 0xf8, 0xf9, 0xfc, 0x00, 0x02, 0x03, 0x02, 0x01, 0x02, 0x07, + 0x09, 0x05, 0x05, 0x03, 0x04, 0x06, 0x02, 0x02, 0x01, 0x02, 0x08, 0x08, + 0x04, 0x05, 0x08, 0x07, 0x0a, 0x08, 0x06, 0x04, 0x04, 0x08, 0x09, 0x01, + 0x02, 0x08, 0x07, 0x0f, 0x14, 0x14, 0x0d, 0x06, 0x05, 0x05, 0x04, 0x07, + 0x04, 0x02, 0x03, 0xff, 0xff, 0x03, 0x03, 0x00, 0xfe, 0xf8, 0xf7, 0xfd, + 0x02, 0x03, 0x00, 0xfd, 0xfc, 0xfb, 0xf9, 0xf5, 0xfb, 0xff, 0xff, 0xfb, + 0xf5, 0xf5, 0xf7, 0xf9, 0xf9, 0xf8, 0xfa, 0xfe, 0xfb, 0x00, 0x03, 0xff, + 0x05, 0x0c, 0x0f, 0x11, 0x12, 0x0e, 0x08, 0x09, 0x0a, 0x0e, 0x12, 0x14, + 0x19, 0x18, 0x12, 0x0d, 0x0c, 0x0c, 0x0b, 0x09, 0x03, 0x05, 0x08, 0x07, + 0x04, 0x00, 0x00, 0x01, 0xfd, 0xf8, 0xf7, 0xf9, 0x02, 0x05, 0x00, 0xf9, + 0xf5, 0xf6, 0xfc, 0xfd, 0xfe, 0x03, 0x01, 0xfa, 0xf9, 0x01, 0x00, 0xfc, + 0xfe, 0x00, 0x04, 0x09, 0x07, 0x01, 0x00, 0x02, 0x03, 0x09, 0x09, 0x06, + 0x02, 0x01, 0x01, 0x00, 0x00, 0x04, 0x0a, 0x0b, 0x05, 0x08, 0x09, 0x07, + 0x04, 0x05, 0x05, 0xff, 0xff, 0x03, 0x01, 0xfe, 0xff, 0xfc, 0xfb, 0xfb, + 0xfe, 0x00, 0xff, 0xfd, 0xfe, 0xfe, 0xfc, 0xfc, 0x01, 0x09, 0x08, 0x04, + 0x01, 0x0b, 0x1b, 0x17, 0x12, 0x0d, 0x0e, 0x0d, 0x0c, 0x0d, 0x09, 0x07, + 0x06, 0x05, 0x05, 0x05, 0x0c, 0x0d, 0x0b, 0x06, 0x05, 0x05, 0x05, 0x05, + 0xfb, 0xf5, 0xf5, 0xfb, 0xfd, 0xfe, 0xfe, 0xfd, 0xfd, 0xf6, 0xf2, 0xee, + 0xf1, 0xfc, 0xfe, 0xf9, 0xf4, 0xf2, 0xf3, 0xf5, 0x01, 0x02, 0xf9, 0xfb, + 0x07, 0x13, 0x16, 0x13, 0x12, 0x0e, 0x0d, 0x09, 0x09, 0x07, 0x0f, 0x12, + 0x0f, 0x0b, 0x09, 0x07, 0x0c, 0x09, 0x04, 0x02, 0x02, 0x03, 0x01, 0x00, + 0x00, 0x01, 0x04, 0x03, 0x04, 0x00, 0xff, 0x02, 0x00, 0xfe, 0xfd, 0x01, + 0x08, 0x0c, 0x0d, 0x0a, 0x02, 0xff, 0xfd, 0xfd, 0x09, 0x0a, 0x07, 0x06, + 0x06, 0x08, 0x08, 0x04, 0x04, 0x06, 0xfd, 0xfa, 0xfc, 0xfb, 0xfe, 0xff, + 0xfa, 0xf3, 0xf5, 0xf8, 0xfa, 0xf9, 0xfe, 0x09, 0x07, 0x01, 0xff, 0xff, + 0x02, 0x04, 0x04, 0xff, 0xfe, 0xfe, 0xfe, 0x04, 0x06, 0x06, 0x08, 0x0e, + 0x0e, 0x0e, 0x09, 0x02, 0xfe, 0xfd, 0xff, 0x09, 0x0f, 0x10, 0x10, 0x0d, + 0x11, 0x14, 0x14, 0x0f, 0x0f, 0x0c, 0x08, 0x04, 0x01, 0x00, 0xfc, 0xf7, + 0xf9, 0xfc, 0xfc, 0xff, 0x05, 0xfe, 0xfe, 0x02, 0x01, 0x00, 0xff, 0xfe, + 0xfa, 0xf9, 0xfa, 0xff, 0xfe, 0xff, 0xff, 0xfe, 0xfb, 0xfd, 0x00, 0xfe, + 0x00, 0xff, 0xfa, 0xf6, 0xf8, 0xfd, 0x04, 0x0f, 0x0b, 0x07, 0x08, 0x11, + 0x14, 0x11, 0x0a, 0x0a, 0x09, 0x07, 0x0a, 0x0b, 0x10, 0x10, 0x0c, 0x08, + 0x07, 0x05, 0x02, 0x02, 0x06, 0x02, 0x01, 0x00, 0xff, 0xfd, 0xfd, 0xff, + 0x01, 0xff, 0xfe, 0xfb, 0xf9, 0xfd, 0x00, 0x01, 0xff, 0xfe, 0x00, 0x05, + 0x0a, 0x05, 0x03, 0xfd, 0xfd, 0x00, 0x08, 0x0d, 0x04, 0xff, 0xfc, 0x00, + 0x05, 0x09, 0x08, 0x09, 0x0d, 0x07, 0x00, 0xfc, 0xfa, 0xfb, 0xfd, 0xfe, + 0xfe, 0xfc, 0xfc, 0x03, 0x0b, 0x0f, 0x10, 0x0b, 0x03, 0x02, 0x08, 0x0a, + 0x07, 0x04, 0xfe, 0xf9, 0xfc, 0x01, 0x02, 0x07, 0x08, 0x03, 0x02, 0x05, + 0x03, 0x01, 0xf8, 0xf4, 0xf7, 0xfc, 0x0a, 0x06, 0x08, 0x09, 0x0a, 0x0a, + 0x0d, 0x12, 0x10, 0x0e, 0x09, 0x03, 0xff, 0xff, 0x01, 0x02, 0x02, 0x03, + 0x08, 0x08, 0x03, 0x07, 0x0b, 0x08, 0x05, 0x04, 0x01, 0x02, 0x00, 0xff, + 0x01, 0xff, 0xfd, 0xfa, 0xfd, 0xfd, 0xfc, 0xf9, 0xf6, 0xf5, 0xf8, 0xf9, + 0xf3, 0xee, 0xe9, 0xf1, 0xfd, 0x0a, 0x09, 0xfe, 0xfa, 0x02, 0x0e, 0x0d, + 0x12, 0x13, 0x0e, 0x0b, 0x10, 0x13, 0x0d, 0x0d, 0x0e, 0x0c, 0x0b, 0x09, + 0x04, 0x02, 0xfe, 0x06, 0x0f, 0x0d, 0x0b, 0x08, 0x09, 0x0d, 0x08, 0x04, + 0x00, 0xfe, 0xfc, 0xf6, 0xf6, 0xfd, 0xfe, 0xfc, 0x00, 0x06, 0x0c, 0x0b, + 0x05, 0x02, 0xff, 0x02, 0x04, 0x06, 0x02, 0x02, 0x00, 0xfd, 0xfa, 0x00, + 0x0a, 0x09, 0x04, 0x00, 0xfc, 0xfa, 0xf9, 0xf9, 0xfb, 0xfd, 0xfc, 0xf9, + 0xf8, 0xfc, 0xfd, 0xfd, 0x04, 0x07, 0x07, 0x02, 0x01, 0x04, 0x01, 0xfe, + 0xfb, 0xfb, 0xfc, 0xfb, 0x06, 0x0d, 0x0f, 0x0d, 0x08, 0x07, 0x06, 0x04, + 0x02, 0x04, 0x06, 0x07, 0x13, 0x12, 0x0f, 0x12, 0x15, 0x13, 0x12, 0x0f, + 0x12, 0x10, 0x0b, 0x0b, 0x08, 0x01, 0xfd, 0x02, 0x08, 0x09, 0x08, 0x01, + 0xf9, 0xf7, 0xfa, 0xf8, 0xfe, 0xff, 0xfe, 0xf9, 0xfb, 0x00, 0xff, 0xf3, + 0xf5, 0xf9, 0xf5, 0xf8, 0xfe, 0xf9, 0xf6, 0xf9, 0xfb, 0xfa, 0xf9, 0xfa, + 0xfc, 0xfc, 0xfd, 0x06, 0x0c, 0x05, 0x05, 0x07, 0x0d, 0x10, 0x10, 0x12, + 0x18, 0x15, 0x0c, 0x0c, 0x11, 0x0e, 0x09, 0x0a, 0x05, 0x02, 0xfd, 0xfc, + 0xfb, 0xf7, 0xf8, 0xfc, 0x08, 0x0c, 0x08, 0x04, 0x03, 0xff, 0xfb, 0xfa, + 0xfa, 0xfb, 0xfc, 0xff, 0x03, 0x07, 0x0c, 0x09, 0x0b, 0x0a, 0x0a, 0x0c, + 0x06, 0x03, 0x05, 0x10, 0x0d, 0x07, 0x04, 0x07, 0x07, 0x07, 0x09, 0x0c, + 0x0d, 0x08, 0x01, 0xfd, 0xf5, 0xf5, 0xf8, 0xf8, 0xfd, 0xfc, 0xf4, 0xf0, + 0xf1, 0xf9, 0xfc, 0xff, 0x06, 0x04, 0x03, 0x04, 0x03, 0x03, 0x01, 0xf8, + 0xf7, 0xfa, 0xfb, 0xfe, 0x01, 0x01, 0x05, 0x01, 0x02, 0x04, 0x06, 0x04, + 0x03, 0x07, 0x19, 0x17, 0x10, 0x0c, 0x0c, 0x0c, 0x0a, 0x08, 0x06, 0x04, + 0x09, 0x0a, 0x07, 0x03, 0x02, 0x02, 0x05, 0x05, 0x06, 0x08, 0x04, 0xff, + 0xff, 0xff, 0x00, 0x05, 0x0f, 0x0b, 0x04, 0x01, 0x00, 0x01, 0xff, 0x00, + 0xfc, 0xf8, 0xf8, 0xfc, 0x01, 0x02, 0xff, 0xfb, 0xf9, 0xfb, 0x01, 0x01, + 0xff, 0x01, 0x03, 0xfb, 0xf8, 0xfd, 0x04, 0x03, 0x03, 0x06, 0x0d, 0x0e, + 0x0d, 0x07, 0x07, 0x09, 0x07, 0x02, 0x03, 0x04, 0x02, 0xff, 0x00, 0xff, + 0xff, 0xfd, 0x00, 0x06, 0x06, 0x05, 0x07, 0x06, 0x04, 0x04, 0x01, 0x00, + 0x03, 0x03, 0x00, 0x02, 0x06, 0x07, 0x0a, 0x09, 0x0a, 0x05, 0x03, 0x01, + 0x05, 0x0f, 0x08, 0x02, 0xfc, 0xfe, 0x03, 0x06, 0x06, 0x04, 0x03, 0x04, + 0x06, 0x02, 0x00, 0xfe, 0xfc, 0xf8, 0x01, 0x07, 0x02, 0xfd, 0xf9, 0xfa, + 0xfb, 0xfb, 0xfd, 0x03, 0x0d, 0x10, 0x0e, 0x09, 0x05, 0x03, 0xfe, 0xfb, + 0xfa, 0xfb, 0xfe, 0x02, 0x06, 0x03, 0x07, 0x08, 0x07, 0x03, 0x02, 0x06, + 0x0e, 0x0b, 0x08, 0x0c, 0x0c, 0x0d, 0x09, 0x0a, 0x0b, 0x07, 0x04, 0x06, + 0x09, 0x03, 0x02, 0x03, 0x05, 0x01, 0x00, 0xfc, 0xfc, 0xfb, 0xf6, 0xf7, + 0xfc, 0xfe, 0x01, 0x10, 0x0e, 0x07, 0x04, 0x05, 0xfd, 0xf6, 0xf3, 0xf1, + 0xf3, 0xf5, 0xfb, 0xf9, 0xfb, 0xfc, 0xfd, 0xfc, 0xf9, 0xf9, 0xfd, 0x09, + 0x12, 0x11, 0x0c, 0x10, 0x16, 0x10, 0x0a, 0x0c, 0x0b, 0x0a, 0x07, 0x0b, + 0x0f, 0x0c, 0x0e, 0x10, 0x0c, 0x0d, 0x0d, 0x05, 0x00, 0xfc, 0xfe, 0xff, + 0x04, 0x05, 0x08, 0x08, 0x07, 0xfe, 0xfa, 0xf5, 0xf4, 0xf5, 0xf8, 0xfe, + 0xfe, 0x00, 0xfc, 0x00, 0x09, 0x0b, 0x05, 0x02, 0xfe, 0xfc, 0x0c, 0x14, + 0x09, 0x04, 0x03, 0x00, 0xfc, 0xfc, 0xfb, 0xfd, 0xff, 0x02, 0x09, 0x0a, + 0x0c, 0x08, 0x02, 0xfe, 0xfc, 0xf8, 0xf8, 0xf8, 0xf9, 0xf6, 0xf5, 0xfb, + 0xfb, 0x04, 0x0d, 0x0d, 0x0b, 0x05, 0x00, 0xfa, 0xfa, 0xfd, 0xfb, 0xfa, + 0x00, 0x04, 0x00, 0x02, 0x0c, 0x0d, 0x0f, 0x15, 0x0e, 0x13, 0x20, 0x19, + 0x15, 0x0d, 0x0c, 0x0d, 0x0b, 0x0a, 0x0c, 0x0e, 0x0b, 0x07, 0x05, 0x08, + 0x07, 0x04, 0x04, 0x03, 0x01, 0xf9, 0xf7, 0xfc, 0xfb, 0xf7, 0xf6, 0xf8, + 0xf6, 0xff, 0x01, 0x00, 0xfe, 0x02, 0xfe, 0xfc, 0xfc, 0xf7, 0xf5, 0xf3, + 0xf4, 0xf1, 0xf4, 0xf7, 0xf9, 0xfe, 0xfd, 0xfa, 0xfe, 0x0b, 0x09, 0x06, + 0x06, 0x0c, 0x11, 0x18, 0x10, 0x08, 0x04, 0x09, 0x0b, 0x06, 0x05, 0x06, + 0x05, 0x06, 0x05, 0x04, 0x04, 0x02, 0x01, 0xfd, 0xfa, 0xfa, 0xfc, 0xfd, + 0x07, 0x10, 0x0e, 0x0f, 0x16, 0x11, 0x04, 0x00, 0xfe, 0xfe, 0xfe, 0x03, + 0x03, 0x05, 0x0b, 0x08, 0x0e, 0x11, 0x0c, 0x0b, 0x15, 0x11, 0x0b, 0x09, + 0x04, 0x03, 0x03, 0x04, 0x02, 0xfa, 0xfb, 0xfb, 0xf7, 0xf7, 0xfc, 0x09, + 0x02, 0xfd, 0xf6, 0xf5, 0xf8, 0xf7, 0xf2, 0xf1, 0xf3, 0xf4, 0xf6, 0xfd, + 0x06, 0x09, 0x05, 0x00, 0x00, 0xfa, 0xf5, 0xf6, 0xf8, 0xf7, 0xfb, 0xfe, + 0x03, 0x06, 0x07, 0x09, 0x09, 0x0d, 0x0f, 0x1d, 0x1b, 0x16, 0x1b, 0x11, + 0x0b, 0x0d, 0x0e, 0x09, 0x07, 0x06, 0x05, 0x06, 0x03, 0x00, 0x03, 0x08, + 0x0c, 0x0c, 0x07, 0x05, 0x04, 0x00, 0xff, 0x08, 0x03, 0xfe, 0xfe, 0x03, + 0x08, 0x0a, 0x07, 0x00, 0x01, 0x00, 0x00, 0xfb, 0xf7, 0xf9, 0xf9, 0xf5, + 0xf7, 0xf7, 0xf4, 0xf4, 0xf8, 0xfc, 0x09, 0x09, 0x07, 0x05, 0x0b, 0x0c, + 0x0a, 0x05, 0x01, 0x01, 0x01, 0x01, 0x08, 0x05, 0x03, 0x02, 0x08, 0x09, + 0x07, 0x04, 0x03, 0x01, 0xff, 0xfb, 0xfb, 0xf9, 0xfe, 0x03, 0x05, 0x09, + 0x07, 0x02, 0x04, 0x0d, 0x0d, 0x06, 0x00, 0xfd, 0xfc, 0x03, 0x06, 0x03, + 0x01, 0x01, 0x00, 0xfd, 0x04, 0x17, 0x12, 0x08, 0x03, 0x03, 0x03, 0x06, + 0x06, 0x08, 0x07, 0x04, 0x04, 0x09, 0x09, 0x09, 0x06, 0xfe, 0x02, 0x04, + 0x01, 0xfb, 0xff, 0xfc, 0xf7, 0xf9, 0xfb, 0x01, 0x06, 0x06, 0x0a, 0x0e, + 0x09, 0x01, 0xfe, 0xff, 0xfb, 0xf1, 0xf5, 0xfa, 0xfd, 0xf9, 0xfb, 0x09, + 0x07, 0x03, 0xfe, 0xfe, 0x15, 0x1d, 0x1a, 0x14, 0x0c, 0x0a, 0x0c, 0x09, + 0x04, 0x04, 0x02, 0x02, 0x02, 0x01, 0xfe, 0xfe, 0x00, 0x04, 0x09, 0x04, + 0xfe, 0xff, 0xff, 0xfb, 0xfb, 0xfb, 0xfb, 0xfd, 0xfe, 0x01, 0x0a, 0x0a, + 0x00, 0xfc, 0xfc, 0xfe, 0x01, 0xfc, 0xfb, 0xf9, 0xf8, 0xf5, 0xf6, 0xfb, + 0xfa, 0xf5, 0xf9, 0x0b, 0x16, 0x17, 0x18, 0x23, 0x1d, 0x17, 0x13, 0x0c, + 0x06, 0x0c, 0x0d, 0x0a, 0x09, 0x03, 0x05, 0x06, 0x06, 0x0b, 0x0b, 0x03, + 0x03, 0x03, 0xfb, 0xfa, 0xf8, 0xf8, 0xf8, 0xf8, 0xfc, 0x04, 0x04, 0x00, + 0xfb, 0xfd, 0xfe, 0x00, 0x01, 0xfb, 0xfe, 0x05, 0xff, 0xfc, 0xff, 0xff, + 0x02, 0x01, 0x0b, 0x0c, 0x10, 0x0f, 0x07, 0x05, 0x09, 0x07, 0x03, 0x02, + 0x02, 0x04, 0x08, 0x0c, 0x07, 0x04, 0x00, 0xfc, 0xfc, 0x06, 0x05, 0xfb, + 0xf6, 0xf3, 0xef, 0xf2, 0xf7, 0xff, 0xfc, 0xfb, 0x05, 0x04, 0x00, 0xfc, + 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0xfd, 0x04, 0x06, 0x04, 0x04, 0x0c, 0x0c, + 0x0c, 0x16, 0x15, 0x17, 0x1c, 0x1b, 0x15, 0x11, 0x12, 0x14, 0x14, 0x11, + 0x0e, 0x0d, 0x09, 0x04, 0xff, 0xfb, 0xfb, 0xfe, 0x01, 0x05, 0x0a, 0x0b, + 0xfd, 0xf9, 0xf4, 0xf7, 0xf9, 0xf8, 0xfa, 0x03, 0x00, 0xfe, 0xfa, 0xf4, + 0xf7, 0xf7, 0xf6, 0xf6, 0xf4, 0xf4, 0xf2, 0xf1, 0xef, 0xf5, 0xf8, 0xfb, + 0x05, 0x00, 0xfc, 0x07, 0x11, 0x0c, 0x0b, 0x14, 0x12, 0x0f, 0x11, 0x11, + 0x0a, 0x06, 0x03, 0xff, 0xfd, 0x05, 0x0c, 0x09, 0x0b, 0x0a, 0x04, 0x01, + 0x02, 0x02, 0xff, 0xff, 0x03, 0x06, 0x15, 0x1c, 0x15, 0x0f, 0x09, 0x06, + 0x03, 0x04, 0x07, 0x05, 0x01, 0x04, 0x03, 0xfe, 0xff, 0x04, 0x05, 0x11, + 0x0f, 0x06, 0x00, 0x06, 0x00, 0xfd, 0x01, 0x02, 0x00, 0xff, 0xfd, 0xff, + 0xfc, 0xf5, 0xf7, 0xff, 0xff, 0xfc, 0xff, 0x01, 0x01, 0xfb, 0xf5, 0xf0, + 0xec, 0xf1, 0x00, 0x01, 0xff, 0x04, 0x05, 0x06, 0x01, 0xfd, 0xfb, 0xfb, + 0xfb, 0xfd, 0x07, 0x0e, 0x09, 0x06, 0x01, 0x01, 0x02, 0x08, 0x1a, 0x19, + 0x0b, 0x06, 0x0b, 0x10, 0x0c, 0x0d, 0x0e, 0x0e, 0x0e, 0x0b, 0x08, 0x06, + 0x05, 0x05, 0x04, 0x04, 0x04, 0x03, 0x03, 0x04, 0x05, 0x02, 0x02, 0x03, + 0x04, 0xfe, 0x02, 0x04, 0x0c, 0x07, 0x03, 0xfe, 0xfa, 0xfb, 0xfd, 0x03, + 0x02, 0x01, 0x03, 0x00, 0xf2, 0xed, 0xed, 0xee, 0xed, 0x01, 0x14, 0x0f, + 0x07, 0x06, 0x0b, 0x0b, 0x08, 0x0d, 0x0c, 0x08, 0x08, 0x09, 0x09, 0x06, + 0x02, 0xfd, 0xfd, 0xff, 0x03, 0x03, 0x01, 0x01, 0xfd, 0xff, 0xfe, 0x00, + 0xfd, 0xf9, 0xff, 0x07, 0xff, 0xfe, 0x02, 0x04, 0x05, 0x05, 0x0a, 0x03, + 0x02, 0x08, 0x04, 0xfd, 0xf8, 0xfb, 0xfd, 0xfd, 0x0d, 0x16, 0x0e, 0x06, + 0x02, 0x05, 0x08, 0x04, 0x05, 0x06, 0x14, 0x18, 0x14, 0x10, 0x0f, 0x0d, + 0x06, 0x06, 0x00, 0xfe, 0xff, 0xff, 0x02, 0xff, 0xfc, 0xf9, 0xfa, 0x02, + 0x01, 0x05, 0x0b, 0x05, 0xf6, 0xf0, 0xf1, 0xf5, 0xf3, 0xf3, 0xf5, 0xf7, + 0xfa, 0xf9, 0xf9, 0xf9, 0xfd, 0x04, 0x05, 0x0c, 0x15, 0x13, 0x0b, 0x06, + 0x04, 0x09, 0x0a, 0x0c, 0x0f, 0x10, 0x12, 0x11, 0x0e, 0x0c, 0x0c, 0x09, + 0x05, 0x05, 0x0e, 0x12, 0x0c, 0x08, 0x05, 0x04, 0x02, 0x04, 0xfd, 0xf5, + 0xfd, 0x01, 0x03, 0xfe, 0xfa, 0xf9, 0xf7, 0xf7, 0xf7, 0xf7, 0xf8, 0xfa, + 0xf9, 0xf9, 0xf4, 0xf3, 0xf4, 0xf1, 0xfa, 0x07, 0x00, 0x01, 0x09, 0x08, + 0x0e, 0x20, 0x1c, 0x0f, 0x0b, 0x0d, 0x0f, 0x10, 0x0b, 0x08, 0x09, 0x0a, + 0x0b, 0x0a, 0x0c, 0x0d, 0x02, 0xfd, 0xff, 0xfe, 0xfa, 0xf9, 0x06, 0x11, + 0x0e, 0x0e, 0x09, 0x00, 0xfd, 0x00, 0xfe, 0xff, 0xfe, 0xfe, 0x02, 0x05, + 0x05, 0x00, 0xfb, 0xf9, 0xf7, 0xfc, 0x0e, 0x07, 0xff, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x03, 0x02, 0xfd, 0xfd, 0x02, 0x01, 0x06, 0x0e, 0x09, 0x01, + 0xfd, 0xfb, 0xfa, 0xfb, 0xfa, 0xf8, 0xf7, 0xf8, 0xfd, 0x09, 0x0e, 0x0d, + 0x07, 0x03, 0xfe, 0xf9, 0xf8, 0xf9, 0x02, 0x0b, 0x08, 0x0c, 0x0f, 0x0f, + 0x08, 0x0a, 0x08, 0x00, 0x02, 0x12, 0x12, 0x0b, 0x0d, 0x0d, 0x0c, 0x14, + 0x13, 0x12, 0x11, 0x10, 0x07, 0x06, 0x04, 0x04, 0x00, 0xff, 0xfd, 0xfb, + 0xf7, 0xf7, 0xf8, 0xf7, 0xfe, 0x06, 0x04, 0x00, 0x06, 0x04, 0xff, 0xfd, + 0xfc, 0xf7, 0xf4, 0xf3, 0xf4, 0xf8, 0xfa, 0xfa, 0xfe, 0xfe, 0xfe, 0xfb, + 0xf7, 0xf6, 0xfa, 0x05, 0x0e, 0x0f, 0x06, 0x09, 0x11, 0x0e, 0x0d, 0x0b, + 0x0a, 0x09, 0x05, 0x05, 0x09, 0x09, 0x09, 0x0b, 0x09, 0x03, 0x01, 0x03, + 0x06, 0x05, 0x00, 0x02, 0x01, 0xfe, 0xfd, 0x05, 0x04, 0x01, 0x04, 0x09, + 0x0c, 0x0b, 0x0c, 0x05, 0x01, 0x00, 0x02, 0x05, 0x09, 0x07, 0x04, 0x00, + 0x00, 0x00, 0x01, 0x08, 0x0c, 0x01, 0xfc, 0xf8, 0xfb, 0x03, 0x03, 0x0b, + 0x0b, 0x0a, 0x09, 0x06, 0x06, 0x01, 0xff, 0xfe, 0x00, 0xfd, 0xfb, 0xfa, + 0xfd, 0xfb, 0xfc, 0xff, 0xfd, 0x00, 0x0a, 0x0d, 0x09, 0x05, 0xff, 0xfc, + 0xf9, 0xf9, 0xf7, 0xf2, 0xf2, 0xf8, 0xfe, 0x07, 0x04, 0x03, 0x06, 0x05, + 0x02, 0xff, 0xfe, 0x0e, 0x09, 0x02, 0xfc, 0xfd, 0x08, 0x11, 0x13, 0x12, + 0x0d, 0x0b, 0x0b, 0x0a, 0x0c, 0x0a, 0x0c, 0x15, 0x15, 0x0d, 0x0b, 0x0b, + 0x0c, 0x07, 0x08, 0x02, 0x0c, 0x07, 0x04, 0x07, 0x06, 0x01, 0x01, 0x02, + 0xff, 0xff, 0xf6, 0xf4, 0xf7, 0xf3, 0xf3, 0xf8, 0xf5, 0xf1, 0xee, 0xe9, + 0xeb, 0xee, 0x03, 0x09, 0xff, 0x02, 0x08, 0x0c, 0x0b, 0x08, 0x03, 0x02, + 0x05, 0x04, 0x03, 0x02, 0x03, 0x07, 0x0a, 0x0b, 0x08, 0x04, 0x05, 0x06, + 0x00, 0x05, 0x0b, 0x18, 0x17, 0x0c, 0x0a, 0x0c, 0x0b, 0x08, 0x04, 0x03, + 0x02, 0x00, 0xfa, 0xfd, 0x04, 0x04, 0x02, 0x02, 0x02, 0x00, 0x00, 0xfd, + 0xfb, 0x02, 0x09, 0xff, 0xfb, 0xfd, 0x01, 0xff, 0x00, 0x03, 0x0d, 0x09, + 0x05, 0x09, 0x09, 0x07, 0x04, 0x04, 0x02, 0x00, 0xfd, 0xfd, 0xfc, 0xfc, + 0xff, 0x05, 0x12, 0x0e, 0x0d, 0x04, 0x02, 0x01, 0xfa, 0xf5, 0xf5, 0xfc, + 0x03, 0xfc, 0xfa, 0x01, 0x08, 0x03, 0x01, 0x01, 0x00, 0xfe, 0xfe, 0x00, + 0x05, 0x10, 0x09, 0x01, 0x00, 0x09, 0x0f, 0x0f, 0x10, 0x0f, 0x0d, 0x0c, + 0x0d, 0x0b, 0x09, 0x06, 0x04, 0x0c, 0x0e, 0x05, 0x00, 0x02, 0x00, 0xfd, + 0x07, 0x0b, 0x02, 0xfd, 0xf9, 0xfb, 0xff, 0xfc, 0xf7, 0xf5, 0xf6, 0xf9, + 0xf3, 0xf4, 0xf8, 0xf9, 0xf8, 0xf8, 0xf8, 0xfb, 0x03, 0x00, 0xfd, 0x02, + 0x18, 0x17, 0x07, 0x07, 0x12, 0x10, 0x09, 0x0b, 0x0e, 0x0b, 0x0b, 0x0a, + 0x0a, 0x0f, 0x10, 0x0e, 0x0e, 0x09, 0xff, 0xfd, 0xfe, 0xfa, 0xf8, 0x02, + 0x0a, 0x0c, 0x08, 0x01, 0x02, 0x08, 0x05, 0xfe, 0xfd, 0xfc, 0xfa, 0xf8, + 0xf6, 0xfb, 0xfd, 0xfc, 0x00, 0x00, 0x01, 0x02, 0xff, 0xfc, 0xfc, 0x04, + 0x0b, 0x04, 0x00, 0x04, 0x0d, 0x11, 0x03, 0x03, 0x08, 0x08, 0x08, 0x06, + 0x03, 0x03, 0x05, 0x06, 0x00, 0xff, 0xfd, 0xfd, 0xf9, 0xf9, 0x0b, 0x10, + 0x09, 0x06, 0x09, 0x06, 0x01, 0x01, 0xff, 0xf9, 0xf9, 0xfe, 0xfc, 0xfc, + 0x06, 0x08, 0x01, 0x01, 0x00, 0x00, 0xfe, 0xff, 0xfe, 0xfb, 0xff, 0x0d, + 0x0d, 0x0d, 0x0f, 0x10, 0x0c, 0x08, 0xff, 0x02, 0x06, 0x03, 0x04, 0x06, + 0x08, 0x15, 0x0f, 0x0b, 0x09, 0x06, 0x05, 0x02, 0xfd, 0x04, 0x0a, 0x06, + 0x00, 0x00, 0x01, 0x01, 0xfe, 0xfe, 0xfe, 0xfb, 0xfa, 0xf9, 0xf9, 0x00, + 0x01, 0xfb, 0xf8, 0xf4, 0xfb, 0xff, 0xf3, 0xf2, 0xfc, 0x02, 0x0b, 0x0d, + 0x06, 0x0b, 0x0a, 0x04, 0x00, 0xfe, 0xff, 0x01, 0x04, 0x06, 0x05, 0x06, + 0x06, 0x0a, 0x0a, 0x05, 0x02, 0x01, 0x01, 0x00, 0x05, 0x15, 0x12, 0x0b, + 0x0c, 0x0d, 0x0b, 0x09, 0x08, 0x06, 0x06, 0x07, 0x04, 0x04, 0x09, 0x09, + 0x04, 0x02, 0x02, 0x05, 0x06, 0x05, 0xfc, 0xf5, 0xf2, 0xf7, 0x04, 0x07, + 0x0e, 0x09, 0x01, 0xff, 0x06, 0x02, 0x02, 0x02, 0xfd, 0xfb, 0xfc, 0xff, + 0xfd, 0xfb, 0xfa, 0xf8, 0xf8, 0xf8, 0xfa, 0x07, 0x0f, 0x08, 0x01, 0x02, + 0x06, 0x0a, 0x05, 0x02, 0xff, 0x02, 0x02, 0xfb, 0xfc, 0x01, 0x03, 0x02, + 0x03, 0x04, 0x03, 0x03, 0x02, 0xfe, 0xf9, 0xfb, 0xfe, 0x09, 0x16, 0x16, + 0x11, 0x0c, 0x09, 0x06, 0x08, 0x09, 0x0a, 0x09, 0x0f, 0x10, 0x10, 0x13, + 0x12, 0x0c, 0x0a, 0x0a, 0x04, 0xfe, 0x03, 0x07, 0x03, 0x02, 0x04, 0x01, + 0xfe, 0x02, 0x03, 0x03, 0x02, 0xfd, 0xf7, 0xef, 0xee, 0xf0, 0xf0, 0xf3, + 0xf3, 0xef, 0xf5, 0xf7, 0xf6, 0xf2, 0xf7, 0xfd, 0x05, 0x17, 0x0d, 0x0d, + 0x0f, 0x08, 0x07, 0x04, 0x07, 0x09, 0x0a, 0x08, 0x07, 0x0e, 0x12, 0x12, + 0x11, 0x0e, 0x0e, 0x08, 0x0a, 0x0e, 0x0a, 0x0d, 0x0a, 0x0a, 0x0c, 0x09, + 0x05, 0x01, 0xfc, 0xf8, 0xf7, 0xfa, 0xfc, 0x00, 0xfe, 0xfa, 0xfa, 0xfe, + 0xff, 0xfe, 0xf9, 0xf6, 0xf5, 0xf2, 0xf2, 0xfb, 0x0b, 0x0f, 0x08, 0x0e, + 0x07, 0x00, 0x02, 0x04, 0x0a, 0x0a, 0x0a, 0x0b, 0x0e, 0x0e, 0x0b, 0x05, + 0x02, 0x02, 0x00, 0xfe, 0x06, 0x10, 0x0f, 0x09, 0xfc, 0xf6, 0xfb, 0x02, + 0x07, 0x0a, 0x02, 0x04, 0x01, 0xfd, 0xff, 0x03, 0xfd, 0xf9, 0xf7, 0xf4, + 0xf6, 0xf7, 0xf9, 0xf9, 0xf5, 0xf2, 0xfb, 0x0b, 0x19, 0x18, 0x11, 0x0a, + 0x05, 0x04, 0x04, 0x06, 0x0b, 0x0a, 0x00, 0x07, 0x18, 0x11, 0x0a, 0x09, + 0x0e, 0x0a, 0x07, 0x0a, 0x11, 0x08, 0x06, 0x02, 0xff, 0xff, 0xff, 0xfe, + 0xfd, 0xfd, 0xfb, 0xfd, 0xfe, 0xfd, 0x00, 0x01, 0x00, 0x00, 0xfc, 0xfe, + 0xf4, 0xf1, 0xf5, 0xf9, 0xf8, 0xfa, 0xfe, 0x02, 0x0c, 0x07, 0x0c, 0x0e, + 0x08, 0x05, 0x04, 0x06, 0x0b, 0x0d, 0x0c, 0x0c, 0x09, 0xfc, 0xf7, 0xfc, + 0x02, 0xff, 0xfd, 0x07, 0x10, 0x0e, 0x09, 0x09, 0x07, 0x02, 0x02, 0x05, + 0x04, 0x07, 0x03, 0x02, 0x02, 0x03, 0x04, 0x03, 0x03, 0x00, 0x00, 0x00, + 0x01, 0x02, 0xff, 0xfc, 0x04, 0x11, 0x08, 0x13, 0x14, 0x0a, 0x09, 0x08, + 0x03, 0x02, 0xff, 0xfc, 0xfc, 0xff, 0x03, 0x00, 0xfe, 0xfc, 0xfa, 0xf7, + 0xf3, 0xf7, 0x06, 0x05, 0xff, 0xfd, 0xf9, 0xfa, 0xfc, 0xfb, 0x00, 0xf7, + 0xfa, 0x0b, 0x09, 0x05, 0x07, 0x04, 0x05, 0x0c, 0x08, 0x03, 0x04, 0x03, + 0x02, 0xff, 0xfe, 0x02, 0x0b, 0x0a, 0x0a, 0x1d, 0x1b, 0x13, 0x05, 0x03, + 0x04, 0x10, 0x16, 0x13, 0x11, 0x11, 0x0a, 0x0a, 0x05, 0x03, 0x02, 0xfe, + 0xfc, 0x05, 0x09, 0x00, 0x00, 0xfe, 0xfa, 0xfc, 0xfb, 0xfc, 0xff, 0x00, + 0x02, 0xff, 0xf7, 0xf7, 0xfc, 0xf9, 0xf4, 0xec, 0xe8, 0xf2, 0xfc, 0xf9, + 0xf4, 0xf7, 0xfa, 0xff, 0xfe, 0xfe, 0x08, 0x12, 0x0a, 0x0f, 0x10, 0x0b, + 0x06, 0x06, 0x04, 0x08, 0x0d, 0x10, 0x10, 0x0d, 0x0e, 0x15, 0x1c, 0x11, + 0x09, 0x11, 0x0f, 0x0d, 0x0b, 0x07, 0x07, 0x02, 0xff, 0xff, 0xff, 0x01, + 0x04, 0x03, 0xff, 0x01, 0x03, 0x00, 0xff, 0x01, 0x00, 0xfc, 0xf3, 0xe9, + 0xe9, 0xed, 0xf5, 0xf1, 0xef, 0xf4, 0x10, 0x1b, 0x0c, 0x06, 0x0b, 0x0b, + 0x05, 0x06, 0x09, 0x0c, 0x08, 0x05, 0x01, 0xff, 0xff, 0x00, 0xff, 0xff, + 0x0c, 0x0e, 0x09, 0x09, 0x07, 0x0b, 0x14, 0x0b, 0x06, 0x09, 0x08, 0x07, + 0x02, 0xfe, 0xfc, 0xfd, 0xfc, 0xfc, 0xfb, 0xf8, 0xf9, 0xf9, 0xf6, 0xf4, + 0xf5, 0xfc, 0xfb, 0xf9, 0xfc, 0x00, 0x10, 0x0e, 0x07, 0x07, 0x06, 0xfe, + 0xfa, 0x06, 0x0d, 0x1c, 0x17, 0x10, 0x11, 0x10, 0x0d, 0x09, 0x0c, 0x11, + 0x14, 0x0d, 0x08, 0x07, 0x04, 0x03, 0x05, 0x02, 0x02, 0x05, 0x09, 0x00, + 0xf5, 0xf6, 0x07, 0x0b, 0x01, 0xfa, 0xf3, 0xed, 0xec, 0xe9, 0xe9, 0xf0, + 0xf8, 0xfa, 0xf4, 0xf1, 0xf5, 0xfb, 0x0b, 0x06, 0x07, 0x0b, 0x09, 0x0a, + 0x0f, 0x10, 0x0d, 0x09, 0x06, 0x04, 0x03, 0x00, 0xfa, 0xfe, 0x05, 0x15, + 0x1e, 0x17, 0x10, 0x09, 0x03, 0x04, 0x04, 0x01, 0x06, 0x07, 0x04, 0x00, + 0x01, 0x04, 0x01, 0xfd, 0xfc, 0xf9, 0xfb, 0x00, 0x01, 0x02, 0x09, 0x14, + 0x0c, 0x03, 0x03, 0x00, 0xfb, 0x09, 0x14, 0x0c, 0x09, 0x0a, 0x09, 0x07, + 0x05, 0x03, 0x03, 0x02, 0xfc, 0xf8, 0xf7, 0xf9, 0xfb, 0xfc, 0x02, 0x09, + 0x01, 0xf1, 0xec, 0xec, 0xf0, 0xf1, 0xf6, 0xf9, 0x07, 0x14, 0x0c, 0x09, + 0x06, 0x06, 0x02, 0x01, 0x02, 0xfe, 0xfd, 0xfe, 0x00, 0xfe, 0x03, 0x0b, + 0x09, 0x05, 0x06, 0x07, 0x05, 0x17, 0x21, 0x23, 0x20, 0x18, 0x1a, 0x14, + 0x0e, 0x0e, 0x08, 0x01, 0xff, 0x01, 0x01, 0x03, 0x03, 0x00, 0x08, 0x0d, + 0x04, 0xfc, 0xf8, 0xf6, 0xfa, 0xfb, 0xfb, 0xff, 0xf9, 0xf4, 0xf7, 0xf6, + 0xf1, 0xee, 0xee, 0xf0, 0xf1, 0xfa, 0x01, 0xfe, 0xf7, 0xf5, 0x00, 0x01, + 0xfe, 0xfc, 0xf9, 0xfd, 0x02, 0x14, 0x11, 0x13, 0x1c, 0x1d, 0x1a, 0x17, + 0x14, 0x0f, 0x0b, 0x0d, 0x11, 0x12, 0x10, 0x0e, 0x04, 0x03, 0x12, 0x0f, + 0x04, 0x02, 0x04, 0x02, 0x02, 0xfe, 0x02, 0x02, 0xfc, 0xfa, 0xfc, 0xfe, + 0x01, 0xfe, 0xfb, 0xfb, 0xf9, 0xf6, 0xf4, 0xf4, 0xf4, 0xf9, 0xf9, 0xfa, + 0xfe, 0xfc, 0x01, 0x06, 0x06, 0x14, 0x12, 0x0c, 0x0e, 0x08, 0x07, 0x0a, + 0x09, 0x04, 0x00, 0xff, 0xfd, 0xfc, 0xfd, 0xfe, 0xfa, 0x00, 0x12, 0x16, + 0x0b, 0x0a, 0x09, 0x06, 0x04, 0x05, 0x04, 0x08, 0x09, 0x04, 0x00, 0x01, + 0x02, 0x01, 0x00, 0xfe, 0xfc, 0xf7, 0xf3, 0xf5, 0xfc, 0x07, 0x05, 0x03, + 0x00, 0xfc, 0xfc, 0xf7, 0xf1, 0x05, 0x07, 0x08, 0x0e, 0x0a, 0x09, 0x10, + 0x17, 0x11, 0x0b, 0x08, 0x08, 0x05, 0x03, 0x06, 0x09, 0x0b, 0x12, 0x0b, + 0x06, 0x08, 0x08, 0x08, 0x08, 0x08, 0x01, 0x02, 0x09, 0x09, 0x0a, 0x04, + 0xfe, 0xf8, 0xf5, 0xf1, 0xf0, 0xe7, 0xe6, 0xe8, 0xf0, 0xf8, 0xfa, 0xfb, + 0xf7, 0xf3, 0xf0, 0xf1, 0xf8, 0x0d, 0x11, 0x15, 0x12, 0x0c, 0x08, 0x04, + 0x05, 0x00, 0x00, 0x00, 0x07, 0x06, 0x03, 0x06, 0x12, 0x21, 0x1e, 0x12, + 0x0c, 0x0b, 0x0a, 0x09, 0x0b, 0x06, 0x02, 0x03, 0x04, 0x03, 0x09, 0x0b, + 0x03, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xf9, 0x08, 0x0a, 0x05, 0x04, 0x00, + 0xfe, 0xfe, 0xf7, 0xf5, 0x04, 0x19, 0x12, 0x0b, 0x07, 0x03, 0xfe, 0xfe, + 0xfe, 0xfc, 0xfc, 0xfc, 0xfa, 0xf6, 0xf3, 0xf1, 0xf4, 0x00, 0x06, 0xfc, + 0xfa, 0xfb, 0xfa, 0xfa, 0xf9, 0x00, 0x0b, 0x0c, 0x09, 0x01, 0x01, 0x02, + 0x00, 0x01, 0x00, 0xfc, 0xf7, 0xf8, 0x00, 0x0b, 0x0b, 0x08, 0x06, 0x05, + 0x0c, 0x11, 0x06, 0x05, 0x1a, 0x2a, 0x23, 0x1d, 0x1d, 0x16, 0x0e, 0x08, + 0x04, 0x06, 0x09, 0x0c, 0x08, 0x03, 0x02, 0x02, 0x02, 0x08, 0x0c, 0x0a, + 0x06, 0x01, 0x01, 0x00, 0xfb, 0xf7, 0xef, 0xe6, 0xec, 0xf4, 0xf7, 0xf0, + 0xec, 0xec, 0xf0, 0xf9, 0xf4, 0xf0, 0xf4, 0xf9, 0xfb, 0xfd, 0xff, 0xfe, + 0xfb, 0xf9, 0xfe, 0x06, 0x12, 0x1d, 0x18, 0x1c, 0x1c, 0x1f, 0x1c, 0x13, + 0x0d, 0x15, 0x10, 0x0b, 0x08, 0x05, 0x05, 0x06, 0x00, 0x04, 0x0c, 0x0c, + 0x0a, 0x07, 0x01, 0x00, 0xfe, 0xfc, 0xfe, 0xff, 0xfb, 0xfd, 0xfb, 0xf7, + 0xf8, 0xf6, 0xf1, 0xeb, 0xf1, 0xf8, 0x05, 0x08, 0x00, 0x00, 0x00, 0x04, + 0x0f, 0x08, 0x04, 0x06, 0x0d, 0x19, 0x11, 0x0d, 0x0d, 0x0a, 0x08, 0x07, + 0x04, 0x05, 0x06, 0x00, 0xfb, 0xff, 0x05, 0x03, 0xf5, 0xff, 0x16, 0x0d, + 0x08, 0x05, 0x03, 0x00, 0xfd, 0xf6, 0xfa, 0x05, 0x06, 0x04, 0xfe, 0xf7, + 0xf7, 0xf7, 0xf6, 0xf5, 0xf5, 0xfc, 0x06, 0x01, 0x01, 0x05, 0x05, 0xfd, + 0xfa, 0xff, 0x04, 0x02, 0x08, 0x11, 0x08, 0x08, 0x0f, 0x15, 0x0b, 0x0a, + 0x08, 0x09, 0x0b, 0x06, 0x04, 0x05, 0x08, 0x07, 0x08, 0x0d, 0x15, 0x0b, + 0x08, 0x0a, 0x09, 0x07, 0x00, 0xfe, 0x00, 0x06, 0x0b, 0x05, 0xff, 0xfc, + 0xfc, 0xf5, 0xea, 0xe9, 0xee, 0xf7, 0xfa, 0xf7, 0xf6, 0xfd, 0x00, 0xfa, + 0xfa, 0x00, 0x00, 0x00, 0x08, 0x10, 0x10, 0x11, 0x0b, 0x06, 0xfe, 0x00, + 0x02, 0x01, 0xff, 0xfd, 0xfe, 0x02, 0x0f, 0x0d, 0x0b, 0x11, 0x18, 0x0f, + 0x08, 0x08, 0x08, 0x06, 0x05, 0x06, 0x02, 0x02, 0x06, 0x06, 0x02, 0x02, + 0x08, 0x03, 0xfe, 0xfe, 0x06, 0x0a, 0x09, 0x09, 0x07, 0x02, 0xfe, 0xfb, + 0xfe, 0x01, 0x00, 0xfe, 0x05, 0x0f, 0x0a, 0x06, 0x02, 0x00, 0x00, 0xfa, + 0xfb, 0xfa, 0xf6, 0xf3, 0xf1, 0xf0, 0xf4, 0xf6, 0xf8, 0x02, 0x0d, 0x04, + 0xff, 0xfd, 0x03, 0x0d, 0x04, 0x00, 0x07, 0x06, 0x03, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x0a, 0x10, 0x0f, 0x12, 0x16, 0x10, 0x06, + 0x06, 0x08, 0x0c, 0x0c, 0x1a, 0x1c, 0x11, 0x0f, 0x0f, 0x0c, 0x0a, 0x07, + 0x03, 0x01, 0x04, 0x06, 0x02, 0x02, 0x00, 0xfc, 0xfc, 0x04, 0x0e, 0x01, + 0xfa, 0xfc, 0xfa, 0xf7, 0xf6, 0xfa, 0xf2, 0xeb, 0xf0, 0xed, 0xe9, 0xf1, + 0xf8, 0xef, 0xee, 0xf0, 0xf1, 0xf8, 0x00, 0xfe, 0xfe, 0x03, 0x04, 0x07, + 0x0a, 0x06, 0x02, 0x03, 0x15, 0x1b, 0x1e, 0x1c, 0x15, 0x0c, 0x12, 0x1b, + 0x12, 0x0f, 0x10, 0x0d, 0x0d, 0x0f, 0x0b, 0x07, 0x07, 0x15, 0x14, 0x04, + 0x01, 0x04, 0x02, 0x00, 0xfe, 0xfd, 0xfc, 0x00, 0x00, 0xfc, 0xfc, 0xfa, + 0xef, 0xeb, 0xf4, 0xf8, 0xf7, 0xfa, 0xfe, 0xfe, 0x04, 0x0e, 0x0a, 0x0a, + 0x04, 0x00, 0x00, 0x03, 0x14, 0x12, 0x0d, 0x0d, 0x0a, 0x07, 0x04, 0x01, + 0xfe, 0xfe, 0x00, 0x05, 0x02, 0xfc, 0xfa, 0x00, 0x04, 0x0d, 0x08, 0xfe, + 0x00, 0x04, 0x01, 0xf9, 0xf3, 0xf7, 0x01, 0x01, 0xfe, 0xfc, 0xfc, 0xfa, + 0xf5, 0xf4, 0xf6, 0xfc, 0x00, 0x04, 0x0e, 0x0b, 0x04, 0x02, 0x06, 0x06, + 0x00, 0xfc, 0x00, 0x08, 0x1b, 0x1f, 0x22, 0x15, 0x10, 0x0f, 0x0d, 0x08, + 0x08, 0x0d, 0x0e, 0x0e, 0x0b, 0x0c, 0x0a, 0x09, 0x08, 0x10, 0x08, 0x03, + 0x0c, 0x07, 0xf8, 0xf6, 0x00, 0x00, 0xfc, 0xfc, 0xfd, 0xfc, 0xf8, 0xf2, + 0xeb, 0xec, 0xee, 0xee, 0xee, 0xf6, 0xfe, 0xf9, 0xfa, 0x00, 0x00, 0xfe, + 0x00, 0x00, 0xfc, 0x03, 0x11, 0x0b, 0x0a, 0x08, 0x08, 0x01, 0xfd, 0xfe, + 0xfd, 0x00, 0x0e, 0x11, 0x08, 0x09, 0x0c, 0x0a, 0x10, 0x14, 0x0c, 0x02, + 0x04, 0x0a, 0x0a, 0x06, 0x04, 0x00, 0x00, 0x08, 0x0b, 0x06, 0x00, 0xff, + 0x01, 0x0a, 0x08, 0x06, 0x08, 0x10, 0x14, 0x0e, 0x08, 0x04, 0x03, 0xfe, + 0xff, 0x00, 0x00, 0x12, 0x14, 0x07, 0x05, 0x06, 0x04, 0x00, 0xfc, 0xfa, + 0xfa, 0xfa, 0xf4, 0xea, 0xe9, 0xee, 0xec, 0xec, 0xfe, 0x00, 0xf8, 0x04, + 0x07, 0x02, 0xfe, 0xfa, 0xfc, 0x01, 0x00, 0x02, 0x00, 0x00, 0x04, 0x04, + 0x02, 0x01, 0x00, 0x02, 0x04, 0x04, 0x10, 0x15, 0x12, 0x16, 0x10, 0x08, + 0x08, 0x0c, 0x16, 0x25, 0x19, 0x0d, 0x0a, 0x0b, 0x0b, 0x09, 0x06, 0x04, + 0x05, 0x04, 0x04, 0x02, 0x00, 0x00, 0x00, 0x04, 0x0c, 0x04, 0xfc, 0xf6, + 0xf0, 0xf4, 0xf7, 0xf6, 0xf3, 0xf2, 0xf4, 0xfa, 0x04, 0x00, 0xfb, 0xf6, + 0xf4, 0xf4, 0xf2, 0xf2, 0xf8, 0xfd, 0x06, 0x0e, 0x10, 0x0c, 0x06, 0x00, + 0x00, 0x03, 0x0a, 0x12, 0x0c, 0x14, 0x1c, 0x15, 0x0e, 0x10, 0x10, 0x12, + 0x12, 0x0f, 0x05, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x0e, 0x05, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xfe, 0xfa, 0xfa, 0xfa, 0xfa, 0xf8, 0xf4, 0xf0, + 0xf0, 0xf0, 0xf2, 0xf6, 0x00, 0x0a, 0x0a, 0x0a, 0x0b, 0x0c, 0x05, 0x00, + 0x00, 0x04, 0x14, 0x1a, 0x16, 0x10, 0x0c, 0x08, 0x07, 0x05, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x06, 0x00, 0x00, 0x06, 0x16, 0x10, 0x0b, 0xff, 0xf7, + 0xf6, 0xfc, 0xf8, 0xf9, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x02, 0x02, 0x02, + 0xfd, 0xf9, 0xfb, 0x00, 0xf8, 0xec, 0xf6, 0x00, 0x04, 0x04, 0x00, 0x00, + 0x02, 0x16, 0x29, 0x20, 0x18, 0x12, 0x0e, 0x0c, 0x08, 0x0a, 0x0d, 0x0b, + 0x0a, 0x0b, 0x0a, 0x04, 0x00, 0x00, 0x08, 0x07, 0x02, 0x00, 0x00, 0x03, + 0x00, 0x06, 0x04, 0x00, 0xff, 0x00, 0xf8, 0xf6, 0xf6, 0xf3, 0xf0, 0xec, + 0xee, 0xf0, 0xf4, 0xf8, 0xf6, 0xf6, 0x00, 0x08, 0x08, 0x01, 0xfc, 0xfd, + 0xfe, 0x0a, 0x12, 0x0a, 0x02, 0x07, 0x08, 0x06, 0x08, 0x12, 0x1c, 0x14, + 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x07, 0x13, 0x12, 0x10, 0x0a, 0x0a, 0x0c, + 0x08, 0x06, 0x04, 0x00, 0x00, 0xf8, 0xf0, 0x04, 0x0e, 0x0b, 0x04, 0x00, + 0x00, 0x03, 0x04, 0x00, 0xff, 0xfa, 0x00, 0x03, 0x02, 0x00, 0x00, 0xfe, + 0x02, 0x14, 0x10, 0x0a, 0x06, 0x02, 0x00, 0xfe, 0xfc, 0xfa, 0xf4, 0xee, + 0xe8, 0xea, 0xed, 0xec, 0xf2, 0x02, 0x08, 0x0b, 0x00, 0xfc, 0xff, 0x00, + 0xff, 0xff, 0x02, 0x05, 0x04, 0x01, 0x05, 0x0c, 0x0c, 0x04, 0x00, 0xff, + 0x00, 0x02, 0x04, 0x04, 0x0c, 0x0e, 0x1a, 0x1e, 0x17, 0x16, 0x12, 0x10, + 0x18, 0x23, 0x14, 0x0e, 0x0c, 0x0a, 0x0c, 0x0c, 0x0c, 0x0a, 0x06, 0x08, + 0x08, 0x04, 0xfc, 0xf8, 0x00, 0x04, 0xf8, 0xea, 0xe9, 0xec, 0xf3, 0xf4, + 0xf2, 0xf6, 0xf8, 0x05, 0x01, 0xfa, 0xfa, 0xfa, 0xf6, 0xf2, 0xf0, 0xf0, + 0xf0, 0xf6, 0xf8, 0xfc, 0x00, 0xff, 0x00, 0xfe, 0x00, 0x05, 0x04, 0x02, + 0x15, 0x1f, 0x24, 0x1c, 0x16, 0x16, 0x12, 0x10, 0x0e, 0x0e, 0x0a, 0x04, + 0x02, 0x00, 0xfe, 0x04, 0x12, 0x0a, 0x08, 0x06, 0x02, 0x04, 0x06, 0x02, + 0x00, 0x00, 0xfc, 0xfc, 0xfa, 0xf9, 0xf5, 0xf5, 0xfd, 0xfb, 0xf9, 0x04, + 0x0f, 0x07, 0x01, 0x03, 0x04, 0x01, 0x05, 0x05, 0x03, 0x05, 0x05, 0x12, + 0x23, 0x1d, 0x11, 0x04, 0x01, 0x03, 0x02, 0xf5, 0xfd, 0x01, 0x07, 0x0b, + 0x00, 0xf9, 0xfe, 0x0d, 0x05, 0xfb, 0xf9, 0xf5, 0xf5, 0xfb, 0xfb, 0xf7, + 0xfd, 0x07, 0x02, 0xff, 0xfc, 0xfd, 0x01, 0x00, 0xfd, 0xf9, 0xf9, 0xf6, + 0xf1, 0xed, 0xf1, 0xef, 0xf7, 0x01, 0x09, 0x09, 0x17, 0x19, 0x15, 0x24, + 0x21, 0x17, 0x11, 0x0d, 0x0c, 0x0b, 0x0d, 0x12, 0x13, 0x0f, 0x0b, 0x03, + 0x00, 0x00, 0xf5, 0xf9, 0xf5, 0xf1, 0xf1, 0xf5, 0xfb, 0xfb, 0xf7, 0xf7, + 0xfd, 0xfb, 0xf1, 0xf5, 0xfb, 0xfd, 0x05, 0x13, 0x19, 0x17, 0x13, 0x11, + 0x11, 0x17, 0x1f, 0x23, 0x23, 0x23, 0x21, 0x23, 0x21, 0x17, 0x09, 0x00, + 0xfb, 0xf1, 0xeb, 0xef, 0xef, 0xed, 0xe7, 0xe5, 0xeb, 0xf7, 0xf9, 0xf7, + 0xfb, 0xf9, 0xf5, 0xf9, 0xf9, 0xf8, 0xfd, 0x09, 0x0d, 0x07, 0x03, 0x03, + 0x00, 0x03, 0x0b, 0x0f, 0x07, 0x00, 0xfd, 0xf1, 0xeb, 0xf3, 0xfd, 0x09, + 0x0b, 0x05, 0x07, 0x18, 0x20, 0x1d, 0x1c, 0x21, 0x20, 0x17, 0x13, 0x13, + 0x0d, 0x05, 0xff, 0xf7, 0xf1, 0xf7, 0x02, 0x09, 0x08, 0x00, 0xf3, 0xed, + 0xed, 0xee, 0xf3, 0xfa, 0x01, 0x05, 0x00, 0xf5, 0xfb, 0x04, 0x03, 0xfd, + 0xf9, 0xf3, 0xf4, 0xfa, 0xf9, 0xf5, 0xfe, 0x08, 0x06, 0x00, 0x00, 0x02, + 0x01, 0x07, 0x0e, 0x0a, 0x08, 0x12, 0x1c, 0x1a, 0x16, 0x12, 0x0e, 0x0e, + 0x0b, 0x06, 0x10, 0x1d, 0x1c, 0x0d, 0x02, 0xfd, 0xfe, 0x00, 0xff, 0xf7, + 0xea, 0xe8, 0xef, 0xf0, 0xec, 0xec, 0xf6, 0x00, 0x02, 0x02, 0xfe, 0xfc, + 0xf8, 0xf6, 0xf8, 0xfc, 0x06, 0x10, 0x12, 0x0c, 0x0e, 0x14, 0x12, 0x10, + 0x0b, 0x04, 0x08, 0x0c, 0x04, 0xfa, 0xf0, 0xf2, 0xf7, 0xfc, 0xff, 0x00, + 0x00, 0x07, 0x10, 0x0c, 0x04, 0x08, 0x10, 0x0e, 0x0a, 0x08, 0x08, 0x06, + 0x00, 0xfc, 0xfe, 0x04, 0x08, 0x0e, 0x0c, 0x00, 0xf9, 0xf6, 0xf4, 0xf6, + 0xfa, 0x02, 0x0c, 0x0e, 0x04, 0x00, 0x0a, 0x16, 0x1a, 0x10, 0xff, 0xf4, + 0xf0, 0xf6, 0xf8, 0xf3, 0xf2, 0xf6, 0xf4, 0xf0, 0xf6, 0xfd, 0xfa, 0xf6, + 0xf4, 0xf0, 0xfa, 0x0c, 0x1a, 0x1c, 0x16, 0x0e, 0x0e, 0x10, 0x11, 0x13, + 0x16, 0x21, 0x28, 0x1c, 0x04, 0xfd, 0xff, 0x05, 0x07, 0x06, 0x00, 0xf5, + 0xef, 0xf6, 0xfc, 0xfe, 0x00, 0x08, 0x08, 0xfe, 0xfe, 0x00, 0xfc, 0xf6, + 0xf2, 0xec, 0xf5, 0xfe, 0x00, 0x02, 0x07, 0x09, 0x08, 0x00, 0xf7, 0xf4, + 0xfa, 0x02, 0x02, 0xf6, 0xf0, 0xf3, 0xfb, 0x04, 0x0d, 0x0e, 0x0a, 0x08, + 0x09, 0x0a, 0x08, 0x0a, 0x16, 0x1c, 0x18, 0x10, 0x12, 0x0e, 0x08, 0x0a, + 0x11, 0x18, 0x20, 0x1e, 0x0c, 0x00, 0xfb, 0xf7, 0xed, 0xea, 0xee, 0xee, + 0xf2, 0xfc, 0xfe, 0xf9, 0xfa, 0x00, 0xff, 0xfc, 0xfa, 0xf8, 0xf2, 0xf2, + 0xf7, 0xf5, 0xf4, 0xf9, 0xfd, 0xfe, 0x00, 0x04, 0x08, 0x00, 0xf4, 0xf0, + 0xfa, 0x0e, 0x21, 0x25, 0x20, 0x18, 0x15, 0x14, 0x1c, 0x28, 0x28, 0x25, + 0x21, 0x19, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xf8, 0xef, 0xe6, 0xef, + 0xfb, 0xf7, 0xf5, 0xf4, 0xf1, 0xf4, 0xfa, 0xfe, 0xfa, 0xf4, 0xf0, 0xf0, + 0xf6, 0x00, 0x06, 0x0a, 0x0a, 0x0a, 0x02, 0xfc, 0xfd, 0xff, 0xfe, 0x02, + 0x06, 0x00, 0xfb, 0x01, 0x05, 0x17, 0x26, 0x29, 0x26, 0x14, 0x04, 0x03, + 0x06, 0x04, 0x03, 0x08, 0x0a, 0x07, 0x02, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x03, 0x08, 0x0a, 0x06, 0xff, 0xfa, 0xf2, 0xed, 0xf4, 0xf6, 0xf8, 0x01, + 0x06, 0x04, 0x05, 0x03, 0xfb, 0xfd, 0x01, 0x01, 0xff, 0xf7, 0xf9, 0x00, + 0xfe, 0xfa, 0x00, 0x0c, 0x12, 0x0c, 0x04, 0xfe, 0xf8, 0xf2, 0xf3, 0x00, + 0x0c, 0x10, 0x14, 0x0e, 0x0a, 0x14, 0x17, 0x1b, 0x1c, 0x14, 0x06, 0x08, + 0x0a, 0x04, 0x01, 0x01, 0x05, 0x09, 0x01, 0xfb, 0xf7, 0xf4, 0xf9, 0xfe, + 0xf4, 0xee, 0xf6, 0x00, 0x03, 0x03, 0xfe, 0xfa, 0xfb, 0xfa, 0x00, 0x12, + 0x1c, 0x1f, 0x1c, 0x0c, 0x00, 0xf9, 0xf5, 0xf0, 0xec, 0xea, 0xf0, 0xf4, + 0xf0, 0xf2, 0xff, 0x0b, 0x12, 0x13, 0x0d, 0x0c, 0x06, 0x06, 0x0a, 0x0c, + 0x04, 0x06, 0x14, 0x15, 0x12, 0x11, 0x0d, 0x0b, 0x0a, 0x03, 0x02, 0x0c, + 0x14, 0x10, 0x00, 0xfb, 0x00, 0xfe, 0xfa, 0xfc, 0x02, 0x06, 0x06, 0x03, + 0x01, 0xfd, 0xf7, 0xf2, 0xf0, 0xf2, 0xec, 0xec, 0xf2, 0xf5, 0xfb, 0xfa, + 0xf8, 0xff, 0x05, 0xff, 0xfa, 0xfd, 0xfc, 0xf7, 0xf4, 0x00, 0x15, 0x1c, + 0x17, 0x10, 0x11, 0x14, 0x19, 0x19, 0x17, 0x15, 0x13, 0x0d, 0x0b, 0x0b, + 0x06, 0x08, 0x10, 0x15, 0x15, 0x13, 0x10, 0x0e, 0x0a, 0xff, 0xef, 0xe6, + 0xe8, 0xe9, 0xea, 0xf0, 0xf7, 0xf3, 0xeb, 0xe7, 0xed, 0xfb, 0x04, 0x02, + 0x04, 0x04, 0x00, 0xfd, 0xfd, 0xf8, 0xf0, 0xf3, 0xf6, 0xf8, 0xfe, 0x04, + 0x09, 0x16, 0x1d, 0x1a, 0x11, 0x13, 0x16, 0x0f, 0x07, 0x0d, 0x12, 0x13, + 0x16, 0x1b, 0x1f, 0x1b, 0x17, 0x0e, 0x02, 0xfa, 0xfc, 0x02, 0x02, 0xfe, + 0xf6, 0xf3, 0xf5, 0xfd, 0xff, 0xf9, 0xf7, 0xfa, 0xf8, 0xf4, 0xf8, 0xfe, + 0xfb, 0xf1, 0xef, 0xf7, 0xf9, 0xfb, 0xfd, 0xfc, 0xfa, 0xfa, 0xf8, 0xfa, + 0x00, 0x04, 0x02, 0x04, 0x04, 0x00, 0xfc, 0x08, 0x1c, 0x29, 0x29, 0x25, + 0x21, 0x21, 0x21, 0x19, 0x0c, 0x05, 0x00, 0xf2, 0xec, 0xf8, 0x03, 0x03, + 0x01, 0x04, 0x06, 0x00, 0xfe, 0x02, 0x00, 0xfc, 0xf7, 0xf5, 0xf3, 0xef, + 0xf1, 0xf4, 0xfc, 0x04, 0xfe, 0xf4, 0xf4, 0x00, 0x0a, 0x0a, 0x07, 0x04, + 0xfe, 0xfd, 0x01, 0x01, 0xff, 0xfc, 0xf6, 0xf6, 0xff, 0x0b, 0x14, 0x14, + 0x12, 0x09, 0x03, 0x04, 0x04, 0x00, 0x00, 0x02, 0x0b, 0x12, 0x10, 0x12, + 0x12, 0x11, 0x12, 0x0f, 0x03, 0xfd, 0xfe, 0x01, 0x04, 0x08, 0x02, 0xfa, + 0xfc, 0x00, 0x02, 0xff, 0xfc, 0xf2, 0xee, 0xf0, 0xfa, 0x02, 0x02, 0xfc, + 0xf8, 0xf9, 0x02, 0x0c, 0x0c, 0x0d, 0x0c, 0x03, 0xfc, 0xf4, 0xf2, 0xf0, + 0xea, 0xec, 0xf7, 0xfd, 0x00, 0x01, 0x09, 0x13, 0x15, 0x12, 0x0c, 0x12, + 0x19, 0x19, 0x17, 0x12, 0x05, 0xf9, 0xf6, 0xfd, 0x0b, 0x14, 0x14, 0x10, + 0x0e, 0x0c, 0x0f, 0x0d, 0x07, 0x00, 0xfa, 0xfa, 0xfd, 0x00, 0x00, 0xfe, + 0xfc, 0x02, 0x00, 0xfc, 0xf4, 0xf4, 0xf8, 0xf8, 0xf8, 0xf2, 0xec, 0xee, + 0xf3, 0xf7, 0xfd, 0xf9, 0xee, 0xec, 0xf4, 0x00, 0x10, 0x1a, 0x14, 0x07, + 0x05, 0x09, 0x0e, 0x12, 0x15, 0x13, 0x10, 0x0e, 0x11, 0x14, 0x15, 0x13, + 0x11, 0x11, 0x10, 0x0a, 0x06, 0x0c, 0x0c, 0x0c, 0x0e, 0x0a, 0x06, 0x0a, + 0x0e, 0x0b, 0x01, 0xf0, 0xda, 0xd2, 0xd8, 0xe0, 0xed, 0xf6, 0xf2, 0xf0, + 0xf0, 0xf4, 0xfa, 0x00, 0x02, 0x00, 0xf9, 0xf9, 0xfc, 0xfe, 0xfa, 0xf8, + 0xff, 0x09, 0x10, 0x11, 0x16, 0x1b, 0x1c, 0x1c, 0x1c, 0x1a, 0x12, 0x13, + 0x19, 0x16, 0x0f, 0x05, 0x01, 0x03, 0x05, 0x0a, 0x12, 0x12, 0x0c, 0x03, + 0xfd, 0xfc, 0xfd, 0xf8, 0xf7, 0xf3, 0xf3, 0xf8, 0xfc, 0xfc, 0xf1, 0xf1, + 0xfa, 0xfe, 0xfe, 0xfe, 0xf7, 0xf2, 0xf5, 0xf4, 0xf7, 0xfc, 0xfd, 0xfe, + 0xfe, 0xf9, 0xf2, 0xf3, 0xf8, 0x00, 0x07, 0x12, 0x1c, 0x1a, 0x11, 0x10, + 0x11, 0x15, 0x1c, 0x24, 0x20, 0x16, 0x12, 0x15, 0x18, 0x0c, 0xfa, 0xf8, + 0xfb, 0xfb, 0x03, 0x0a, 0x04, 0xfe, 0xfb, 0xf8, 0xfd, 0x02, 0x06, 0x08, + 0x04, 0xf8, 0xeb, 0xe2, 0xe2, 0xe4, 0xea, 0xf4, 0x01, 0x03, 0xfe, 0xff, + 0x02, 0x06, 0x0c, 0x0a, 0xfd, 0xf6, 0xfa, 0x03, 0x07, 0x06, 0x07, 0x0d, + 0x0f, 0x10, 0x15, 0x13, 0x0e, 0x0a, 0x05, 0x06, 0x08, 0x07, 0x09, 0x0a, + 0x04, 0xfa, 0xfd, 0x02, 0xfe, 0xff, 0x06, 0x17, 0x1b, 0x0e, 0x00, 0xfc, + 0xfc, 0x00, 0x08, 0x0c, 0x02, 0xfe, 0x00, 0x00, 0xfe, 0xf9, 0xf7, 0xf8, + 0xfe, 0x03, 0x02, 0xfc, 0xfc, 0xfa, 0xf8, 0xf6, 0x00, 0x02, 0xfe, 0xf8, + 0xf3, 0xf5, 0xf9, 0xf6, 0xef, 0xef, 0xfa, 0x08, 0x0f, 0x0c, 0x07, 0x06, + 0x0a, 0x10, 0x1e, 0x20, 0x16, 0x14, 0x18, 0x17, 0x0f, 0x06, 0x07, 0x0d, + 0x11, 0x0c, 0x0d, 0x0d, 0x08, 0x04, 0x05, 0x0e, 0x0d, 0x0b, 0x04, 0xf6, + 0xed, 0xef, 0xef, 0xe6, 0xe2, 0xeb, 0xf4, 0xf7, 0xfc, 0xfa, 0xf4, 0xf6, + 0xf8, 0xf8, 0xf7, 0xf2, 0xef, 0xf8, 0xfd, 0xfd, 0x01, 0x07, 0x0a, 0x14, + 0x1b, 0x1b, 0x17, 0x12, 0x07, 0x01, 0x08, 0x14, 0x1a, 0x13, 0x09, 0x03, + 0x05, 0x0a, 0x0c, 0x05, 0x04, 0x0a, 0x15, 0x18, 0x0f, 0x05, 0x04, 0x06, + 0x04, 0x08, 0x11, 0x0b, 0xfe, 0xff, 0x01, 0xf7, 0xed, 0xec, 0xea, 0xe8, + 0xec, 0xf3, 0xf7, 0xf1, 0xed, 0xee, 0xf1, 0xf5, 0xfc, 0xf8, 0xf5, 0xfc, + 0x01, 0x00, 0xfc, 0xfb, 0x02, 0x09, 0x10, 0x12, 0x11, 0x14, 0x16, 0x1c, + 0x23, 0x27, 0x28, 0x20, 0x17, 0x14, 0x0f, 0x10, 0x12, 0x0e, 0x10, 0x11, + 0x09, 0x02, 0xff, 0xfa, 0xf7, 0xfc, 0x00, 0xfe, 0xf1, 0xec, 0xf0, 0xee, + 0xe7, 0xdd, 0xd8, 0xda, 0xe5, 0xf6, 0x02, 0x04, 0x02, 0x00, 0xfa, 0xf5, + 0xfa, 0x04, 0x03, 0xff, 0x06, 0x0e, 0x10, 0x15, 0x17, 0x18, 0x1a, 0x1b, + 0x18, 0x11, 0x0a, 0x0b, 0x0e, 0x15, 0x14, 0x09, 0x01, 0x01, 0x02, 0x03, + 0x00, 0x00, 0xfe, 0xff, 0xfa, 0xfa, 0x02, 0x02, 0x00, 0xfd, 0xff, 0x01, + 0x09, 0x12, 0x10, 0x09, 0x07, 0x03, 0xfb, 0xee, 0xef, 0xfd, 0xff, 0xf9, + 0xf9, 0xf6, 0xf5, 0xfb, 0x01, 0x01, 0xf9, 0xf5, 0xfa, 0x04, 0x03, 0xff, + 0x01, 0x00, 0xfe, 0xff, 0x03, 0x0b, 0x0d, 0x09, 0x0a, 0x0b, 0x11, 0x1a, + 0x1d, 0x14, 0x0c, 0x0d, 0x0f, 0x0d, 0x08, 0x06, 0x0e, 0x14, 0x10, 0x0b, + 0x07, 0x05, 0x02, 0x06, 0x03, 0xfd, 0xfa, 0xf9, 0xf8, 0xf8, 0xf7, 0xf2, + 0xe8, 0xe6, 0xeb, 0xf0, 0xf9, 0x04, 0x06, 0xfe, 0x00, 0x00, 0xfa, 0xfc, + 0xfd, 0xfc, 0xfe, 0x07, 0x0e, 0x06, 0x06, 0x13, 0x1c, 0x14, 0x05, 0xfd, + 0xfc, 0xfe, 0x01, 0x0a, 0x11, 0x0b, 0x02, 0x02, 0x0b, 0x0f, 0x0c, 0x08, + 0x01, 0xff, 0x05, 0x07, 0x07, 0x0a, 0x04, 0x02, 0x06, 0x0f, 0x12, 0x13, + 0x18, 0x18, 0x14, 0x0d, 0x00, 0xef, 0xef, 0xf9, 0xf7, 0xee, 0xf0, 0xf4, + 0xf0, 0xee, 0xf0, 0xf1, 0xed, 0xe8, 0xe4, 0xed, 0xff, 0x02, 0xfa, 0xf9, + 0xf6, 0xf6, 0xfa, 0x02, 0x0a, 0x0e, 0x14, 0x18, 0x1d, 0x1f, 0x1f, 0x1d, + 0x1a, 0x1a, 0x18, 0x18, 0x1b, 0x1d, 0x23, 0x26, 0x1c, 0x11, 0x0b, 0x04, + 0xfe, 0x00, 0x06, 0x01, 0xf5, 0xec, 0xea, 0xec, 0xee, 0xe6, 0xda, 0xd3, + 0xdb, 0xe4, 0xed, 0xf1, 0xf3, 0xf1, 0xf1, 0xf6, 0xf6, 0xf9, 0xff, 0x04, + 0x10, 0x19, 0x1b, 0x17, 0x15, 0x19, 0x1d, 0x1d, 0x15, 0x0a, 0x06, 0x02, + 0x05, 0x0d, 0x11, 0x0c, 0x06, 0x08, 0x0e, 0x13, 0x13, 0x0f, 0x09, 0xff, + 0xfb, 0xfb, 0xf8, 0xfb, 0x02, 0x01, 0x00, 0x00, 0x02, 0x06, 0x0c, 0x0f, + 0x0b, 0x07, 0xfb, 0xf1, 0xf0, 0xf5, 0xf5, 0xef, 0xeb, 0xec, 0xf2, 0xf7, + 0xfd, 0xfe, 0xf8, 0xf1, 0xf2, 0xf6, 0xfb, 0x01, 0x05, 0x0a, 0x0b, 0x09, + 0x0b, 0x0d, 0x0d, 0x0d, 0x11, 0x14, 0x17, 0x1e, 0x1a, 0x16, 0x14, 0x12, + 0x12, 0x0d, 0x03, 0x06, 0x11, 0x16, 0x16, 0x10, 0x0a, 0x02, 0xf6, 0xee, + 0xf0, 0xef, 0xf0, 0xf9, 0xfc, 0xfb, 0xf8, 0xf9, 0xf5, 0xec, 0xe3, 0xe2, + 0xea, 0xf3, 0xf3, 0xf7, 0xfc, 0x01, 0x01, 0xfd, 0xf9, 0x04, 0x19, 0x21, + 0x24, 0x1d, 0x1d, 0x23, 0x23, 0x14, 0x01, 0xfc, 0xfc, 0xfe, 0xfe, 0x04, + 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x04, 0x02, 0xfe, 0xfb, 0xfc, + 0xff, 0xfa, 0xf0, 0xfa, 0x0a, 0x11, 0x0f, 0x0f, 0x16, 0x1c, 0x1e, 0x13, + 0x01, 0xfc, 0x06, 0x0b, 0x06, 0x00, 0x00, 0x02, 0xfd, 0xf5, 0xf2, 0xf4, + 0xf3, 0xef, 0xf0, 0xea, 0xea, 0xef, 0xf5, 0xf3, 0xee, 0xf1, 0xf9, 0xfb, + 0xff, 0x02, 0x06, 0x0d, 0x12, 0x09, 0x04, 0x10, 0x1a, 0x22, 0x28, 0x2b, + 0x22, 0x20, 0x26, 0x23, 0x1a, 0x1b, 0x18, 0x0b, 0xff, 0xfa, 0xfa, 0xf8, + 0xf7, 0xf5, 0xf4, 0xfa, 0xfd, 0xfa, 0xf6, 0xf8, 0xf5, 0xed, 0xe4, 0xd8, + 0xd4, 0xdf, 0xea, 0xf8, 0xfc, 0xfb, 0xfe, 0x01, 0x06, 0x0e, 0x17, 0x1b, + 0x17, 0x18, 0x19, 0x10, 0x0d, 0x08, 0xff, 0xf6, 0xf7, 0xff, 0x03, 0x07, + 0x0d, 0x10, 0x13, 0x10, 0x0d, 0x02, 0x03, 0x12, 0x12, 0x0e, 0x0c, 0x0d, + 0x0d, 0x0b, 0x0a, 0x07, 0x09, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x02, 0xf7, + 0xf0, 0xee, 0xec, 0xeb, 0xf2, 0xf3, 0xee, 0xef, 0xf1, 0xe8, 0xe7, 0xe6, + 0xe9, 0xf6, 0xfb, 0xfc, 0x00, 0x09, 0x14, 0x11, 0x07, 0x00, 0x02, 0x05, + 0x07, 0x0b, 0x10, 0x16, 0x19, 0x16, 0x0f, 0x15, 0x25, 0x2e, 0x2f, 0x2d, + 0x28, 0x26, 0x22, 0x19, 0x0f, 0xff, 0xf0, 0xf0, 0xea, 0xe7, 0xec, 0xf4, + 0xf9, 0xf7, 0xf0, 0xe8, 0xe9, 0xf0, 0xef, 0xe7, 0xe1, 0xde, 0xdd, 0xde, + 0xe2, 0xe8, 0xf5, 0x01, 0x08, 0x0c, 0x12, 0x1f, 0x26, 0x26, 0x29, 0x25, + 0x22, 0x26, 0x21, 0x1a, 0x17, 0x14, 0x0d, 0x06, 0xff, 0xfd, 0x03, 0x02, + 0x02, 0x03, 0xfe, 0xf7, 0xf4, 0xf6, 0xf3, 0xf0, 0xef, 0xf2, 0xf9, 0xfe, + 0xfe, 0x01, 0x04, 0x06, 0x04, 0x00, 0x07, 0x17, 0x18, 0x15, 0x1a, 0x17, + 0x0e, 0x07, 0x01, 0x01, 0xfd, 0xf1, 0xeb, 0xeb, 0xef, 0xf6, 0xf7, 0xf6, + 0xf5, 0xf4, 0xf5, 0xfc, 0x0a, 0x13, 0x0f, 0x03, 0xf9, 0xf7, 0xf9, 0xf8, + 0xfc, 0x01, 0x07, 0x09, 0x0d, 0x15, 0x21, 0x29, 0x28, 0x28, 0x25, 0x1b, + 0x15, 0x15, 0x14, 0x0e, 0xfb, 0xec, 0xe6, 0xe6, 0xee, 0xf4, 0xfc, 0x02, + 0x02, 0xfd, 0xf6, 0xf6, 0xfd, 0xff, 0xfa, 0xf4, 0xef, 0xf2, 0xf7, 0xfd, + 0x02, 0x02, 0x08, 0x0a, 0x03, 0x06, 0x12, 0x15, 0x16, 0x15, 0x0a, 0x03, + 0xfe, 0xff, 0x00, 0xfd, 0xf7, 0xf6, 0xf4, 0xf5, 0xfa, 0xff, 0x05, 0x07, + 0x0b, 0x0b, 0x09, 0x11, 0x19, 0x16, 0x0d, 0x09, 0x0a, 0x0a, 0x05, 0x04, + 0x04, 0x09, 0x0f, 0x07, 0xfe, 0x09, 0x13, 0x15, 0x15, 0x12, 0x0b, 0x0a, + 0x06, 0xfe, 0xf1, 0xe6, 0xdc, 0xda, 0xde, 0xe4, 0xec, 0xf4, 0xf9, 0xfa, + 0xf3, 0xf5, 0xfc, 0x03, 0x03, 0xfd, 0xf8, 0xf7, 0xf7, 0xf8, 0xfa, 0xfd, + 0x00, 0x07, 0x11, 0x15, 0x1e, 0x33, 0x40, 0x3c, 0x37, 0x33, 0x2b, 0x29, + 0x29, 0x22, 0x19, 0x09, 0xfc, 0xf5, 0xf7, 0xfd, 0xf9, 0xf0, 0xec, 0xe8, + 0xe6, 0xe6, 0xe2, 0xdd, 0xd9, 0xd8, 0xd6, 0xd6, 0xd9, 0xe1, 0xe7, 0xf2, + 0xf7, 0xfc, 0x05, 0x0c, 0x14, 0x24, 0x2b, 0x29, 0x29, 0x2b, 0x29, 0x24, + 0x20, 0x1c, 0x0e, 0xff, 0xf4, 0xf8, 0x01, 0x05, 0x02, 0x02, 0x04, 0x07, + 0x08, 0x09, 0x09, 0x07, 0x02, 0x01, 0x02, 0xff, 0xfd, 0xfb, 0xf9, 0xfa, + 0xfa, 0xfa, 0xfe, 0x03, 0x0d, 0x18, 0x1b, 0x15, 0x0c, 0x05, 0x01, 0xfe, + 0xf9, 0xeb, 0xdb, 0xd4, 0xda, 0xe5, 0xef, 0xf7, 0xfd, 0x00, 0xfd, 0xff, + 0x07, 0x09, 0x0f, 0x11, 0x0c, 0x0b, 0x0f, 0x0f, 0x0f, 0x11, 0x0e, 0x0a, + 0x0e, 0x13, 0x18, 0x1d, 0x29, 0x2c, 0x26, 0x18, 0x10, 0x0e, 0x08, 0x02, + 0xfe, 0xf0, 0xe5, 0xdf, 0xe0, 0xe7, 0xee, 0xed, 0xed, 0xf1, 0xf7, 0xfb, + 0xfe, 0x00, 0x01, 0xfd, 0xfc, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xfe, 0xfe, + 0x04, 0x08, 0x10, 0x1b, 0x25, 0x22, 0x1e, 0x1d, 0x1b, 0x17, 0x0b, 0x01, + 0xfd, 0xf7, 0xef, 0xeb, 0xf0, 0xf7, 0xfd, 0xff, 0x00, 0x03, 0x06, 0x08, + 0x0a, 0x08, 0x03, 0xfd, 0xfa, 0xfb, 0xf9, 0xf7, 0xfb, 0xf9, 0xf7, 0xf6, + 0xfc, 0x07, 0x13, 0x1f, 0x1c, 0x19, 0x21, 0x25, 0x21, 0x1b, 0x0e, 0x00, + 0x01, 0xfe, 0xf3, 0xf0, 0xf7, 0xfa, 0xfa, 0xf9, 0xfb, 0xf8, 0xf3, 0xed, + 0xe8, 0xe9, 0xe9, 0xec, 0xed, 0xef, 0xf2, 0xf5, 0xf4, 0xf2, 0xef, 0xf5, + 0x0a, 0x1e, 0x2c, 0x36, 0x39, 0x37, 0x3b, 0x3b, 0x36, 0x28, 0x18, 0x10, + 0x0f, 0x06, 0xfc, 0xfc, 0xfb, 0xef, 0xe7, 0xea, 0xee, 0xf3, 0xf5, 0xf6, + 0xf6, 0xef, 0xe9, 0xe3, 0xe6, 0xeb, 0xf4, 0xf4, 0xec, 0xf0, 0xf7, 0xfd, + 0x13, 0x20, 0x1b, 0x1b, 0x1e, 0x18, 0x15, 0x1c, 0x19, 0x04, 0xf2, 0xec, + 0xee, 0xed, 0xec, 0xf4, 0xfa, 0xff, 0x07, 0x0b, 0x0f, 0x11, 0x0e, 0x0f, + 0x18, 0x1b, 0x13, 0x10, 0x14, 0x13, 0x1a, 0x16, 0x07, 0x00, 0xfc, 0xfb, + 0x0a, 0x14, 0x14, 0x0f, 0x05, 0xfc, 0x01, 0x01, 0xf4, 0xe6, 0xe3, 0xe5, + 0xdf, 0xd9, 0xd6, 0xdd, 0xe3, 0xe9, 0xf4, 0xf9, 0xfe, 0x05, 0x05, 0x06, + 0x11, 0x14, 0x0f, 0x14, 0x15, 0x12, 0x12, 0x12, 0x11, 0x0c, 0x08, 0x13, + 0x23, 0x29, 0x2a, 0x2e, 0x2d, 0x2c, 0x27, 0x15, 0x00, 0xf7, 0xf2, 0xf3, + 0xef, 0xea, 0xe9, 0xe9, 0xea, 0xec, 0xf0, 0xf6, 0xf2, 0xf1, 0xf3, 0xf2, + 0xef, 0xf1, 0xf2, 0xee, 0xe7, 0xe6, 0xe8, 0xed, 0xf5, 0xfe, 0x0f, 0x1d, + 0x22, 0x20, 0x21, 0x22, 0x22, 0x24, 0x21, 0x1a, 0x17, 0x13, 0x0d, 0x0c, + 0x09, 0x07, 0x02, 0xfc, 0xfd, 0x02, 0x06, 0x0b, 0x05, 0xfc, 0xf8, 0xf8, + 0xf4, 0xf3, 0xf4, 0xf5, 0xf6, 0xf2, 0xef, 0xe9, 0xe5, 0xed, 0xf7, 0xfd, + 0xff, 0x0a, 0x17, 0x21, 0x26, 0x24, 0x1f, 0x21, 0x1a, 0x0a, 0x02, 0xff, + 0xff, 0x01, 0xfd, 0xf4, 0xf6, 0xfc, 0xfd, 0xfb, 0xf9, 0xfd, 0xfb, 0xf5, + 0xf4, 0xf3, 0xf8, 0xf9, 0xf6, 0xf5, 0xf3, 0xfa, 0x05, 0x15, 0x1f, 0x20, + 0x24, 0x30, 0x31, 0x28, 0x22, 0x15, 0x0d, 0x0b, 0xff, 0xef, 0xeb, 0xe7, + 0xe2, 0xe4, 0xed, 0xf3, 0xf7, 0xf6, 0xf4, 0xf7, 0x00, 0x07, 0x09, 0x03, + 0xff, 0x05, 0x0d, 0x0b, 0x09, 0x08, 0x0a, 0x13, 0x16, 0x13, 0x12, 0x10, + 0x15, 0x15, 0x0d, 0x04, 0xfb, 0xf4, 0xf5, 0xfa, 0xf8, 0xf2, 0xed, 0xe7, + 0xe2, 0xe3, 0xe9, 0xf3, 0xf7, 0xf9, 0xfb, 0x06, 0x11, 0x16, 0x1a, 0x1d, + 0x24, 0x29, 0x1e, 0x10, 0x0d, 0x10, 0x12, 0x13, 0x0f, 0x06, 0xfd, 0x02, + 0x09, 0x13, 0x18, 0x13, 0x05, 0xff, 0xfe, 0xfa, 0xf2, 0xeb, 0xe7, 0xe2, + 0xdf, 0xe7, 0xf6, 0xfc, 0xfe, 0xfe, 0x00, 0x02, 0xfc, 0xf6, 0xf1, 0xf6, + 0xf8, 0xf3, 0xf2, 0xf2, 0xf2, 0xf4, 0xfe, 0x16, 0x24, 0x22, 0x21, 0x21, + 0x28, 0x34, 0x35, 0x2c, 0x21, 0x1b, 0x19, 0x18, 0x13, 0x0c, 0x05, 0xfc, + 0xfd, 0xfd, 0xf5, 0xef, 0xed, 0xf0, 0xee, 0xeb, 0xf0, 0xef, 0xeb, 0xea, + 0xe8, 0xe6, 0xea, 0xed, 0xee, 0xee, 0xfc, 0x01, 0xff, 0xfd, 0xfc, 0xff, + 0x0b, 0x11, 0x10, 0x10, 0x1a, 0x2a, 0x30, 0x28, 0x19, 0x0e, 0x07, 0x0a, + 0x07, 0x04, 0x09, 0x08, 0x05, 0x05, 0x08, 0x0b, 0x0a, 0x07, 0x03, 0xfe, + 0xf8, 0xf6, 0xf7, 0xf2, 0xef, 0xf7, 0x01, 0xfe, 0xfe, 0x00, 0x03, 0x10, + 0x1c, 0x19, 0x10, 0x07, 0x04, 0x01, 0xf7, 0xf2, 0xee, 0xea, 0xe3, 0xe3, + 0xeb, 0xf9, 0x06, 0x08, 0xfe, 0xfc, 0x02, 0x06, 0x08, 0x06, 0x05, 0x05, + 0x07, 0x0b, 0x0e, 0x14, 0x1e, 0x29, 0x25, 0x20, 0x1f, 0x18, 0x14, 0x18, + 0x17, 0x0e, 0x0b, 0x07, 0x03, 0xff, 0xfd, 0xf4, 0xec, 0xe4, 0xda, 0xd6, + 0xd9, 0xde, 0xe0, 0xde, 0xe1, 0xef, 0xfc, 0xfd, 0x03, 0x10, 0x18, 0x1c, + 0x18, 0x17, 0x1c, 0x24, 0x25, 0x1e, 0x1a, 0x16, 0x14, 0x08, 0x03, 0x08, + 0x08, 0x01, 0xff, 0x00, 0xfe, 0xff, 0xff, 0xfb, 0xf3, 0xe9, 0xe6, 0xed, + 0xf7, 0xf8, 0xfb, 0x08, 0x13, 0x14, 0x0e, 0x0d, 0x0d, 0x07, 0xfa, 0xf2, + 0xf2, 0xf5, 0xfb, 0xfc, 0xf9, 0x00, 0x03, 0x04, 0x07, 0x09, 0x0e, 0x18, + 0x1d, 0x1c, 0x1c, 0x18, 0x14, 0x13, 0x10, 0x07, 0x01, 0x04, 0x05, 0x02, + 0x00, 0x00, 0xff, 0xfa, 0xf0, 0xeb, 0xee, 0xef, 0xec, 0xe6, 0xe5, 0xed, + 0xf3, 0xfa, 0xfd, 0x02, 0x03, 0x02, 0x01, 0x03, 0x06, 0x04, 0x09, 0x13, + 0x15, 0x14, 0x1c, 0x2b, 0x30, 0x29, 0x22, 0x1d, 0x12, 0x06, 0xfc, 0xf7, + 0xf9, 0xfb, 0xfb, 0xf9, 0xfc, 0x01, 0x00, 0xf8, 0xf4, 0xf1, 0xf0, 0xf2, + 0xf8, 0xfe, 0x04, 0x05, 0x07, 0x03, 0xff, 0xfc, 0xfd, 0x01, 0x09, 0x08, + 0x05, 0x09, 0x07, 0x02, 0xfc, 0xfa, 0xfc, 0xf6, 0xf1, 0xeb, 0xef, 0xf9, + 0x03, 0x08, 0x0e, 0x16, 0x1a, 0x1a, 0x16, 0x12, 0x10, 0x0d, 0x0f, 0x13, + 0x12, 0x0f, 0x12, 0x15, 0x12, 0x0a, 0x07, 0x09, 0x04, 0xfd, 0xff, 0x02, + 0x06, 0x05, 0xfd, 0xf7, 0xf5, 0xf9, 0xf6, 0xef, 0xe9, 0xe5, 0xe2, 0xe2, + 0xe1, 0xe2, 0xe7, 0xee, 0xf4, 0xf5, 0xf3, 0xfa, 0x03, 0x0f, 0x1b, 0x22, + 0x2c, 0x35, 0x31, 0x27, 0x21, 0x1e, 0x1f, 0x1c, 0x13, 0x0d, 0x0d, 0x13, + 0x11, 0x09, 0x06, 0x07, 0x05, 0xfd, 0xf4, 0xe8, 0xe0, 0xe1, 0xe3, 0xe5, + 0xe8, 0xf3, 0xfa, 0x03, 0x08, 0x02, 0xfd, 0xfd, 0xf9, 0xf6, 0xfd, 0x00, + 0x07, 0x09, 0x06, 0x05, 0x03, 0x04, 0x01, 0xfd, 0xff, 0x09, 0x13, 0x17, + 0x13, 0x0f, 0x12, 0x16, 0x16, 0x1a, 0x14, 0x07, 0xfe, 0x00, 0x05, 0x06, + 0x0c, 0x10, 0x09, 0x05, 0x03, 0xfb, 0xf8, 0xf7, 0xf5, 0xf7, 0xf8, 0xfa, + 0xfa, 0xf5, 0xf4, 0xf4, 0xf3, 0xf1, 0xee, 0xed, 0xf3, 0xfd, 0x0b, 0x10, + 0x12, 0x17, 0x19, 0x19, 0x20, 0x25, 0x24, 0x18, 0x09, 0x05, 0x04, 0xfd, + 0xff, 0x01, 0x01, 0xfa, 0xef, 0xec, 0xed, 0xef, 0xf3, 0xfd, 0x05, 0x05, + 0x05, 0x04, 0x07, 0x0c, 0x0b, 0x05, 0x06, 0x05, 0x02, 0x07, 0x12, 0x11, + 0x10, 0x0d, 0x09, 0x08, 0x04, 0xfa, 0xee, 0xe4, 0xe2, 0xe7, 0xed, 0xf7, + 0xff, 0x07, 0x0e, 0x0f, 0x0f, 0x0c, 0x07, 0x07, 0x10, 0x1c, 0x1d, 0x21, + 0x24, 0x19, 0x0f, 0x09, 0x02, 0xfb, 0xfb, 0xf9, 0xf4, 0xfc, 0x04, 0x00, + 0xf7, 0xf7, 0xf8, 0xf8, 0xf4, 0xf6, 0xef, 0xe8, 0xe9, 0xed, 0xf4, 0xf8, + 0xfa, 0xfb, 0xfb, 0xfd, 0x01, 0x0b, 0x14, 0x19, 0x1b, 0x1b, 0x20, 0x24, + 0x22, 0x1d, 0x1b, 0x19, 0x12, 0x0b, 0x0a, 0x08, 0x08, 0x0a, 0x05, 0xfd, + 0xfe, 0x04, 0x04, 0x01, 0x00, 0xfe, 0xf1, 0xe7, 0xe8, 0xe6, 0xe7, 0xf2, + 0xf6, 0xf3, 0xee, 0xee, 0xf2, 0xf6, 0xf8, 0xfc, 0xff, 0x07, 0x13, 0x0f, + 0x08, 0x0b, 0x12, 0x0c, 0x03, 0x06, 0x0a, 0x0c, 0x12, 0x1c, 0x1f, 0x1e, + 0x20, 0x1f, 0x1a, 0x17, 0x17, 0x10, 0xff, 0xf2, 0xf1, 0xf3, 0xfb, 0x01, + 0x00, 0xfd, 0xff, 0xfd, 0xfd, 0xfc, 0xfa, 0xfb, 0xfe, 0x01, 0xff, 0xfc, + 0xfa, 0xfb, 0xf2, 0xe6, 0xe1, 0xe8, 0xe9, 0xee, 0xf8, 0x00, 0x0c, 0x15, + 0x16, 0x12, 0x15, 0x1a, 0x1b, 0x19, 0x10, 0x10, 0x17, 0x1a, 0x1b, 0x16, + 0x0c, 0x05, 0x00, 0xfc, 0xff, 0x02, 0x02, 0x01, 0x05, 0x06, 0x02, 0xfc, + 0xf8, 0xf9, 0xf8, 0xf5, 0xff, 0x02, 0xfe, 0x00, 0xff, 0xfd, 0xff, 0x04, + 0x05, 0x09, 0x0b, 0x0a, 0x08, 0xfd, 0xee, 0xea, 0xee, 0xed, 0xee, 0xf6, + 0xfb, 0xfd, 0xff, 0x04, 0x0d, 0x0e, 0x0a, 0x13, 0x1f, 0x28, 0x29, 0x23, + 0x1e, 0x14, 0x08, 0xff, 0x00, 0xfe, 0xff, 0x05, 0x08, 0x0e, 0x0f, 0x0d, + 0x05, 0xfe, 0xfa, 0xf2, 0xe9, 0xdd, 0xd6, 0xe1, 0xec, 0xee, 0xf1, 0xf6, + 0xf5, 0xf5, 0xfb, 0x09, 0x15, 0x15, 0x17, 0x20, 0x25, 0x20, 0x18, 0x14, + 0x17, 0x13, 0x0b, 0x09, 0x0a, 0x09, 0x01, 0xfc, 0xfd, 0xfe, 0xfb, 0xf9, + 0xfa, 0xff, 0x01, 0x03, 0x01, 0xf6, 0xef, 0xf6, 0xfb, 0x00, 0x01, 0xfd, + 0xfa, 0xfb, 0xfe, 0xfc, 0xf9, 0xfa, 0x08, 0x12, 0x13, 0x0d, 0x06, 0x04, + 0xff, 0xfb, 0xff, 0x03, 0x04, 0x06, 0x07, 0x07, 0x0e, 0x18, 0x1d, 0x1e, + 0x1d, 0x1e, 0x20, 0x1c, 0x0d, 0xfe, 0xf9, 0xf6, 0xed, 0xe6, 0xe4, 0xec, + 0xf9, 0xff, 0xfe, 0xfd, 0xfa, 0xfa, 0xfe, 0x00, 0x05, 0x03, 0xff, 0xfa, + 0xf2, 0xf1, 0xf6, 0xf6, 0xf4, 0xf7, 0x00, 0x04, 0x13, 0x1e, 0x1d, 0x1f, + 0x1f, 0x1d, 0x14, 0x06, 0xf5, 0xf6, 0x0b, 0x15, 0x17, 0x17, 0x17, 0x11, + 0x05, 0xfd, 0x01, 0x03, 0x00, 0x01, 0x04, 0x07, 0x09, 0x07, 0xfe, 0xef, + 0xea, 0xed, 0xf6, 0xf3, 0xf2, 0xf7, 0xf7, 0xf7, 0xf7, 0xf3, 0xee, 0xf7, + 0x07, 0x0f, 0x12, 0x10, 0x05, 0x01, 0xfe, 0xf9, 0xf9, 0xff, 0x04, 0x05, + 0x05, 0x09, 0x0f, 0x14, 0x19, 0x1f, 0x27, 0x2a, 0x23, 0x16, 0x09, 0x07, + 0x0c, 0x0b, 0x00, 0xf2, 0xec, 0xf7, 0x02, 0x09, 0x0e, 0x10, 0x0b, 0x07, + 0x02, 0xfb, 0xf5, 0xeb, 0xdf, 0xda, 0xd5, 0xd7, 0xe1, 0xed, 0xf0, 0xf3, + 0xfe, 0x03, 0x04, 0x07, 0x11, 0x1e, 0x28, 0x28, 0x20, 0x0d, 0x00, 0x09, + 0x19, 0x1d, 0x17, 0x13, 0x13, 0x13, 0x0b, 0x09, 0x0e, 0x0e, 0x06, 0x00, + 0xfc, 0xfa, 0xf9, 0xf4, 0xed, 0xef, 0xf6, 0xff, 0x04, 0xff, 0xfa, 0xfc, + 0xfd, 0xfa, 0xf5, 0xf3, 0xf8, 0x06, 0x13, 0x18, 0x10, 0x02, 0xfc, 0xfa, + 0xf9, 0xf8, 0xf6, 0xf7, 0xfc, 0xfc, 0xf9, 0x00, 0x0e, 0x13, 0x13, 0x1b, + 0x27, 0x2a, 0x1f, 0x10, 0x05, 0x02, 0x01, 0xfc, 0xf3, 0xee, 0xf5, 0xff, + 0x06, 0x07, 0x09, 0x0c, 0x0e, 0x0d, 0x08, 0xfb, 0xf0, 0xea, 0xec, 0xf1, + 0xf3, 0xf3, 0xef, 0xf4, 0xfa, 0x00, 0x10, 0x1a, 0x19, 0x17, 0x18, 0x1d, + 0x1c, 0x12, 0x01, 0xf2, 0xea, 0xf1, 0x02, 0x0f, 0x10, 0x11, 0x0e, 0x06, + 0xfb, 0xf8, 0xfd, 0x06, 0x09, 0x06, 0x06, 0x05, 0x01, 0xfd, 0xf9, 0xfd, + 0x02, 0xf9, 0xf5, 0xff, 0x00, 0xff, 0x04, 0x05, 0xfd, 0xf8, 0xfb, 0x00, + 0x0b, 0x0d, 0x07, 0xfd, 0xff, 0x04, 0x07, 0x05, 0x05, 0x06, 0x02, 0xff, + 0x00, 0x06, 0x11, 0x1d, 0x20, 0x28, 0x28, 0x19, 0x0a, 0x03, 0x02, 0x01, + 0xf9, 0xed, 0xe7, 0xeb, 0xef, 0xf5, 0x03, 0x0a, 0x05, 0x01, 0x03, 0x06, + 0x06, 0xfe, 0xf0, 0xe6, 0xe1, 0xe2, 0xe5, 0xee, 0xf9, 0x01, 0x04, 0x09, + 0x0f, 0x13, 0x1f, 0x26, 0x25, 0x22, 0x18, 0x06, 0x00, 0x05, 0x07, 0x09, + 0x13, 0x14, 0x13, 0x13, 0x15, 0x12, 0x12, 0x0e, 0x03, 0xff, 0xfe, 0xfe, + 0xf9, 0xee, 0xea, 0xe8, 0xea, 0xf4, 0xf6, 0xf8, 0xfb, 0xf8, 0xf2, 0xf0, + 0xf1, 0xf4, 0xfa, 0x00, 0x03, 0x07, 0x0f, 0x10, 0x0b, 0x06, 0x03, 0x03, + 0x03, 0x02, 0x02, 0x05, 0x06, 0x08, 0x0d, 0x11, 0x0f, 0x16, 0x23, 0x27, + 0x1b, 0x13, 0x0e, 0x09, 0x06, 0x05, 0x02, 0xfd, 0xf8, 0xf7, 0xf3, 0xf8, + 0x06, 0x0d, 0x09, 0x09, 0x08, 0xff, 0xf8, 0xf4, 0xe8, 0xe1, 0xe0, 0xdf, + 0xde, 0xe5, 0xf0, 0xfb, 0x05, 0x0c, 0x0e, 0x12, 0x17, 0x1e, 0x1d, 0x19, + 0x0d, 0x01, 0xfb, 0xfa, 0xfa, 0x02, 0x15, 0x1d, 0x18, 0x12, 0x0f, 0x0f, + 0x14, 0x15, 0x0e, 0x08, 0x04, 0xff, 0xfd, 0xfc, 0xfc, 0xfe, 0x02, 0xfd, + 0xf6, 0xfa, 0x03, 0x02, 0xff, 0xfd, 0xf6, 0xf1, 0xf6, 0xfa, 0xfa, 0xfd, + 0x01, 0xfe, 0xfa, 0xfc, 0xfe, 0x06, 0x0c, 0x06, 0xf8, 0xf5, 0xf9, 0x00, + 0x06, 0x0f, 0x13, 0x1d, 0x27, 0x25, 0x1b, 0x13, 0x0e, 0x07, 0x00, 0xf9, + 0xf7, 0xfa, 0xff, 0xff, 0xfd, 0x02, 0x0a, 0x0a, 0x07, 0x06, 0x05, 0x01, + 0xfd, 0xf9, 0xec, 0xe6, 0xee, 0xf6, 0xf5, 0xf4, 0xf7, 0x01, 0x0a, 0x0d, + 0x13, 0x1a, 0x1e, 0x1b, 0x14, 0x0e, 0x02, 0xfb, 0xfc, 0xf9, 0xf6, 0xf7, + 0x05, 0x0f, 0x13, 0x10, 0x0e, 0x0e, 0x10, 0x0a, 0x00, 0x00, 0x01, 0xfb, + 0xf6, 0xf3, 0xef, 0xf8, 0x05, 0x05, 0xff, 0xfb, 0xfc, 0xfd, 0xff, 0x02, + 0x00, 0x00, 0x04, 0x04, 0x05, 0x05, 0x07, 0x0b, 0x0b, 0x09, 0x07, 0x07, + 0x0d, 0x0e, 0x05, 0xff, 0x02, 0x03, 0x04, 0x05, 0x0d, 0x1b, 0x1b, 0x14, + 0x0f, 0x08, 0x03, 0x04, 0x05, 0xfd, 0xf2, 0xf0, 0xf2, 0xf4, 0xfb, 0xfe, + 0x03, 0x09, 0x06, 0x02, 0x00, 0xff, 0xfb, 0xf4, 0xe9, 0xe2, 0xe6, 0xee, + 0xf6, 0xfa, 0x02, 0x0c, 0x12, 0x17, 0x1a, 0x1d, 0x1f, 0x1e, 0x17, 0x10, + 0x09, 0x01, 0x03, 0x09, 0x0c, 0x09, 0x0a, 0x0e, 0x0f, 0x0f, 0x12, 0x10, + 0x12, 0x0e, 0xff, 0xfb, 0xfe, 0xf7, 0xf2, 0xed, 0xef, 0xf1, 0xf2, 0xf5, + 0xf9, 0xf9, 0xfb, 0xfc, 0xf8, 0xf7, 0xf4, 0xf7, 0xfd, 0xfd, 0xfd, 0xfd, + 0xff, 0x02, 0x0c, 0x15, 0x12, 0x0c, 0x0a, 0x07, 0x04, 0x07, 0x0d, 0x10, + 0x12, 0x13, 0x1d, 0x25, 0x21, 0x1c, 0x16, 0x11, 0x09, 0x06, 0x03, 0xfe, + 0xf9, 0xfa, 0xf9, 0xf5, 0xf7, 0xf8, 0xf8, 0xff, 0x01, 0xfd, 0xfa, 0xf8, + 0xf5, 0xf3, 0xec, 0xea, 0xea, 0xeb, 0xed, 0xf2, 0xfe, 0x0a, 0x12, 0x18, + 0x1a, 0x17, 0x18, 0x15, 0x0d, 0x07, 0x02, 0xfe, 0xfc, 0xfe, 0x02, 0x06, + 0x0c, 0x14, 0x16, 0x17, 0x17, 0x15, 0x15, 0x15, 0x0b, 0x03, 0x02, 0xff, + 0xfa, 0xfd, 0x03, 0x00, 0xfa, 0xf6, 0xf5, 0xf4, 0xfb, 0xff, 0xfa, 0xf7, + 0xf7, 0xfb, 0xff, 0xfc, 0xfa, 0xfa, 0xfa, 0xfd, 0x00, 0x02, 0x06, 0x08, + 0x0a, 0x08, 0x03, 0x03, 0x03, 0x02, 0x07, 0x0d, 0x11, 0x13, 0x14, 0x16, + 0x16, 0x15, 0x14, 0x0b, 0xff, 0xf8, 0xf5, 0xf9, 0x03, 0x04, 0x01, 0x03, + 0x05, 0x0b, 0x0b, 0x05, 0x00, 0xfe, 0xfb, 0xf4, 0xea, 0xeb, 0xf2, 0xf4, + 0xf6, 0xfa, 0x00, 0x04, 0x07, 0x11, 0x17, 0x15, 0x12, 0x0e, 0x06, 0x07, + 0x05, 0x00, 0xfe, 0xfb, 0xfd, 0xff, 0x00, 0x0d, 0x17, 0x18, 0x12, 0x0d, + 0x0b, 0x08, 0x00, 0xfb, 0xfd, 0xfa, 0xf5, 0xf2, 0xf5, 0xfb, 0xf9, 0xfa, + 0xff, 0x03, 0x05, 0x01, 0xff, 0x03, 0x07, 0x06, 0x04, 0x01, 0x05, 0x09, + 0x08, 0x0d, 0x0f, 0x0a, 0x02, 0x00, 0x07, 0x09, 0x05, 0x03, 0x03, 0x04, + 0x0e, 0x10, 0x0f, 0x0d, 0x0e, 0x0e, 0x07, 0x02, 0x03, 0x00, 0xf9, 0xfa, + 0xf8, 0xf9, 0xf9, 0xf7, 0xf9, 0xfa, 0xf7, 0xf8, 0xfb, 0x00, 0x06, 0x06, + 0x01, 0xfc, 0xf3, 0xed, 0xed, 0xf4, 0x00, 0x0a, 0x13, 0x17, 0x19, 0x1e, + 0x24, 0x20, 0x1a, 0x12, 0x0c, 0x05, 0xfd, 0xfd, 0xfe, 0xfd, 0x01, 0x04, + 0x00, 0x04, 0x0d, 0x10, 0x12, 0x13, 0x11, 0x07, 0xfd, 0xff, 0x03, 0xfd, + 0xf6, 0xf5, 0xf2, 0xef, 0xed, 0xf2, 0xfe, 0x07, 0x03, 0xf7, 0xf1, 0xf5, + 0xf7, 0xfa, 0xfe, 0x01, 0x03, 0x00, 0xfe, 0x05, 0x09, 0x0a, 0x0b, 0x0d, + 0x0f, 0x0e, 0x0f, 0x0f, 0x11, 0x17, 0x17, 0x13, 0x17, 0x1c, 0x1e, 0x18, + 0x13, 0x0d, 0x02, 0xf9, 0xf4, 0xf7, 0xfb, 0xfe, 0xf8, 0xf5, 0xf9, 0xfe, + 0xfa, 0xfa, 0xfd, 0xfe, 0xf8, 0xf3, 0xf1, 0xf1, 0xf0, 0xec, 0xf0, 0xf9, + 0xfc, 0x02, 0x09, 0x0c, 0x0a, 0x0a, 0x10, 0x15, 0x18, 0x1a, 0x15, 0x0a, + 0x02, 0xff, 0xfb, 0xfc, 0x02, 0x0b, 0x14, 0x1a, 0x1c, 0x1a, 0x1a, 0x1b, + 0x17, 0x10, 0x08, 0xfe, 0xf7, 0xf2, 0xf0, 0xf3, 0xf1, 0xef, 0xef, 0xf0, + 0xf4, 0xfd, 0xfe, 0xfc, 0xfe, 0xfc, 0xf9, 0xfd, 0x05, 0x09, 0x06, 0xfe, + 0xfd, 0xff, 0x00, 0x01, 0x08, 0x12, 0x16, 0x0d, 0x01, 0xf9, 0xfe, 0x09, + 0x0d, 0x11, 0x14, 0x0f, 0x0a, 0x0b, 0x0f, 0x09, 0xff, 0x00, 0x02, 0xff, + 0x00, 0x06, 0x06, 0x07, 0x04, 0xfe, 0xff, 0x09, 0x10, 0x09, 0xfc, 0xf7, + 0xf7, 0xf1, 0xe9, 0xe8, 0xf6, 0xff, 0xff, 0x02, 0x08, 0x0c, 0x12, 0x15, + 0x14, 0x12, 0x0a, 0x01, 0xfe, 0xfe, 0xfb, 0xf9, 0xfa, 0x00, 0x00, 0xfe, + 0x06, 0x0f, 0x0f, 0x09, 0x07, 0x0c, 0x14, 0x18, 0x13, 0x03, 0xfc, 0xf9, + 0xf4, 0xee, 0xef, 0xf8, 0x04, 0x09, 0x08, 0x04, 0x02, 0x04, 0x07, 0x08, + 0x06, 0x04, 0xfe, 0xf9, 0xf9, 0xfa, 0xfd, 0x01, 0x03, 0x00, 0xff, 0x07, + 0x11, 0x13, 0x0b, 0x04, 0x09, 0x0f, 0x13, 0x17, 0x14, 0x10, 0x0a, 0x09, + 0x04, 0xfe, 0xfc, 0x02, 0x08, 0x00, 0xf2, 0xf0, 0xef, 0xf0, 0xf7, 0xfc, + 0x00, 0x02, 0xff, 0xf9, 0xf9, 0xfb, 0xf7, 0xf5, 0xf5, 0xf6, 0xfe, 0x06, + 0x11, 0x16, 0x16, 0x15, 0x1a, 0x20, 0x23, 0x1d, 0x12, 0x05, 0xfe, 0xfb, + 0xf6, 0xf6, 0xfb, 0x03, 0x04, 0x02, 0x06, 0x10, 0x12, 0x12, 0x16, 0x13, + 0x0b, 0x05, 0xfb, 0xf3, 0xf6, 0xf1, 0xee, 0xee, 0xef, 0xf2, 0xf8, 0xfc, + 0xff, 0xf6, 0xee, 0xf5, 0x04, 0x0a, 0x0b, 0x0e, 0x06, 0xfe, 0xfc, 0x00, + 0x00, 0x06, 0x0e, 0x14, 0x19, 0x17, 0x13, 0x12, 0x0e, 0x13, 0x19, 0x14, + 0x0d, 0x0b, 0x03, 0x06, 0x0a, 0x06, 0x02, 0xfc, 0xf6, 0xfa, 0xfe, 0x02, + 0xff, 0xfd, 0xfb, 0xfd, 0xfe, 0x00, 0x02, 0x04, 0xfb, 0xf4, 0xf6, 0xf5, + 0xf2, 0xf6, 0xfb, 0xff, 0xfd, 0xf7, 0xf6, 0xfe, 0x07, 0x14, 0x17, 0x16, + 0x15, 0x0c, 0x04, 0x06, 0x03, 0xfc, 0xfc, 0x01, 0x03, 0x07, 0x0e, 0x16, + 0x19, 0x1a, 0x19, 0x1c, 0x22, 0x1f, 0x16, 0x06, 0xf7, 0xf2, 0xf4, 0xee, + 0xea, 0xee, 0xf7, 0xfc, 0xfa, 0xfb, 0xfd, 0xfa, 0xff, 0x03, 0x02, 0xfb, + 0xf9, 0xf9, 0xfa, 0xf9, 0xf7, 0xfa, 0x00, 0x02, 0x02, 0x05, 0x0a, 0x0a, + 0x08, 0x02, 0x09, 0x15, 0x1d, 0x1b, 0x15, 0x0d, 0x09, 0x0d, 0x0c, 0x08, + 0x05, 0x07, 0x0b, 0x0a, 0x05, 0x00, 0x01, 0x05, 0x06, 0x04, 0xff, 0xf8, + 0xf6, 0xf6, 0xf3, 0xf2, 0xf3, 0xf0, 0xee, 0xf1, 0xf8, 0xfd, 0x02, 0x07, + 0x06, 0x0b, 0x17, 0x1e, 0x19, 0x15, 0x0f, 0x06, 0x01, 0x02, 0xfe, 0xfa, + 0xff, 0x04, 0x02, 0xfc, 0xf9, 0xff, 0x07, 0x10, 0x16, 0x16, 0x15, 0x0e, + 0x07, 0x03, 0xfe, 0xf9, 0xf5, 0xf1, 0xf1, 0xf8, 0xfd, 0x04, 0x09, 0x09, + 0x00, 0x04, 0x0c, 0x10, 0x0b, 0x04, 0xfb, 0xf4, 0xf5, 0xf8, 0xf6, 0xfb, + 0x04, 0x0a, 0x08, 0x08, 0x0d, 0x0c, 0x0d, 0x12, 0x11, 0x09, 0x05, 0x03, + 0x08, 0x0b, 0x09, 0x07, 0x04, 0x03, 0x00, 0xfc, 0xf9, 0xfe, 0x00, 0xf8, + 0xf5, 0x00, 0x07, 0x05, 0x04, 0x01, 0xfe, 0xff, 0xfe, 0xfa, 0xf6, 0xf8, + 0x01, 0x05, 0x03, 0x00, 0x04, 0x07, 0x11, 0x18, 0x17, 0x12, 0x0c, 0x05, + 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xfa, 0xfe, 0x04, 0x0a, 0x0d, 0x0e, + 0x16, 0x1d, 0x1a, 0x15, 0x11, 0x0a, 0x04, 0x00, 0xfa, 0xf2, 0xf1, 0xf2, + 0xf6, 0xf2, 0xee, 0xf2, 0xf6, 0xfb, 0xfa, 0xfc, 0x02, 0x04, 0x04, 0x02, + 0xff, 0xff, 0xfe, 0xf9, 0xfd, 0x02, 0x08, 0x0f, 0x11, 0x17, 0x16, 0x16, + 0x1a, 0x20, 0x1b, 0x13, 0x0a, 0x03, 0x00, 0x02, 0x03, 0x02, 0x04, 0x07, + 0x02, 0xff, 0xfe, 0x04, 0x07, 0x01, 0xfa, 0xfb, 0xf7, 0xf3, 0xf5, 0xfa, + 0xfd, 0xfa, 0xf6, 0xf2, 0xf0, 0xef, 0xf5, 0xf7, 0xfb, 0xff, 0xff, 0x04, + 0x10, 0x19, 0x1c, 0x1d, 0x17, 0x0c, 0x03, 0x04, 0x02, 0x01, 0x07, 0x08, + 0x06, 0x06, 0x0a, 0x0f, 0x12, 0x13, 0x17, 0x18, 0x11, 0x08, 0x03, 0xff, + 0xfe, 0xfa, 0xf2, 0xed, 0xed, 0xf1, 0xf5, 0xfa, 0x04, 0x06, 0x03, 0x02, + 0x01, 0x01, 0x03, 0x08, 0x04, 0xfa, 0xfa, 0xfa, 0xf8, 0xf9, 0x00, 0x00, + 0x00, 0x03, 0x06, 0x07, 0x06, 0x08, 0x0f, 0x13, 0x11, 0x0d, 0x0c, 0x0e, + 0x0e, 0x0a, 0x07, 0x06, 0x08, 0x04, 0x01, 0x09, 0x10, 0x0e, 0x0a, 0x08, + 0x08, 0x04, 0x00, 0xfa, 0xf2, 0xf0, 0xf4, 0xf6, 0xf1, 0xf4, 0xf9, 0xf7, + 0xfb, 0x04, 0x05, 0x02, 0x02, 0x03, 0x06, 0x0b, 0x0c, 0x0f, 0x11, 0x06, + 0xff, 0x00, 0xfc, 0xfc, 0xfb, 0xf8, 0xfd, 0x06, 0x08, 0x07, 0x0d, 0x16, + 0x1e, 0x21, 0x1c, 0x15, 0x08, 0x03, 0x04, 0xfe, 0xf8, 0xfa, 0xfa, 0xf7, + 0xfb, 0x02, 0x06, 0x06, 0x03, 0xfc, 0xf9, 0xfa, 0xfa, 0xfc, 0xfc, 0xf6, + 0xf6, 0xf7, 0xf5, 0xf7, 0xfd, 0x06, 0x11, 0x16, 0x11, 0x0e, 0x0f, 0x13, + 0x16, 0x18, 0x13, 0x0a, 0x05, 0x03, 0x04, 0x05, 0x07, 0x0a, 0x03, 0xf8, + 0xf8, 0xfe, 0x02, 0x01, 0xfc, 0xfb, 0x00, 0x00, 0xff, 0x01, 0xff, 0xfc, + 0xfd, 0xfb, 0xf4, 0xf2, 0xf5, 0xff, 0x08, 0x0e, 0x0c, 0x0a, 0x10, 0x12, + 0x15, 0x13, 0x0f, 0x07, 0xff, 0xf8, 0xf8, 0xfd, 0x04, 0x09, 0x04, 0x01, + 0x09, 0x0a, 0x08, 0x06, 0x05, 0x09, 0x11, 0x12, 0x0f, 0x0a, 0x03, 0x01, + 0xff, 0xf6, 0xee, 0xec, 0xed, 0xf0, 0xf9, 0x00, 0x01, 0x03, 0x05, 0x05, + 0x07, 0x0b, 0x07, 0x00, 0xfe, 0xfd, 0xfd, 0xfc, 0x00, 0x01, 0x01, 0x0a, + 0x15, 0x14, 0x0b, 0x06, 0x07, 0x0c, 0x0c, 0x0a, 0x07, 0x04, 0x02, 0x01, + 0x01, 0x01, 0x06, 0x0a, 0x07, 0x06, 0x06, 0x07, 0x08, 0x09, 0x07, 0x04, + 0x05, 0x02, 0xf8, 0xf2, 0xf3, 0xf5, 0xf8, 0xfc, 0xf6, 0xec, 0xee, 0xfa, + 0xff, 0x00, 0xfd, 0xfe, 0x02, 0x09, 0x14, 0x18, 0x19, 0x13, 0x08, 0xfe, + 0xfb, 0xfe, 0x05, 0x09, 0x0a, 0x0e, 0x0f, 0x0f, 0x11, 0x13, 0x17, 0x18, + 0x18, 0x0e, 0xfd, 0xf7, 0xf9, 0xfd, 0x00, 0x01, 0xfb, 0xf4, 0xf8, 0xfd, + 0xfe, 0xfc, 0xfa, 0xfa, 0xfa, 0xfa, 0xfc, 0x01, 0x05, 0x01, 0xfb, 0xf8, + 0xf4, 0xf1, 0xf4, 0xfa, 0x02, 0x0a, 0x11, 0x12, 0x0c, 0x10, 0x19, 0x21, + 0x1d, 0x14, 0x0a, 0x07, 0x06, 0x08, 0x0a, 0x0d, 0x0a, 0x0b, 0x09, 0x05, + 0x00, 0x01, 0x02, 0x02, 0x02, 0xfd, 0xf8, 0xfa, 0xf8, 0xf3, 0xf0, 0xf3, + 0xf8, 0xfb, 0xf9, 0xf8, 0x00, 0x06, 0x0a, 0x08, 0x07, 0x0a, 0x0d, 0x12, + 0x10, 0x09, 0x04, 0x04, 0x02, 0xfb, 0xf9, 0xfd, 0x01, 0x01, 0x05, 0x05, + 0x04, 0x02, 0x02, 0x08, 0x12, 0x1c, 0x21, 0x19, 0x0a, 0x00, 0x01, 0xfe, + 0xfb, 0xfa, 0xf6, 0xf7, 0xfc, 0x05, 0x08, 0x07, 0x09, 0x0a, 0x03, 0xfa, + 0xf5, 0xf3, 0xf6, 0xfc, 0x00, 0xff, 0xfe, 0x00, 0x00, 0x02, 0x05, 0x09, + 0x0b, 0x06, 0xff, 0x01, 0x0f, 0x17, 0x12, 0x0b, 0x06, 0x04, 0xfe, 0xfc, + 0x01, 0x07, 0x07, 0x07, 0x05, 0x03, 0x03, 0x08, 0x10, 0x14, 0x13, 0x07, + 0xfc, 0xf7, 0xf7, 0xf8, 0xf8, 0xfb, 0xfd, 0xf8, 0xf2, 0xf6, 0x00, 0x01, + 0x01, 0x01, 0xfe, 0xfe, 0x03, 0x0b, 0x0d, 0x0e, 0x0b, 0x08, 0xfb, 0xfa, + 0x01, 0x06, 0x08, 0x0b, 0x11, 0x0f, 0x0b, 0x0b, 0x10, 0x14, 0x16, 0x12, + 0x0b, 0x03, 0xfa, 0xf9, 0xfd, 0xff, 0xfe, 0xf7, 0xf1, 0xf0, 0xf2, 0xf6, + 0xfb, 0xfd, 0x02, 0x09, 0x07, 0x00, 0x02, 0x01, 0x02, 0xff, 0xfd, 0xf5, + 0xf5, 0xf9, 0x01, 0x0a, 0x13, 0x17, 0x18, 0x13, 0x0e, 0x0e, 0x0f, 0x0b, + 0x08, 0x04, 0x03, 0x04, 0x06, 0x0d, 0x0f, 0x0c, 0x0c, 0x09, 0x00, 0xf7, + 0xf7, 0xfd, 0x07, 0x0d, 0x08, 0xfe, 0xf7, 0xf5, 0xf2, 0xee, 0xed, 0xf4, + 0xf8, 0xf3, 0xf2, 0xfd, 0x07, 0x09, 0x0d, 0x11, 0x0e, 0x0c, 0x0a, 0x0d, + 0x0f, 0x0e, 0x0d, 0x09, 0x01, 0xfa, 0xfb, 0x01, 0x09, 0x0c, 0x0a, 0x06, + 0x03, 0x05, 0x07, 0x0d, 0x11, 0x14, 0x12, 0x06, 0xfb, 0xfb, 0x02, 0x03, + 0x02, 0xfa, 0xf9, 0xff, 0xff, 0x01, 0x05, 0x09, 0x08, 0x05, 0xfa, 0xef, + 0xee, 0xf5, 0xfe, 0xff, 0xff, 0xf9, 0xf4, 0xf6, 0xfd, 0x00, 0x03, 0x0a, + 0x0e, 0x0e, 0x0f, 0x16, 0x18, 0x14, 0x14, 0x0e, 0x02, 0xfd, 0xfd, 0x02, + 0x07, 0x0f, 0x1a, 0x1a, 0x0a, 0x02, 0x04, 0x08, 0x0c, 0x09, 0xff, 0xf7, + 0xf2, 0xf5, 0xf8, 0xfa, 0xfd, 0xff, 0xfa, 0xf4, 0xf1, 0xf5, 0xf9, 0xfe, + 0x06, 0x04, 0x03, 0x03, 0x00, 0x05, 0x0c, 0x09, 0x03, 0x00, 0xfb, 0xf7, + 0xfa, 0x07, 0x13, 0x15, 0x12, 0x11, 0x10, 0x13, 0x15, 0x12, 0x11, 0x11, + 0x0c, 0x02, 0xfd, 0x00, 0xfe, 0xfd, 0xfe, 0xf8, 0xf3, 0xf5, 0xf7, 0xfb, + 0x00, 0x04, 0x05, 0x00, 0xf6, 0xf8, 0xfc, 0xff, 0x04, 0x03, 0xfd, 0xf8, + 0xf9, 0x02, 0x0b, 0x0d, 0x0f, 0x10, 0x13, 0x11, 0x0c, 0x0b, 0x04, 0x03, + 0x05, 0x01, 0xfe, 0x02, 0x02, 0x03, 0x08, 0x08, 0x08, 0x05, 0xfe, 0x00, + 0x08, 0x11, 0x14, 0x0c, 0x05, 0x01, 0xf9, 0xf2, 0xf0, 0xee, 0xef, 0xf6, + 0xff, 0x04, 0x06, 0x05, 0x03, 0x08, 0x0d, 0x04, 0xff, 0xfc, 0xfd, 0x08, + 0x0f, 0x10, 0x0f, 0x08, 0xfe, 0xfa, 0xff, 0x03, 0x07, 0x05, 0x08, 0x0a, + 0x08, 0x0b, 0x0d, 0x09, 0x0a, 0x0b, 0x02, 0xfa, 0xfb, 0xfd, 0xfa, 0x02, + 0x08, 0x02, 0xfd, 0xfc, 0x00, 0x0a, 0x0f, 0x0e, 0x0b, 0x01, 0xf4, 0xf3, + 0xf7, 0xfc, 0x01, 0xfd, 0xf7, 0xf8, 0xf8, 0xfb, 0xff, 0x04, 0x0c, 0x0d, + 0x0c, 0x0e, 0x0e, 0x0d, 0x0f, 0x13, 0x0d, 0x05, 0x02, 0xfd, 0xff, 0x0e, + 0x1a, 0x17, 0x12, 0x0b, 0x02, 0x02, 0x09, 0x0e, 0x07, 0xfa, 0xf5, 0xf3, + 0xef, 0xf1, 0xf8, 0xf5, 0xf3, 0xf4, 0xf2, 0xf0, 0xf9, 0x03, 0x09, 0x0e, + 0x0e, 0x08, 0x03, 0x03, 0x07, 0x0b, 0x09, 0x04, 0x02, 0xfc, 0xfb, 0x07, + 0x12, 0x13, 0x12, 0x12, 0x11, 0x10, 0x0e, 0x0b, 0x08, 0x07, 0x09, 0x09, + 0x07, 0x05, 0x04, 0xff, 0xfd, 0xfe, 0xf6, 0xf0, 0xf3, 0xf7, 0xfc, 0x02, + 0x07, 0x04, 0x00, 0xf8, 0xef, 0xf0, 0xf6, 0xfd, 0xfe, 0xfa, 0x01, 0x08, + 0x03, 0x03, 0x0a, 0x10, 0x16, 0x18, 0x16, 0x10, 0x0b, 0x07, 0x06, 0x09, + 0x06, 0x00, 0xfb, 0xfc, 0x01, 0x08, 0x0c, 0x0e, 0x0f, 0x07, 0xff, 0x05, + 0x0b, 0x0a, 0x09, 0x07, 0x04, 0xfd, 0xf5, 0xef, 0xf0, 0xf5, 0xfe, 0x02, + 0xff, 0xfc, 0xfe, 0x05, 0x0c, 0x0e, 0x05, 0xf8, 0xef, 0xf1, 0xf7, 0x04, + 0x0d, 0x0e, 0x08, 0xff, 0xf8, 0xfd, 0x03, 0x0b, 0x12, 0x14, 0x14, 0x14, + 0x0f, 0x0d, 0x0d, 0x09, 0x06, 0x01, 0xfd, 0xfa, 0xfb, 0x04, 0x0f, 0x0f, + 0x04, 0xfa, 0xf9, 0xfc, 0x03, 0x0b, 0x0a, 0x03, 0xfc, 0xf6, 0xf3, 0xf9, + 0x00, 0x01, 0xff, 0xfc, 0xfc, 0xf6, 0xf4, 0xfc, 0x06, 0x08, 0x0c, 0x0d, + 0x0a, 0x06, 0x06, 0x05, 0x07, 0x07, 0x01, 0xfb, 0xfc, 0x07, 0x10, 0x15, + 0x17, 0x17, 0x16, 0x11, 0x0c, 0x0e, 0x09, 0x02, 0xff, 0xfc, 0xf8, 0xf4, + 0xf1, 0xf0, 0xef, 0xf3, 0xf6, 0xf5, 0xf7, 0xfd, 0x03, 0x07, 0x0e, 0x0c, + 0x04, 0xff, 0xfe, 0xfe, 0x03, 0x07, 0x09, 0x07, 0x0a, 0x0b, 0x06, 0x06, + 0x0b, 0x0f, 0x15, 0x16, 0x11, 0x0a, 0x02, 0xfc, 0xfb, 0xfc, 0x02, 0x06, + 0x03, 0x02, 0x01, 0x00, 0xfe, 0xfd, 0xfd, 0xfc, 0xfc, 0xfe, 0x06, 0x0a, + 0x09, 0x02, 0xfa, 0xf2, 0xf3, 0xf6, 0xf4, 0xfd, 0x09, 0x0a, 0x05, 0x04, + 0x05, 0x07, 0x0b, 0x10, 0x14, 0x0f, 0x08, 0x07, 0x09, 0x0b, 0x0c, 0x09, + 0x03, 0x01, 0xfb, 0xfb, 0xfc, 0x09, 0x10, 0x10, 0x0c, 0x07, 0x04, 0x04, + 0x01, 0x00, 0xfe, 0xfb, 0xf8, 0xf2, 0xf2, 0xf9, 0xfb, 0xfc, 0x01, 0x01, + 0x04, 0x09, 0x10, 0x11, 0x10, 0x04, 0xf6, 0xf0, 0xf1, 0xf6, 0xfd, 0x05, + 0x0c, 0x0b, 0x04, 0xfd, 0xfd, 0x06, 0x0b, 0x12, 0x16, 0x18, 0x13, 0x0f, + 0x0c, 0x07, 0x02, 0x05, 0x05, 0x00, 0x02, 0x09, 0x0b, 0x09, 0x09, 0x04, + 0xff, 0xfd, 0xf9, 0xf8, 0xfa, 0xfa, 0xf9, 0xf8, 0xf4, 0xf0, 0xf3, 0xfb, + 0xff, 0x01, 0xff, 0xfb, 0xfb, 0x02, 0x07, 0x06, 0x07, 0x10, 0x12, 0x0b, + 0x04, 0x02, 0x07, 0x09, 0x07, 0x03, 0x03, 0x0a, 0x07, 0x09, 0x0f, 0x17, + 0x1a, 0x19, 0x14, 0x0e, 0x07, 0x02, 0x02, 0x06, 0x04, 0xfb, 0xf8, 0xf5, + 0xf4, 0xf0, 0xec, 0xf0, 0xf7, 0xf9, 0xfc, 0xff, 0x07, 0x08, 0x03, 0xfc, + 0xf6, 0xf1, 0xf2, 0xf8, 0xfd, 0x06, 0x13, 0x18, 0x10, 0x0f, 0x10, 0x11, + 0x13, 0x19, 0x1a, 0x13, 0x09, 0x01, 0xff, 0xfa, 0xfb, 0x03, 0x04, 0x02, + 0x02, 0x04, 0x04, 0x04, 0x05, 0x03, 0xfe, 0xff, 0xff, 0x00, 0x01, 0x04, + 0x05, 0x00, 0xfb, 0xf5, 0xf3, 0xf9, 0x07, 0x0b, 0x08, 0x05, 0x05, 0x05, + 0x02, 0xfd, 0x00, 0x06, 0x05, 0x02, 0xff, 0x03, 0x07, 0x06, 0x07, 0x04, + 0x02, 0xfd, 0xfc, 0x02, 0x0b, 0x13, 0x18, 0x16, 0x0e, 0x06, 0x00, 0xfc, + 0xfe, 0x02, 0x02, 0xf9, 0xf7, 0xff, 0x00, 0xfa, 0xfe, 0x04, 0x07, 0x05, + 0x05, 0x0b, 0x0c, 0x09, 0x04, 0xfc, 0xf8, 0xf7, 0xf4, 0xf5, 0xfb, 0x03, + 0x0c, 0x09, 0x02, 0x04, 0x05, 0x05, 0x0a, 0x0e, 0x0e, 0x0a, 0x04, 0x00, + 0xfc, 0xfa, 0xfc, 0x02, 0x06, 0x0d, 0x0f, 0x11, 0x13, 0x11, 0x0c, 0x07, + 0x00, 0xfb, 0xf6, 0xf5, 0xf4, 0xfa, 0xff, 0xfb, 0xf5, 0xf5, 0xf7, 0xfc, + 0x00, 0x03, 0x04, 0x04, 0x05, 0x05, 0x02, 0x02, 0x09, 0x0e, 0x0c, 0x08, + 0x07, 0x06, 0x05, 0x03, 0x09, 0x0d, 0x09, 0x05, 0x04, 0x0a, 0x0d, 0x0f, + 0x10, 0x09, 0x03, 0x00, 0xfd, 0xfb, 0xfc, 0x01, 0xff, 0xf9, 0xf7, 0xf5, + 0xf3, 0xf2, 0xfa, 0x01, 0x01, 0x00, 0x05, 0x07, 0x04, 0x00, 0xfc, 0xf7, + 0xf1, 0xf3, 0xf5, 0xfe, 0x0b, 0x16, 0x1c, 0x18, 0x17, 0x15, 0x0e, 0x0f, + 0x14, 0x14, 0x0f, 0x09, 0x06, 0x01, 0xfb, 0xfa, 0xfb, 0xff, 0x00, 0x03, + 0x04, 0x05, 0x06, 0x04, 0xff, 0xfb, 0xf8, 0xf6, 0xf5, 0xf8, 0xf7, 0xf7, + 0xfb, 0xf9, 0xfa, 0x01, 0x07, 0x09, 0x0c, 0x10, 0x0d, 0x08, 0x05, 0x02, + 0xfc, 0xf7, 0xfe, 0x04, 0x03, 0x05, 0x09, 0x08, 0x06, 0x08, 0x06, 0x06, + 0x02, 0x03, 0x05, 0x0a, 0x11, 0x17, 0x16, 0x10, 0x0c, 0x08, 0xff, 0xf9, + 0xfc, 0x00, 0x00, 0x04, 0x04, 0xff, 0xf9, 0xfa, 0xfd, 0xfe, 0x00, 0x00, + 0xff, 0x01, 0x02, 0xfd, 0xf7, 0xf6, 0xf4, 0xf3, 0xf5, 0xfa, 0x01, 0x0c, + 0x12, 0x0f, 0x0e, 0x0f, 0x0b, 0x07, 0x09, 0x0b, 0x08, 0x01, 0xfb, 0xf9, + 0xfa, 0x02, 0x0d, 0x15, 0x16, 0x14, 0x16, 0x11, 0x0f, 0x0c, 0x0b, 0x06, + 0x00, 0xf9, 0xf8, 0xf9, 0xfb, 0xfc, 0xf8, 0xf2, 0xf6, 0xfc, 0xfd, 0xfb, + 0xfd, 0x01, 0x00, 0xfe, 0xfb, 0xf9, 0xf8, 0xfb, 0x01, 0x00, 0x00, 0x03, + 0x07, 0x0b, 0x13, 0x15, 0x11, 0x0f, 0x09, 0x07, 0x0a, 0x0c, 0x0c, 0x0b, + 0x08, 0x02, 0x05, 0x06, 0x01, 0xff, 0x01, 0x05, 0x02, 0x01, 0xfd, 0xf9, + 0xf7, 0xfb, 0x01, 0x04, 0x07, 0x0a, 0x07, 0x06, 0xff, 0xf6, 0xf2, 0xf2, + 0xf2, 0xfb, 0x05, 0x09, 0x0c, 0x11, 0x0f, 0x0d, 0x0f, 0x0e, 0x0a, 0x03, + 0x03, 0x07, 0x06, 0x02, 0xfd, 0xf7, 0xf5, 0xfb, 0x04, 0x08, 0x09, 0x0a, + 0x0b, 0x09, 0x05, 0x01, 0x00, 0xfb, 0xf8, 0xf7, 0xf3, 0xf0, 0xf6, 0x01, + 0x07, 0x0c, 0x12, 0x10, 0x0f, 0x0c, 0x0b, 0x0b, 0x0c, 0x0c, 0x02, 0xf7, + 0xf5, 0xff, 0x06, 0x06, 0x03, 0x01, 0xff, 0x03, 0x07, 0x03, 0xff, 0xfe, + 0xfe, 0x01, 0x04, 0x08, 0x08, 0x09, 0x07, 0xff, 0xfd, 0xfc, 0xfd, 0x00, + 0x0a, 0x12, 0x0f, 0x0a, 0x04, 0xfe, 0xf9, 0xfb, 0x02, 0x00, 0xfc, 0xfc, + 0x02, 0x04, 0x01, 0xfb, 0xf8, 0xf8, 0xfb, 0xff, 0x02, 0x04, 0x0a, 0x10, + 0x12, 0x13, 0x15, 0x15, 0x0f, 0x0a, 0x03, 0xfd, 0xfa, 0xf9, 0xf7, 0xfc, + 0x04, 0x0e, 0x0f, 0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x07, 0xff, 0xf7, 0xf5, + 0xfa, 0xfe, 0xfa, 0xf2, 0xf2, 0xf8, 0xfb, 0x00, 0x05, 0x06, 0x03, 0x00, + 0xff, 0xff, 0xff, 0xfc, 0xf7, 0xf6, 0xf1, 0xf7, 0x03, 0x09, 0x10, 0x1a, + 0x1e, 0x1c, 0x16, 0x0d, 0x08, 0x0b, 0x10, 0x13, 0x11, 0x0a, 0x03, 0x06, + 0x0c, 0x08, 0xff, 0xfa, 0xf9, 0xfa, 0xff, 0x01, 0x00, 0xf7, 0xf2, 0xf2, + 0xf1, 0xf9, 0x00, 0x01, 0xff, 0xfe, 0xf7, 0xf5, 0xf7, 0xf6, 0xfb, 0x05, + 0x0a, 0x0a, 0x0a, 0x09, 0x0a, 0x11, 0x12, 0x0c, 0x09, 0x05, 0x03, 0x07, + 0x09, 0x07, 0x04, 0x01, 0xfe, 0xff, 0x03, 0x0c, 0x0d, 0x0b, 0x0c, 0x0e, + 0x0e, 0x0f, 0x0d, 0x01, 0xf9, 0xf6, 0xf2, 0xf1, 0xf1, 0xf2, 0xf9, 0x09, + 0x10, 0x0a, 0x09, 0x06, 0x07, 0x06, 0x06, 0x03, 0xfa, 0xf2, 0xf1, 0xf6, + 0xf9, 0xfe, 0x00, 0x02, 0x05, 0x0a, 0x0c, 0x08, 0x03, 0xfe, 0xfe, 0xff, + 0x01, 0x07, 0x08, 0x04, 0xff, 0x00, 0x02, 0x04, 0x0a, 0x10, 0x18, 0x1c, + 0x19, 0x11, 0x09, 0x06, 0x04, 0x01, 0xff, 0x01, 0xfd, 0xfd, 0x04, 0x06, + 0xfe, 0xf4, 0xf2, 0xed, 0xf2, 0xfa, 0xfc, 0xfd, 0xfc, 0xfb, 0xfe, 0x0a, + 0x10, 0x0e, 0x0a, 0x03, 0xfb, 0xf8, 0xfc, 0xfe, 0xfb, 0x01, 0x0d, 0x0e, + 0x0c, 0x0f, 0x0f, 0x0e, 0x0d, 0x09, 0x06, 0x03, 0xfc, 0xfa, 0x02, 0x05, + 0x02, 0x03, 0x00, 0xfb, 0xfe, 0x05, 0x0b, 0x0b, 0x09, 0x06, 0x06, 0x0c, + 0x0d, 0x05, 0xf6, 0xee, 0xec, 0xeb, 0xf2, 0xf9, 0x01, 0x10, 0x19, 0x17, + 0x11, 0x08, 0x01, 0xfe, 0x03, 0x07, 0x09, 0x07, 0x02, 0x01, 0x05, 0x09, + 0x03, 0xfe, 0xff, 0x04, 0x07, 0x08, 0x07, 0xff, 0xf6, 0xf6, 0xf8, 0xf5, + 0xf8, 0xfc, 0xfa, 0xfb, 0x02, 0x07, 0x04, 0x02, 0x09, 0x0e, 0x0f, 0x0f, + 0x0e, 0x0e, 0x0d, 0x0b, 0x0f, 0x14, 0x11, 0x09, 0x05, 0x05, 0x03, 0xff, + 0xf9, 0xf3, 0xf3, 0xf8, 0xfd, 0xfd, 0xfe, 0x01, 0x00, 0x04, 0x0b, 0x0d, + 0x09, 0x01, 0xf5, 0xef, 0xf4, 0xf9, 0xfa, 0xfe, 0x03, 0x06, 0x0b, 0x0d, + 0x0c, 0x0c, 0x0a, 0x04, 0x03, 0x06, 0x00, 0xf6, 0xf7, 0xfd, 0xfd, 0xfc, + 0x01, 0x09, 0x0c, 0x10, 0x13, 0x11, 0x09, 0x05, 0x01, 0x01, 0x06, 0x0d, + 0x0a, 0x04, 0xfc, 0xf9, 0xff, 0xff, 0xfd, 0x00, 0x0e, 0x15, 0x17, 0x12, + 0x08, 0x00, 0xfe, 0xfd, 0xfc, 0xf7, 0xf4, 0xf6, 0xfc, 0x02, 0x03, 0x01, + 0xf9, 0xf8, 0xf9, 0xf8, 0xfa, 0xfd, 0xfd, 0xfe, 0xfc, 0xff, 0x0a, 0x0d, + 0x08, 0x03, 0x04, 0x06, 0x0a, 0x09, 0x05, 0x08, 0x14, 0x16, 0x12, 0x0f, + 0x12, 0x15, 0x12, 0x0f, 0x0e, 0x0b, 0x04, 0x00, 0xfa, 0xf4, 0xf6, 0xf7, + 0xf5, 0xf9, 0xf6, 0xf7, 0xfc, 0xff, 0x00, 0x02, 0x04, 0x07, 0x0c, 0x07, + 0xf7, 0xe9, 0xea, 0xf0, 0xf2, 0xf0, 0xfb, 0x0f, 0x18, 0x17, 0x15, 0x10, + 0x08, 0x01, 0xfd, 0xfb, 0x02, 0x05, 0x0a, 0x0d, 0x0d, 0x0f, 0x12, 0x0e, + 0x0b, 0x0c, 0x0c, 0x0e, 0x12, 0x0d, 0x05, 0xff, 0xff, 0x01, 0xff, 0xf6, + 0xf1, 0xf3, 0xf9, 0xfc, 0xf8, 0xf8, 0xfe, 0x07, 0x07, 0x05, 0x06, 0x05, + 0x06, 0x03, 0x03, 0x08, 0x07, 0x03, 0x00, 0x02, 0x00, 0x02, 0x03, 0x00, + 0xfa, 0xf8, 0xfb, 0xfe, 0xfd, 0xfd, 0x01, 0x04, 0x06, 0x09, 0x0b, 0x07, + 0x02, 0x03, 0x03, 0x01, 0x03, 0x09, 0x10, 0x12, 0x12, 0x13, 0x13, 0x11, + 0x0f, 0x0e, 0x0b, 0x0d, 0x09, 0xfe, 0xf2, 0xf0, 0xf0, 0xed, 0xee, 0xf3, + 0xf9, 0x00, 0x04, 0x04, 0x04, 0x03, 0x00, 0xfe, 0xfe, 0x00, 0x00, 0xfe, + 0xfd, 0xfd, 0x01, 0x02, 0x01, 0x03, 0x0c, 0x16, 0x17, 0x16, 0x13, 0x08, + 0x00, 0xfb, 0xfc, 0xfc, 0xf8, 0xf7, 0xff, 0x09, 0x0a, 0x0d, 0x10, 0x08, + 0x02, 0x01, 0xfe, 0xfe, 0x02, 0x03, 0x01, 0x00, 0x0b, 0x0c, 0x03, 0xfe, + 0xfa, 0xfa, 0xf8, 0xfa, 0xfc, 0xff, 0x05, 0x0c, 0x0e, 0x0c, 0x09, 0x06, + 0x0a, 0x0c, 0x09, 0x06, 0x03, 0xff, 0xfc, 0xfc, 0xfe, 0xfc, 0xfc, 0xf9, + 0xf5, 0xf7, 0xfc, 0xfe, 0xfd, 0xfe, 0x02, 0x06, 0x0b, 0x0b, 0x07, 0x01, + 0xfc, 0xfb, 0xfc, 0xfb, 0xfd, 0x0b, 0x18, 0x20, 0x1c, 0x15, 0x11, 0x0d, + 0x09, 0x04, 0x00, 0xfe, 0xfe, 0x00, 0xfe, 0x01, 0x05, 0x04, 0xfe, 0xfd, + 0x00, 0x05, 0x09, 0x0b, 0x09, 0x04, 0xfe, 0xfd, 0xfc, 0xf2, 0xeb, 0xec, + 0xf5, 0xfa, 0xfa, 0xfc, 0x05, 0x0b, 0x0d, 0x09, 0x02, 0xfc, 0xfd, 0x00, + 0xff, 0x05, 0x0c, 0x0a, 0x06, 0x09, 0x0e, 0x0f, 0x12, 0x10, 0x06, 0x01, + 0x01, 0x05, 0x06, 0x04, 0x02, 0x03, 0x0a, 0x0f, 0x09, 0x03, 0x00, 0xfc, + 0xfa, 0xf5, 0xf5, 0xf8, 0x00, 0x07, 0x0d, 0x10, 0x0d, 0x09, 0x09, 0x07, + 0x06, 0x07, 0x05, 0xfc, 0xf6, 0xf6, 0xf4, 0xf5, 0xf5, 0xf1, 0xed, 0xf3, + 0xfe, 0x01, 0xfc, 0xfe, 0xff, 0xff, 0x03, 0x06, 0x02, 0x02, 0x08, 0x0b, + 0x0c, 0x12, 0x13, 0x10, 0x14, 0x1d, 0x21, 0x1b, 0x18, 0x16, 0x11, 0x0a, + 0x04, 0x00, 0xf5, 0xed, 0xec, 0xf0, 0xf8, 0xfe, 0xfc, 0xfb, 0xfb, 0xfb, + 0xfd, 0xfd, 0xfa, 0xfa, 0xfa, 0xf9, 0x00, 0x04, 0x00, 0xfc, 0xf7, 0xf5, + 0xf8, 0xfe, 0x02, 0x05, 0x0a, 0x0d, 0x07, 0x05, 0x04, 0x03, 0x02, 0x08, + 0x0f, 0x0c, 0x0a, 0x11, 0x13, 0x11, 0x12, 0x0f, 0x06, 0xfe, 0xfd, 0x01, + 0x07, 0x08, 0x06, 0x02, 0x03, 0x09, 0x0a, 0x05, 0x02, 0xfc, 0xf3, 0xed, + 0xec, 0xf0, 0xf1, 0xf7, 0x03, 0x0d, 0x12, 0x0e, 0x0b, 0x09, 0x04, 0x02, + 0xfe, 0xf9, 0xf8, 0xf6, 0xf8, 0x02, 0x0b, 0x09, 0x00, 0xfa, 0xfd, 0x02, + 0x04, 0x03, 0x04, 0x05, 0x0c, 0x0d, 0x07, 0x05, 0xff, 0xfa, 0xfb, 0x01, + 0x0b, 0x0c, 0x0c, 0x14, 0x1a, 0x17, 0x0d, 0x07, 0x03, 0xfd, 0xfe, 0x00, + 0x01, 0x01, 0xfd, 0xf8, 0xf8, 0xfd, 0xfe, 0xfc, 0xfc, 0xfd, 0x02, 0x02, + 0x01, 0x02, 0x00, 0xfe, 0xff, 0x05, 0x05, 0x01, 0xfe, 0xfd, 0xfd, 0xfe, + 0xff, 0x01, 0x00, 0x02, 0x06, 0x06, 0x06, 0x07, 0x08, 0x08, 0x0b, 0x0c, + 0x0b, 0x0b, 0x0e, 0x0d, 0x0b, 0x07, 0x01, 0xfb, 0xf5, 0xf7, 0xff, 0x04, + 0x04, 0xff, 0x01, 0x05, 0x09, 0x07, 0x01, 0xf8, 0xf2, 0xee, 0xf6, 0x02, + 0x07, 0x09, 0x0a, 0x13, 0x1a, 0x19, 0x17, 0x13, 0x0e, 0x09, 0x07, 0xff, + 0xf9, 0xf6, 0xf0, 0xef, 0xf5, 0xfd, 0xfb, 0xf6, 0xf6, 0xfd, 0xfe, 0xf8, + 0xf5, 0xf5, 0xf5, 0xfa, 0x05, 0x0b, 0x0b, 0x0a, 0x06, 0x05, 0x0a, 0x0a, + 0x09, 0x0b, 0x14, 0x1d, 0x15, 0x0d, 0x0d, 0x0c, 0x05, 0x03, 0x03, 0x02, + 0x03, 0x01, 0x02, 0x03, 0x01, 0xff, 0xfd, 0xfb, 0xfa, 0xfb, 0x01, 0x05, + 0x06, 0x02, 0xfe, 0x02, 0x05, 0x01, 0xfc, 0xf8, 0xf6, 0xf8, 0xf7, 0xf3, + 0xf3, 0xf6, 0xfc, 0xff, 0xff, 0x01, 0x04, 0x04, 0x09, 0x0a, 0x09, 0x0c, + 0x0e, 0x0d, 0x08, 0x09, 0x11, 0x12, 0x0c, 0x09, 0x07, 0x0d, 0x0f, 0x0c, + 0x06, 0x06, 0x0c, 0x10, 0x08, 0xfe, 0xf7, 0xf0, 0xec, 0xf1, 0xf7, 0xfd, + 0x01, 0x09, 0x12, 0x15, 0x10, 0x0b, 0x03, 0xfb, 0xf0, 0xee, 0xf7, 0x00, + 0xff, 0xf8, 0xf7, 0xfc, 0xfc, 0xf7, 0xf5, 0xf7, 0xff, 0x02, 0xfd, 0xfb, + 0x01, 0x07, 0x08, 0x0c, 0x0d, 0x0d, 0x10, 0x14, 0x15, 0x10, 0x0c, 0x0c, + 0x0f, 0x12, 0x10, 0x0b, 0x09, 0x0d, 0x0e, 0x06, 0xff, 0x02, 0x05, 0x03, + 0xfb, 0xf9, 0xfc, 0xfc, 0xf7, 0xf2, 0xf2, 0xf5, 0xf8, 0xfe, 0xfc, 0xfc, + 0xfd, 0xfb, 0xff, 0x01, 0xfd, 0xfb, 0xfa, 0xf7, 0xf6, 0xf9, 0x00, 0x07, + 0x0a, 0x0b, 0x0e, 0x0f, 0x11, 0x13, 0x0c, 0x09, 0x0f, 0x17, 0x1a, 0x13, + 0x0d, 0x06, 0x03, 0x04, 0x01, 0xfc, 0x00, 0x06, 0x07, 0x01, 0xfe, 0xff, + 0xfc, 0xf8, 0xf7, 0xf5, 0xf6, 0xfa, 0xfb, 0xf8, 0xf8, 0xfd, 0x00, 0x02, + 0x08, 0x12, 0x1a, 0x15, 0x0e, 0x06, 0xfd, 0xf9, 0xfd, 0x05, 0x05, 0x01, + 0x02, 0x04, 0x03, 0xfd, 0xf8, 0xf9, 0xfe, 0xfc, 0xf8, 0xf5, 0xff, 0x07, + 0x09, 0x09, 0x0e, 0x0f, 0x10, 0x11, 0x0c, 0x09, 0x07, 0x05, 0x02, 0x01, + 0x04, 0x04, 0x03, 0x04, 0x03, 0xff, 0xfd, 0xff, 0x02, 0x01, 0x00, 0xfd, + 0xfb, 0xfb, 0xfd, 0xfa, 0x00, 0x0a, 0x0b, 0x0a, 0x0f, 0x10, 0x0e, 0x00, + 0xfa, 0x02, 0x09, 0x08, 0x01, 0xfc, 0xf8, 0xf3, 0xf4, 0xf6, 0xf8, 0xfd, + 0x06, 0x0b, 0x09, 0x05, 0x01, 0xfe, 0xfe, 0x05, 0x08, 0x0b, 0x0f, 0x0e, + 0x07, 0x04, 0x01, 0xff, 0x01, 0x01, 0xff, 0x04, 0x08, 0x07, 0x01, 0x00, + 0x01, 0x03, 0x00, 0xfe, 0xfe, 0x03, 0x07, 0x06, 0x03, 0x05, 0x07, 0x0f, + 0x17, 0x18, 0x0c, 0x03, 0xfe, 0xfc, 0xfd, 0x00, 0x05, 0x07, 0x01, 0xf7, + 0xf2, 0xf3, 0xf5, 0xf1, 0xed, 0xee, 0xf1, 0xf3, 0xf7, 0xf8, 0xf5, 0xfc, + 0x0b, 0x10, 0x0f, 0x12, 0x13, 0x0f, 0x07, 0x06, 0x07, 0x0b, 0x11, 0x15, + 0x15, 0x15, 0x16, 0x17, 0x0f, 0x06, 0x03, 0x09, 0x0f, 0x0c, 0x02, 0xfc, + 0xf8, 0xf9, 0xf9, 0xf8, 0xfc, 0x04, 0x07, 0x01, 0xfc, 0xf3, 0xed, 0xf1, + 0xf8, 0xf9, 0xf7, 0xf7, 0xfa, 0xf5, 0xf0, 0xf3, 0xf9, 0xfd, 0x02, 0x08, + 0x0a, 0x0c, 0x0d, 0x07, 0x08, 0x0e, 0x14, 0x19, 0x1b, 0x16, 0x12, 0x13, + 0x14, 0x0b, 0x03, 0x01, 0x02, 0x03, 0x04, 0x06, 0x03, 0xfd, 0xff, 0x01, + 0xfd, 0xff, 0x03, 0x08, 0x02, 0xf6, 0xf5, 0xfc, 0x02, 0x03, 0x06, 0x06, + 0x02, 0xfe, 0xf8, 0xf3, 0xf7, 0xfc, 0x01, 0x02, 0x01, 0xfd, 0xf5, 0xf5, + 0xf6, 0xf7, 0xf9, 0xfc, 0x01, 0x02, 0x02, 0x09, 0x0c, 0x0c, 0x0f, 0x13, + 0x15, 0x1c, 0x22, 0x1c, 0x0f, 0x07, 0x04, 0x03, 0x02, 0x01, 0x05, 0x0b, + 0x09, 0x02, 0xfd, 0xfb, 0xf8, 0xf7, 0xfa, 0xfe, 0xfc, 0xf8, 0xf7, 0xf8, + 0xf5, 0xfa, 0x01, 0x05, 0x04, 0x00, 0x00, 0xfe, 0xfa, 0xf9, 0x00, 0x05, + 0x08, 0x07, 0x04, 0xff, 0xff, 0x00, 0x00, 0x01, 0x01, 0x02, 0x06, 0x0a, + 0x0a, 0x0a, 0x0b, 0x0d, 0x0f, 0x10, 0x14, 0x19, 0x17, 0x0e, 0x03, 0xfd, + 0xfa, 0xfd, 0xfc, 0xf6, 0xf5, 0xf6, 0xf6, 0xf4, 0xf1, 0xf4, 0xfc, 0xfe, + 0x00, 0x05, 0x03, 0xfb, 0xf5, 0xfa, 0x07, 0x13, 0x17, 0x14, 0x12, 0x0b, + 0x08, 0x0d, 0x12, 0x0e, 0x0a, 0x09, 0x0a, 0x0c, 0x07, 0xfe, 0xf8, 0xf8, + 0xf7, 0xf4, 0xf4, 0xf9, 0xfe, 0xf9, 0xf4, 0xf1, 0xf5, 0xfd, 0x07, 0x0b, + 0x0e, 0x0f, 0x0a, 0x00, 0xfc, 0xff, 0x02, 0x04, 0x05, 0x08, 0x08, 0x06, + 0x07, 0x0a, 0x08, 0x03, 0x03, 0x09, 0x0c, 0x0b, 0x07, 0x06, 0x0a, 0x0a, + 0x07, 0x0a, 0x06, 0x01, 0xfe, 0xfb, 0xfb, 0x00, 0x04, 0x04, 0x01, 0x00, + 0x01, 0xfe, 0xf7, 0xf0, 0xef, 0xf5, 0xfb, 0xfe, 0xff, 0xfa, 0xf4, 0xf8, + 0xff, 0x01, 0x05, 0x0b, 0x12, 0x11, 0x14, 0x13, 0x08, 0x00, 0xfe, 0xfc, + 0x00, 0x08, 0x0a, 0x04, 0x00, 0x00, 0x03, 0x09, 0x0e, 0x0e, 0x0c, 0x0e, + 0x0e, 0x09, 0x03, 0x01, 0x05, 0x10, 0x10, 0x09, 0x05, 0x02, 0xff, 0xfa, + 0xf7, 0xfa, 0xf8, 0xf7, 0xf7, 0xf7, 0xfa, 0xf9, 0xf4, 0xee, 0xed, 0xed, + 0xf5, 0xfc, 0xfe, 0xfc, 0xf8, 0xf9, 0xff, 0x08, 0x12, 0x17, 0x1c, 0x1e, + 0x15, 0x0f, 0x0d, 0x10, 0x13, 0x11, 0x0b, 0x09, 0x05, 0x03, 0x04, 0x09, + 0x0f, 0x12, 0x0b, 0x05, 0x03, 0x05, 0x05, 0x02, 0xfe, 0xf8, 0xf8, 0xfe, + 0x01, 0xff, 0xf6, 0xe8, 0xe5, 0xec, 0xf2, 0xf8, 0x00, 0x04, 0x02, 0xf8, + 0xf4, 0xf4, 0xf1, 0xf4, 0xfb, 0x04, 0x0b, 0x0e, 0x09, 0x04, 0x09, 0x0f, + 0x18, 0x1f, 0x21, 0x1f, 0x1e, 0x1c, 0x1c, 0x16, 0x08, 0x00, 0x02, 0x05, + 0x02, 0xff, 0xf8, 0xf5, 0xf3, 0xed, 0xee, 0xf5, 0xfb, 0xfc, 0xf9, 0xf8, + 0xfc, 0xfc, 0xfa, 0x01, 0x08, 0x06, 0x05, 0x02, 0xfd, 0xfe, 0x03, 0x06, + 0x08, 0x0b, 0x07, 0x05, 0x06, 0x06, 0x04, 0xff, 0xfe, 0x04, 0x07, 0x03, + 0x01, 0xfd, 0xf6, 0xf4, 0xfa, 0x06, 0x15, 0x1e, 0x1e, 0x19, 0x11, 0x0a, + 0x05, 0x00, 0xfe, 0xff, 0xfe, 0xfe, 0xfd, 0xfb, 0xf8, 0xf8, 0xfb, 0xfd, + 0xfe, 0x00, 0x02, 0x05, 0x06, 0x00, 0xfe, 0xfe, 0xfe, 0xff, 0x02, 0x0a, + 0x0b, 0xfd, 0xf6, 0xfa, 0x00, 0x06, 0x11, 0x19, 0x14, 0x0a, 0x03, 0xff, + 0x00, 0x03, 0x03, 0x06, 0x09, 0x03, 0x00, 0xfe, 0x00, 0x03, 0x00, 0xfe, + 0x00, 0x06, 0x07, 0x07, 0x06, 0x06, 0x01, 0xf7, 0xf3, 0xfb, 0xfe, 0xfe, + 0xfb, 0xf4, 0xf3, 0xf8, 0xfc, 0x00, 0x0b, 0x11, 0x0b, 0x08, 0x08, 0x07, + 0x0b, 0x11, 0x19, 0x1c, 0x15, 0x07, 0xff, 0x02, 0x02, 0x04, 0x08, 0x13, + 0x13, 0x08, 0x05, 0x03, 0xfd, 0xf9, 0xf6, 0xf0, 0xee, 0xf2, 0xf5, 0xf4, + 0xee, 0xea, 0xe9, 0xed, 0xf8, 0x03, 0x10, 0x15, 0x12, 0x0c, 0x04, 0xfc, + 0xfb, 0x00, 0x03, 0x03, 0x05, 0x0d, 0x0e, 0x08, 0x0a, 0x10, 0x12, 0x16, + 0x18, 0x19, 0x16, 0x12, 0x10, 0x0f, 0x10, 0x0c, 0x09, 0x09, 0x06, 0xfc, + 0xf1, 0xee, 0xf3, 0xf5, 0xf3, 0xf2, 0xf7, 0xf6, 0xee, 0xe9, 0xef, 0xf4, + 0xf3, 0xf4, 0xfa, 0xfe, 0xfd, 0xff, 0x01, 0xfe, 0x04, 0x0b, 0x0f, 0x14, + 0x1c, 0x1c, 0x15, 0x11, 0x10, 0x0b, 0x06, 0x0a, 0x11, 0x11, 0x07, 0xf9, + 0xf4, 0xf9, 0xfd, 0x00, 0x09, 0x15, 0x10, 0x07, 0x07, 0x0a, 0x04, 0x02, + 0x05, 0x00, 0xfa, 0xf6, 0xf9, 0xf9, 0xf7, 0xf9, 0xf7, 0xfa, 0xff, 0x00, + 0x00, 0x00, 0xff, 0xfa, 0xf6, 0xf0, 0xf1, 0xf6, 0xfc, 0xfc, 0xfb, 0xf8, + 0xf8, 0x00, 0x08, 0x12, 0x1c, 0x25, 0x23, 0x1b, 0x16, 0x11, 0x0b, 0x0d, + 0x10, 0x0c, 0x06, 0x07, 0x09, 0x04, 0xff, 0x01, 0x02, 0xff, 0xfc, 0xf4, + 0xf5, 0xfc, 0x00, 0xff, 0xff, 0xfa, 0xf7, 0xfa, 0xfe, 0xfb, 0xf4, 0xf4, + 0xf5, 0xf3, 0xf9, 0x01, 0x0a, 0x0b, 0x06, 0x03, 0x00, 0x01, 0x04, 0x06, + 0x07, 0x0c, 0x0f, 0x0f, 0x0d, 0x04, 0x02, 0x0a, 0x14, 0x18, 0x19, 0x15, + 0x12, 0x0d, 0x0b, 0x09, 0x06, 0xff, 0xfa, 0xf7, 0xef, 0xe8, 0xe8, 0xee, + 0xf2, 0xf2, 0xf5, 0xfa, 0x00, 0x00, 0x05, 0x0a, 0x08, 0x03, 0x01, 0xfc, + 0xf8, 0xfd, 0x04, 0x0b, 0x0c, 0x04, 0x02, 0x0b, 0x14, 0x19, 0x18, 0x18, + 0x10, 0x0b, 0x09, 0x07, 0x06, 0x07, 0x09, 0x05, 0xf9, 0xf5, 0xf4, 0xf2, + 0xf9, 0x01, 0x01, 0xff, 0xff, 0xf7, 0xf5, 0xfa, 0xfc, 0xfb, 0xfa, 0xf6, + 0xf5, 0xfb, 0x04, 0x0d, 0x08, 0x01, 0x02, 0x09, 0x09, 0x08, 0x0b, 0x12, + 0x15, 0x13, 0x10, 0x0f, 0x0d, 0x0c, 0x0d, 0x09, 0x02, 0x00, 0xff, 0xf9, + 0xfb, 0x01, 0x08, 0x0d, 0x09, 0x03, 0x00, 0xfd, 0xfe, 0x02, 0x00, 0xf9, + 0xf5, 0xf3, 0xf8, 0xf8, 0xf6, 0xfb, 0x04, 0x06, 0x02, 0x02, 0x04, 0x04, + 0x07, 0x05, 0x00, 0x00, 0xfe, 0xf9, 0xf5, 0xf5, 0xfa, 0xfc, 0xfc, 0x00, + 0x07, 0x0a, 0x10, 0x1a, 0x1f, 0x1e, 0x1b, 0x18, 0x14, 0x10, 0x0d, 0x0a, + 0x0c, 0x0d, 0x0d, 0x04, 0xfa, 0xfd, 0x06, 0x02, 0xfb, 0xfa, 0xf5, 0xed, + 0xee, 0xed, 0xf0, 0xf0, 0xef, 0xed, 0xeb, 0xf0, 0xf4, 0xfd, 0x02, 0x03, + 0x00, 0x01, 0x03, 0x08, 0x0d, 0x0b, 0x0d, 0x0e, 0x0e, 0x0d, 0x0c, 0x10, + 0x12, 0x13, 0x15, 0x13, 0x0d, 0x0e, 0x0e, 0x0c, 0x0f, 0x10, 0x0f, 0x0d, + 0x08, 0x04, 0x08, 0x0c, 0x06, 0xf7, 0xec, 0xec, 0xeb, 0xec, 0xed, 0xeb, + 0xef, 0xf3, 0xf9, 0xfe, 0xfe, 0xff, 0xfc, 0xf8, 0xf8, 0xf8, 0xfa, 0xfa, + 0xfd, 0x04, 0x0a, 0x08, 0x0c, 0x17, 0x19, 0x16, 0x18, 0x1c, 0x1c, 0x19, + 0x16, 0x14, 0x12, 0x12, 0x09, 0x01, 0x00, 0x00, 0xfa, 0xf5, 0xf8, 0xfd, + 0xfa, 0xf9, 0xfb, 0xfe, 0xfc, 0xf8, 0xf6, 0xf3, 0xf3, 0xf4, 0xf5, 0xf9, + 0x00, 0x08, 0x0a, 0x07, 0x09, 0x07, 0x02, 0x03, 0x08, 0x0c, 0x0b, 0x04, + 0x02, 0x06, 0x08, 0x09, 0x07, 0x02, 0x00, 0x00, 0x06, 0x0c, 0x0d, 0x06, + 0x01, 0x00, 0x07, 0x0a, 0x07, 0x03, 0x01, 0x01, 0x09, 0x0d, 0x05, 0xfe, + 0xfd, 0xfe, 0xfb, 0xfe, 0xff, 0xfa, 0xfc, 0x02, 0x04, 0x05, 0x08, 0x06, + 0xff, 0x00, 0x00, 0xfb, 0xf8, 0xf6, 0xf8, 0xf5, 0xf6, 0xfc, 0xfe, 0x02, + 0x09, 0x12, 0x1d, 0x1e, 0x16, 0x0d, 0x07, 0x0d, 0x0f, 0x0c, 0x06, 0x08, + 0x0e, 0x0c, 0x07, 0x05, 0x07, 0x00, 0xfb, 0xf8, 0xf5, 0xf9, 0xfa, 0xf5, + 0xf1, 0xed, 0xf1, 0xf1, 0xf1, 0xf2, 0xf4, 0xf9, 0x03, 0x04, 0x02, 0x01, + 0x01, 0x09, 0x10, 0x0f, 0x08, 0x05, 0x0d, 0x15, 0x13, 0x12, 0x15, 0x15, + 0x16, 0x12, 0x13, 0x13, 0x10, 0x0a, 0x07, 0x06, 0x0a, 0x08, 0xfd, 0xf4, + 0xf6, 0xfa, 0x00, 0x01, 0xfa, 0xf0, 0xed, 0xf2, 0xf4, 0xef, 0xe8, 0xe9, + 0xf0, 0xf8, 0xfb, 0xfd, 0xfc, 0xfe, 0x04, 0x05, 0x03, 0x05, 0x08, 0x08, + 0x07, 0x08, 0x0c, 0x10, 0x11, 0x18, 0x1e, 0x21, 0x23, 0x21, 0x1a, 0x18, + 0x13, 0x12, 0x14, 0x0a, 0xff, 0xfb, 0xfb, 0xf8, 0xef, 0xee, 0xf2, 0xf6, + 0xfc, 0x00, 0xfb, 0xf2, 0xec, 0xea, 0xe8, 0xe9, 0xf0, 0xf7, 0xfc, 0x04, + 0x0d, 0x13, 0x10, 0x09, 0x03, 0xff, 0xfe, 0x03, 0x08, 0x05, 0x04, 0x05, + 0x0a, 0x15, 0x16, 0x0e, 0x08, 0x07, 0x08, 0x07, 0x0a, 0x0e, 0x10, 0x0c, + 0x06, 0x02, 0x00, 0x00, 0x01, 0x04, 0x07, 0x09, 0x08, 0x0b, 0x0c, 0x0a, + 0x07, 0x01, 0xf8, 0xee, 0xef, 0xf7, 0xff, 0x03, 0xfd, 0xf7, 0xf0, 0xf0, + 0xf6, 0xfe, 0xfc, 0xf8, 0xf8, 0xf6, 0xf3, 0xf3, 0xf9, 0xff, 0x05, 0x09, + 0x0f, 0x11, 0x13, 0x18, 0x1d, 0x20, 0x21, 0x1c, 0x16, 0x12, 0x0f, 0x0f, + 0x0d, 0x09, 0x01, 0xfd, 0xfe, 0x01, 0x02, 0x02, 0xff, 0xf9, 0xf4, 0xec, + 0xea, 0xed, 0xee, 0xf1, 0xf4, 0xf6, 0xf7, 0xf9, 0xfb, 0x02, 0x05, 0x09, + 0x09, 0x03, 0xfd, 0xfc, 0xff, 0x06, 0x0e, 0x14, 0x19, 0x1b, 0x1d, 0x20, + 0x1c, 0x14, 0x0a, 0x09, 0x09, 0x02, 0xfd, 0xfb, 0xfa, 0xf8, 0xfb, 0x00, + 0x06, 0x06, 0x02, 0x00, 0xfd, 0xfa, 0xf7, 0xf1, 0xf2, 0xf1, 0xf0, 0xf3, + 0xf7, 0xfc, 0x00, 0x04, 0x06, 0x04, 0x06, 0x0a, 0x0d, 0x11, 0x0f, 0x0a, + 0x00, 0xfc, 0x02, 0x0d, 0x19, 0x20, 0x20, 0x17, 0x0e, 0x0c, 0x0f, 0x16, + 0x18, 0x10, 0x08, 0xff, 0xf5, 0xef, 0xe9, 0xec, 0xed, 0xe9, 0xe8, 0xeb, + 0xf2, 0xfa, 0x00, 0x02, 0xfa, 0xf2, 0xf3, 0xfa, 0x01, 0x09, 0x11, 0x14, + 0x11, 0x08, 0x07, 0x0a, 0x0f, 0x12, 0x0c, 0x00, 0xfd, 0xff, 0x07, 0x0f, + 0x13, 0x19, 0x14, 0x0b, 0x04, 0xff, 0x01, 0x09, 0x0c, 0x0a, 0x05, 0xff, + 0xf8, 0xf5, 0xf6, 0xf7, 0xf9, 0xff, 0x06, 0x0d, 0x13, 0x17, 0x16, 0x0c, + 0xfb, 0xe8, 0xe0, 0xe5, 0xec, 0xea, 0xed, 0xf7, 0xfa, 0x00, 0x03, 0x04, + 0x07, 0x09, 0x03, 0xf9, 0xf2, 0xf3, 0xf8, 0x02, 0x0a, 0x0c, 0x0f, 0x1a, + 0x22, 0x20, 0x21, 0x22, 0x25, 0x25, 0x23, 0x21, 0x19, 0x0f, 0x04, 0xfa, + 0xf4, 0xf6, 0xf9, 0xff, 0xfe, 0xf8, 0xf2, 0xf3, 0xf0, 0xeb, 0xe8, 0xe8, + 0xe9, 0xee, 0xee, 0xed, 0xee, 0xf2, 0xf2, 0xf2, 0xf3, 0xf5, 0xfb, 0x05, + 0x07, 0x07, 0x08, 0x0d, 0x12, 0x19, 0x27, 0x2f, 0x2c, 0x29, 0x24, 0x1b, + 0x13, 0x13, 0x11, 0x0b, 0x08, 0xfa, 0xef, 0xf4, 0xfb, 0xfc, 0x02, 0x0a, + 0x08, 0x02, 0xfd, 0xf9, 0xf7, 0xf5, 0xf4, 0xed, 0xe5, 0xe5, 0xec, 0xf5, + 0xfb, 0xfe, 0xfd, 0xfb, 0xfe, 0x08, 0x16, 0x19, 0x10, 0x06, 0xfd, 0xf1, + 0xef, 0xfa, 0x04, 0x0b, 0x0c, 0x10, 0x14, 0x1b, 0x20, 0x23, 0x25, 0x20, + 0x17, 0x0d, 0xfd, 0xf0, 0xeb, 0xee, 0xf1, 0xf1, 0xf3, 0xf5, 0xfa, 0x00, + 0x04, 0x07, 0x03, 0xfd, 0x00, 0x02, 0x03, 0x05, 0x08, 0x06, 0x06, 0x04, + 0x00, 0x02, 0x0a, 0x0b, 0x02, 0xfe, 0xff, 0xfc, 0xfa, 0x02, 0x09, 0x10, + 0x12, 0x0e, 0x06, 0xfd, 0xfb, 0xf9, 0xf8, 0xf9, 0xfa, 0xfb, 0xfe, 0xfd, + 0xfb, 0xff, 0x01, 0x05, 0x14, 0x21, 0x1e, 0x19, 0x1c, 0x18, 0x0b, 0x00, + 0xfa, 0xf7, 0xed, 0xe3, 0xe9, 0xf5, 0xfc, 0x02, 0x07, 0x07, 0x07, 0x07, + 0x04, 0xf9, 0xee, 0xec, 0xf0, 0xf3, 0xfb, 0x07, 0x0c, 0x12, 0x1f, 0x22, + 0x1e, 0x1c, 0x1c, 0x21, 0x29, 0x2b, 0x20, 0x11, 0x01, 0xf3, 0xe6, 0xe1, + 0xe6, 0xe9, 0xe8, 0xe9, 0xf2, 0xf9, 0xfc, 0xff, 0x01, 0xff, 0xfb, 0xf5, + 0xef, 0xf0, 0xf0, 0xf2, 0xf5, 0xfa, 0xfd, 0x03, 0x07, 0x0a, 0x0e, 0x11, + 0x10, 0x10, 0x14, 0x21, 0x2d, 0x2b, 0x25, 0x25, 0x27, 0x1e, 0x12, 0x0e, + 0x0a, 0xff, 0xf9, 0xfb, 0xfc, 0xf6, 0xed, 0xee, 0xf2, 0xf9, 0x01, 0xfe, + 0xf9, 0xf3, 0xec, 0xe4, 0xe4, 0xe9, 0xe8, 0xe3, 0xe6, 0xed, 0xf7, 0xfd, + 0x02, 0x08, 0x15, 0x21, 0x22, 0x1b, 0x14, 0x10, 0x0d, 0x04, 0x00, 0x02, + 0xfe, 0xfe, 0x0b, 0x19, 0x21, 0x25, 0x28, 0x27, 0x25, 0x1d, 0x15, 0x09, + 0xff, 0xf2, 0xe7, 0xe5, 0xe8, 0xea, 0xec, 0xf2, 0xfd, 0x00, 0xff, 0xfd, + 0xf9, 0xfd, 0x08, 0x0c, 0x06, 0xff, 0xf9, 0xf9, 0xf7, 0xf3, 0xf0, 0xed, + 0xef, 0xf4, 0xfc, 0x00, 0x04, 0x0a, 0x0b, 0x0d, 0x15, 0x1a, 0x16, 0x11, + 0x0d, 0x09, 0x0a, 0x0c, 0x0b, 0x04, 0x02, 0x04, 0x08, 0x09, 0x0b, 0x07, + 0x04, 0x0f, 0x18, 0x17, 0x14, 0x15, 0x16, 0x14, 0x0d, 0x00, 0xf6, 0xec, + 0xe4, 0xe8, 0xf3, 0xf6, 0xf1, 0xef, 0xee, 0xf4, 0xff, 0xfe, 0xf7, 0xed, + 0xe4, 0xe1, 0xe3, 0xe5, 0xf0, 0xf8, 0xff, 0x0a, 0x14, 0x1d, 0x25, 0x2c, + 0x38, 0x40, 0x39, 0x2e, 0x26, 0x1c, 0x12, 0x0d, 0x04, 0xf4, 0xe3, 0xdd, + 0xe5, 0xf2, 0x01, 0x07, 0x01, 0xfe, 0x00, 0x01, 0xfd, 0xf7, 0xf1, 0xeb, + 0xe7, 0xe9, 0xee, 0xf2, 0xf8, 0xff, 0x07, 0x0c, 0x08, 0x07, 0x08, 0x0b, + 0x16, 0x1e, 0x22, 0x21, 0x1b, 0x19, 0x19, 0x13, 0x0c, 0xfb, 0xf0, 0xef, + 0xf7, 0xfa, 0xfe, 0xfd, 0xfd, 0xfd, 0xfe, 0x01, 0x05, 0x01, 0xfc, 0xf9, + 0xfa, 0xfa, 0xf5, 0xf4, 0xf3, 0xf2, 0xf8, 0x00, 0x07, 0x09, 0x0a, 0x0f, + 0x15, 0x15, 0x17, 0x14, 0x11, 0x11, 0x10, 0x0a, 0xfb, 0xf0, 0xf4, 0x00, + 0x08, 0x12, 0x1a, 0x1b, 0x19, 0x17, 0x19, 0x17, 0x09, 0xfb, 0xef, 0xe7, + 0xe3, 0xe5, 0xe5, 0xe4, 0xe3, 0xe8, 0xee, 0xf4, 0xfb, 0x04, 0x0e, 0x19, + 0x1c, 0x16, 0x0f, 0x10, 0x12, 0x0e, 0x06, 0xfa, 0xec, 0xe9, 0xf3, 0xfe, + 0x09, 0x0f, 0x10, 0x0d, 0x08, 0x0b, 0x12, 0x14, 0x10, 0x0d, 0x08, 0x05, + 0x07, 0x07, 0x06, 0x06, 0x05, 0x05, 0x04, 0x01, 0x01, 0x07, 0x0f, 0x0e, + 0x08, 0x01, 0x05, 0x0c, 0x0a, 0x04, 0xfc, 0xef, 0xe2, 0xde, 0xe1, 0xe9, + 0xf5, 0xff, 0xff, 0xfd, 0xfb, 0xfc, 0xfd, 0xfd, 0xf8, 0xf5, 0xf4, 0xf8, + 0xf9, 0xf7, 0xf8, 0xff, 0x0a, 0x17, 0x1e, 0x23, 0x30, 0x3c, 0x41, 0x39, + 0x2e, 0x29, 0x28, 0x1d, 0x11, 0x0a, 0x02, 0xf4, 0xe9, 0xe7, 0xe9, 0xeb, + 0xee, 0xf0, 0xed, 0xf0, 0xf4, 0xf3, 0xee, 0xe7, 0xe2, 0xdf, 0xe4, 0xe8, + 0xe8, 0xe6, 0xec, 0xf4, 0xfb, 0x02, 0x04, 0x0c, 0x1b, 0x23, 0x20, 0x23, + 0x2b, 0x2f, 0x30, 0x2d, 0x27, 0x18, 0x09, 0xfd, 0xfa, 0x00, 0x08, 0x0a, + 0x07, 0x04, 0x03, 0x01, 0x00, 0x00, 0xfc, 0xf6, 0xf5, 0xf6, 0xf9, 0xfb, + 0xf7, 0xf6, 0xf7, 0xf0, 0xf1, 0xfc, 0x02, 0x0a, 0x13, 0x10, 0x04, 0xfe, + 0xfe, 0xfd, 0xfd, 0x02, 0xfe, 0xf4, 0xee, 0xec, 0xf0, 0xfa, 0x06, 0x0e, + 0x16, 0x1d, 0x20, 0x1d, 0x1e, 0x1b, 0x12, 0x09, 0x00, 0xf6, 0xf5, 0xfa, + 0xf9, 0xf8, 0xfa, 0xfb, 0xfe, 0xfc, 0xfd, 0x08, 0x12, 0x13, 0x14, 0x13, + 0x12, 0x13, 0x11, 0x08, 0xfe, 0xf6, 0xf5, 0xf6, 0xf4, 0xfa, 0xfc, 0xfe, + 0x02, 0x06, 0xfe, 0xf7, 0xfc, 0xff, 0xfd, 0xfe, 0xff, 0x02, 0x01, 0xff, + 0xf6, 0xf3, 0xfa, 0x07, 0x0f, 0x0d, 0x0e, 0x15, 0x15, 0x13, 0x14, 0x18, + 0x1e, 0x1c, 0x0f, 0x02, 0xf9, 0xf6, 0xf5, 0xf5, 0xf2, 0xf2, 0xfd, 0x03, + 0x06, 0x06, 0x06, 0x01, 0xf8, 0xed, 0xe6, 0xeb, 0xef, 0xfa, 0x01, 0x00, + 0xfe, 0x01, 0x05, 0x09, 0x12, 0x1e, 0x2f, 0x32, 0x2a, 0x21, 0x1d, 0x20, + 0x1b, 0x0f, 0xfb, 0xf0, 0xf1, 0xf1, 0xee, 0xef, 0xf4, 0xf4, 0xf3, 0xe9, + 0xe6, 0xec, 0xf0, 0xf6, 0xfa, 0xf8, 0xf6, 0xf5, 0xf6, 0xf3, 0xf5, 0xf8, + 0x03, 0x05, 0x03, 0x08, 0x13, 0x19, 0x1e, 0x23, 0x1e, 0x1d, 0x27, 0x2e, + 0x2b, 0x24, 0x1c, 0x13, 0x08, 0x02, 0xfb, 0xf9, 0xfb, 0x00, 0x03, 0xfd, + 0xf8, 0xf4, 0xee, 0xe5, 0xe6, 0xeb, 0xf2, 0xef, 0xea, 0xec, 0xed, 0xf0, + 0xf0, 0xf1, 0xf7, 0x05, 0x0d, 0x0a, 0x11, 0x14, 0x16, 0x17, 0x14, 0x0c, + 0x02, 0xfb, 0xf5, 0xfa, 0x04, 0x09, 0x07, 0x07, 0x0b, 0x10, 0x14, 0x1f, + 0x25, 0x1f, 0x11, 0x0d, 0x0d, 0x0d, 0x07, 0xfd, 0xfb, 0xfd, 0xfe, 0xfc, + 0xf8, 0xfa, 0x01, 0x02, 0xfa, 0xf7, 0xfa, 0xfb, 0xfb, 0x01, 0x08, 0x01, + 0xfa, 0xf5, 0xed, 0xea, 0xf3, 0xff, 0x06, 0x03, 0xfc, 0xfa, 0xfc, 0x00, + 0xfd, 0xfb, 0x01, 0x06, 0x0a, 0x0e, 0x0e, 0x0f, 0x0d, 0x06, 0x03, 0x06, + 0x05, 0x0c, 0x13, 0x16, 0x1a, 0x1a, 0x18, 0x17, 0x15, 0x16, 0x16, 0x16, + 0x12, 0x05, 0xfa, 0xfa, 0xfd, 0xfa, 0xed, 0xea, 0xf2, 0xf8, 0xf7, 0xf3, + 0xf0, 0xed, 0xea, 0xe3, 0xe0, 0xe2, 0xe1, 0xe7, 0xec, 0xf5, 0x03, 0x09, + 0x0e, 0x15, 0x1b, 0x1d, 0x21, 0x27, 0x2b, 0x2f, 0x2d, 0x2a, 0x24, 0x16, + 0x04, 0xfd, 0x02, 0x04, 0x06, 0x04, 0xfd, 0xfb, 0xfd, 0xf7, 0xf0, 0xed, + 0xeb, 0xe9, 0xeb, 0xf0, 0xfa, 0xfe, 0xfb, 0xfa, 0xf6, 0xf9, 0x03, 0x08, + 0x0b, 0x10, 0x0b, 0x08, 0x0a, 0x09, 0x0d, 0x16, 0x16, 0x12, 0x14, 0x10, + 0x0b, 0x08, 0x02, 0x00, 0x06, 0x05, 0x00, 0xfb, 0xfa, 0xf4, 0xf6, 0xf8, + 0xf3, 0xf4, 0xf8, 0xfb, 0x00, 0x02, 0x01, 0x02, 0xfd, 0xff, 0x00, 0xfe, + 0x02, 0x0f, 0x14, 0x12, 0x0e, 0x11, 0x17, 0x16, 0x0c, 0x0a, 0x05, 0x00, + 0xfb, 0xfc, 0xff, 0x02, 0x08, 0x07, 0x02, 0x02, 0x02, 0x05, 0x09, 0x05, + 0x01, 0x04, 0x06, 0x00, 0xfa, 0xf1, 0xf4, 0xfb, 0xff, 0x02, 0x05, 0x08, + 0x07, 0x02, 0xfe, 0xfa, 0xf7, 0xfe, 0x04, 0x02, 0xff, 0x01, 0x02, 0x00, + 0xfe, 0x00, 0x05, 0x09, 0x0c, 0x0b, 0x0a, 0x0b, 0x08, 0x00, 0xf6, 0xf5, + 0x00, 0x0a, 0x0f, 0x10, 0x13, 0x11, 0x0c, 0x06, 0x04, 0x05, 0x0b, 0x0c, + 0x07, 0x03, 0xff, 0xfe, 0x06, 0x0e, 0x08, 0x02, 0x02, 0x04, 0xfe, 0xfb, + 0x03, 0x08, 0x06, 0xfe, 0xf4, 0xee, 0xf2, 0xf6, 0xf1, 0xed, 0xed, 0xef, + 0xf1, 0xf1, 0xf3, 0xf4, 0xf6, 0xfb, 0xfd, 0x00, 0x04, 0x10, 0x18, 0x1c, + 0x23, 0x25, 0x22, 0x21, 0x20, 0x21, 0x27, 0x2d, 0x28, 0x17, 0x06, 0x08, + 0x0e, 0x0a, 0x04, 0x04, 0xfe, 0xef, 0xe2, 0xe0, 0xe2, 0xe2, 0xe3, 0xe3, + 0xe3, 0xe0, 0xe0, 0xe6, 0xee, 0xf6, 0xfa, 0xfe, 0x0c, 0x13, 0x0d, 0x0b, + 0x14, 0x18, 0x12, 0x07, 0xfe, 0x09, 0x1a, 0x1f, 0x1b, 0x18, 0x17, 0x12, + 0x0a, 0x09, 0x0c, 0x0e, 0x0b, 0x07, 0x00, 0xfa, 0xf2, 0xf2, 0xf6, 0xfd, + 0x02, 0x01, 0x05, 0x06, 0x04, 0x01, 0x05, 0x0f, 0x11, 0xfe, 0xf2, 0xfa, + 0x00, 0x02, 0x00, 0xfd, 0xfc, 0xfa, 0xfd, 0xfa, 0xf9, 0xfe, 0x04, 0x07, + 0x07, 0x02, 0xff, 0x03, 0x04, 0x02, 0xff, 0x00, 0xff, 0xfc, 0xfe, 0x06, + 0x09, 0x0c, 0x0a, 0x03, 0xff, 0x03, 0x0f, 0x18, 0x18, 0x13, 0x0d, 0x07, + 0x05, 0x00, 0xfd, 0xfd, 0x02, 0x0b, 0x0a, 0x02, 0xfe, 0x00, 0x00, 0x02, + 0x04, 0x05, 0x05, 0x01, 0xf7, 0xf3, 0xf8, 0xff, 0xfb, 0xf3, 0xf5, 0xfa, + 0xff, 0x06, 0x0b, 0x0a, 0x02, 0x03, 0x0a, 0x0f, 0x0f, 0x0c, 0x0b, 0x09, + 0x04, 0xfc, 0xf3, 0xf5, 0xff, 0x06, 0x0b, 0x0d, 0x0e, 0x0d, 0x0c, 0x0e, + 0x0f, 0x10, 0x0d, 0x05, 0xf9, 0xf2, 0xf4, 0xf7, 0xf5, 0xf4, 0xf4, 0xf7, + 0xf9, 0xfd, 0x00, 0x01, 0x08, 0x0e, 0x0d, 0x05, 0x02, 0x07, 0x0e, 0x0d, + 0x0b, 0x07, 0x07, 0x0d, 0x14, 0x17, 0x17, 0x14, 0x10, 0x0f, 0x0e, 0x0a, + 0x08, 0x0b, 0x07, 0xf9, 0xea, 0xe2, 0xe1, 0xe1, 0xe1, 0xe6, 0xed, 0xef, + 0xf0, 0xef, 0xf0, 0xf8, 0x03, 0x08, 0x10, 0x19, 0x1b, 0x17, 0x17, 0x15, + 0x0f, 0x0f, 0x14, 0x17, 0x1a, 0x1d, 0x21, 0x22, 0x1e, 0x0f, 0x06, 0x01, + 0x01, 0xff, 0xfc, 0xf8, 0xef, 0xe7, 0xe8, 0xe9, 0xe9, 0xf0, 0xf6, 0xf6, + 0xfc, 0x02, 0x03, 0x06, 0x0c, 0x0d, 0x0e, 0x13, 0x11, 0x0b, 0x00, 0xf5, + 0xf2, 0xf6, 0xf6, 0xf1, 0xf5, 0xfd, 0x03, 0x09, 0x0d, 0x0f, 0x12, 0x0f, + 0x0b, 0x0c, 0x0b, 0x09, 0x03, 0xfc, 0xff, 0x05, 0x07, 0x0c, 0x13, 0x10, + 0x0f, 0x0e, 0x0d, 0x12, 0x11, 0x0b, 0x0b, 0x0f, 0x08, 0xf9, 0xf1, 0xea, + 0xe8, 0xf1, 0xfb, 0x00, 0x04, 0x04, 0x03, 0xfe, 0xfb, 0xfe, 0xff, 0xfc, + 0xfe, 0x03, 0x00, 0xfd, 0xfa, 0xf7, 0xf8, 0xf9, 0xf7, 0xfc, 0x02, 0x07, + 0x10, 0x14, 0x11, 0x0b, 0x0d, 0x11, 0x17, 0x1b, 0x15, 0x0b, 0x01, 0xf9, + 0xfc, 0x07, 0x0c, 0x0a, 0x0f, 0x13, 0x12, 0x10, 0x0c, 0x08, 0x01, 0xfc, + 0xff, 0x01, 0xfd, 0xf6, 0xec, 0xe5, 0xe8, 0xeb, 0xec, 0xec, 0xf4, 0xf9, + 0xff, 0x06, 0x0b, 0x0d, 0x10, 0x0e, 0x11, 0x15, 0x0f, 0x05, 0xf9, 0xf5, + 0xfd, 0x05, 0x04, 0x05, 0x12, 0x1a, 0x17, 0x16, 0x17, 0x19, 0x18, 0x12, + 0x0b, 0x05, 0xfc, 0xf0, 0xea, 0xe9, 0xed, 0xf0, 0xf8, 0xff, 0x02, 0xff, + 0x01, 0x02, 0xfd, 0xfc, 0xfd, 0x02, 0x07, 0x08, 0x03, 0xfc, 0xfb, 0x02, + 0x0f, 0x13, 0x14, 0x1e, 0x28, 0x20, 0x12, 0x0c, 0x08, 0x01, 0xff, 0xfe, + 0xfe, 0xfe, 0xfa, 0xf1, 0xe8, 0xe3, 0xe1, 0xe5, 0xeb, 0xf7, 0xfd, 0x05, + 0x0b, 0x0e, 0x11, 0x13, 0x17, 0x1e, 0x1b, 0x11, 0x07, 0x01, 0x02, 0x02, + 0x02, 0x00, 0xff, 0x01, 0x08, 0x0b, 0x0a, 0x09, 0x08, 0x04, 0x01, 0x01, + 0x04, 0x04, 0xfb, 0xf2, 0xed, 0xf0, 0xf6, 0x01, 0x0d, 0x0f, 0x14, 0x16, + 0x0f, 0x0c, 0x0f, 0x15, 0x1b, 0x15, 0x08, 0xfb, 0xf0, 0xe7, 0xe7, 0xea, + 0xea, 0xea, 0xf4, 0xfe, 0x06, 0x09, 0x09, 0x0c, 0x09, 0x04, 0xff, 0x01, + 0x03, 0x02, 0x06, 0x04, 0x04, 0x08, 0x07, 0x0e, 0x17, 0x1f, 0x23, 0x16, + 0x05, 0x03, 0x03, 0x03, 0x07, 0x08, 0xff, 0xf4, 0xf2, 0xf0, 0xf5, 0xfc, + 0x02, 0x07, 0x0d, 0x0e, 0x0e, 0x0d, 0x06, 0x05, 0x04, 0x01, 0x05, 0x07, + 0xfe, 0xfa, 0xfb, 0xf4, 0xeb, 0xe1, 0xdb, 0xe3, 0xee, 0xfa, 0x05, 0x0a, + 0x0d, 0x11, 0x1b, 0x1f, 0x1d, 0x15, 0x10, 0x0b, 0x04, 0x00, 0x07, 0x0d, + 0x08, 0x0a, 0x11, 0x18, 0x1c, 0x15, 0x07, 0x07, 0x06, 0x05, 0x06, 0xfd, + 0xf3, 0xf3, 0xee, 0xe3, 0xe3, 0xed, 0xf2, 0xff, 0x0a, 0x09, 0x02, 0x03, + 0x05, 0x04, 0x05, 0x05, 0x02, 0xfd, 0xf8, 0xf8, 0xf9, 0x02, 0x06, 0xfe, + 0xfe, 0x0c, 0x17, 0x21, 0x23, 0x17, 0x0f, 0x0f, 0x08, 0x01, 0x01, 0x02, + 0x00, 0xff, 0xfd, 0xf3, 0xf3, 0xf7, 0xfe, 0x08, 0x0a, 0x06, 0x06, 0x03, + 0xff, 0x01, 0x0c, 0x10, 0x08, 0xfd, 0xfa, 0xfd, 0x03, 0x09, 0x04, 0x00, + 0x01, 0x03, 0x03, 0x05, 0x09, 0x07, 0x05, 0x04, 0x05, 0x05, 0x09, 0x09, + 0x02, 0xfb, 0xee, 0xe3, 0xe4, 0xe8, 0xf4, 0x01, 0x0e, 0x18, 0x18, 0x12, + 0x14, 0x1e, 0x1f, 0x12, 0x07, 0x02, 0x02, 0x02, 0x01, 0xf8, 0xf7, 0xfe, + 0x00, 0xfd, 0x00, 0x06, 0x08, 0x05, 0x02, 0xfc, 0xf6, 0xf6, 0xf9, 0xf6, + 0xf6, 0xf9, 0xff, 0x06, 0x0a, 0x0f, 0x1e, 0x2a, 0x27, 0x1b, 0x0e, 0x09, + 0x0c, 0x0d, 0x04, 0xf9, 0xf8, 0xf9, 0xf4, 0xf1, 0xec, 0xe7, 0xeb, 0xf3, + 0xf4, 0xfa, 0x03, 0x10, 0x15, 0x10, 0x08, 0x03, 0x09, 0x0e, 0x07, 0x03, + 0x09, 0x0c, 0x05, 0xfd, 0xfc, 0x03, 0x05, 0x03, 0xfe, 0xfa, 0x01, 0x06, + 0x0a, 0x0a, 0x09, 0x07, 0x0a, 0x09, 0x03, 0xfe, 0xfd, 0x01, 0x08, 0x0a, + 0x0a, 0x0c, 0x16, 0x19, 0x0f, 0x04, 0x05, 0x0a, 0x08, 0xfe, 0xf7, 0xf8, + 0xf5, 0xea, 0xdb, 0xd7, 0xe4, 0xf2, 0xf6, 0xf9, 0x01, 0x0a, 0x0f, 0x14, + 0x15, 0x0a, 0x02, 0x02, 0x07, 0x07, 0x07, 0x08, 0x0c, 0x10, 0x13, 0x11, + 0x14, 0x1c, 0x1b, 0x14, 0x0a, 0x07, 0x04, 0xfe, 0xf8, 0xf4, 0xf7, 0xf7, + 0xf7, 0xf4, 0xf5, 0xfc, 0x06, 0x0a, 0x0b, 0x07, 0x07, 0x06, 0x06, 0x08, + 0x04, 0x02, 0x02, 0x05, 0xff, 0xf6, 0xf7, 0xf5, 0xf1, 0xf3, 0xfa, 0xfb, + 0xfc, 0x00, 0x05, 0x09, 0x0d, 0x0e, 0x0b, 0x0a, 0x0f, 0x14, 0x12, 0x0f, + 0x07, 0xfe, 0xff, 0x01, 0x03, 0x03, 0x07, 0x0b, 0x0b, 0x0b, 0x09, 0x06, + 0x05, 0x05, 0x05, 0x01, 0x00, 0x03, 0x03, 0xfc, 0xfb, 0xfd, 0xff, 0x01, + 0x01, 0x01, 0x04, 0x03, 0x02, 0x03, 0x00, 0xff, 0xfe, 0xf7, 0xf2, 0xf4, + 0xf6, 0xf5, 0xf7, 0xfd, 0x05, 0x0c, 0x17, 0x1b, 0x19, 0x1b, 0x19, 0x10, + 0x08, 0x06, 0x04, 0x03, 0x03, 0x02, 0xf8, 0xf5, 0xfc, 0xfe, 0xfa, 0xfb, + 0xfc, 0x02, 0x06, 0x05, 0x03, 0x01, 0x04, 0x02, 0xfd, 0xfc, 0xff, 0x04, + 0x09, 0x0a, 0x09, 0x0e, 0x14, 0x18, 0x0f, 0x04, 0xff, 0x01, 0x01, 0x00, + 0x03, 0x0a, 0x0a, 0x07, 0xfe, 0xf5, 0xec, 0xf0, 0xf5, 0xf3, 0xf3, 0xfe, + 0x07, 0x0e, 0x13, 0x10, 0x0a, 0x09, 0x0a, 0x06, 0x04, 0x0a, 0x0b, 0x0a, + 0x09, 0xff, 0xf4, 0xf1, 0xf7, 0xfc, 0xfe, 0x00, 0x05, 0x04, 0x00, 0x02, + 0x09, 0x0a, 0x07, 0x00, 0xff, 0x04, 0x09, 0x0a, 0x0e, 0x12, 0x19, 0x1a, + 0x17, 0x14, 0x0e, 0x0d, 0x0c, 0x08, 0x02, 0xf5, 0xef, 0xed, 0xed, 0xef, + 0xed, 0xe9, 0xea, 0xef, 0xf8, 0xfe, 0x05, 0x0e, 0x11, 0x06, 0x06, 0x0d, + 0x0e, 0x0e, 0x0c, 0x05, 0x01, 0xff, 0xfe, 0xff, 0x01, 0x07, 0x09, 0x08, + 0x05, 0x03, 0x01, 0x02, 0x04, 0x05, 0x04, 0x08, 0x0b, 0x0c, 0x0f, 0x11, + 0x0c, 0x07, 0x08, 0x09, 0x0f, 0x11, 0x0e, 0x0c, 0x02, 0xfa, 0xfc, 0x02, + 0x02, 0xfd, 0xf7, 0xf4, 0xef, 0xef, 0xf2, 0xf1, 0xea, 0xe8, 0xef, 0xfa, + 0x02, 0x09, 0x0b, 0x08, 0x06, 0x09, 0x0f, 0x14, 0x0e, 0x09, 0x11, 0x11, + 0x04, 0xff, 0x02, 0x07, 0x13, 0x16, 0x14, 0x12, 0x0e, 0x0a, 0x0d, 0x0f, + 0x0b, 0x03, 0xfd, 0xfb, 0xf7, 0xf9, 0xff, 0x01, 0xfe, 0xff, 0x03, 0x00, + 0x00, 0x04, 0x04, 0x04, 0x03, 0xff, 0xf9, 0xf6, 0xf2, 0xf4, 0xfa, 0xf7, + 0xee, 0xf0, 0x00, 0x0d, 0x11, 0x14, 0x17, 0x0c, 0xff, 0x00, 0x0a, 0x13, + 0x17, 0x15, 0x0c, 0x03, 0x01, 0xff, 0xff, 0xfd, 0xfb, 0x01, 0x06, 0x05, + 0x08, 0x09, 0x02, 0xfb, 0xff, 0xff, 0xff, 0x04, 0x10, 0x14, 0x14, 0x10, + 0x09, 0x03, 0x00, 0xfd, 0xfd, 0x04, 0x04, 0xf8, 0xf6, 0xfc, 0x06, 0x06, + 0x06, 0x00, 0xf8, 0xf4, 0xf2, 0xf5, 0xf7, 0xfa, 0xfb, 0x00, 0x0d, 0x10, + 0x13, 0x18, 0x15, 0x10, 0x11, 0x12, 0x0e, 0x09, 0x03, 0x00, 0xfa, 0xf3, + 0xef, 0xf2, 0xf5, 0xfa, 0x03, 0x08, 0x04, 0x00, 0x06, 0x0f, 0x0f, 0x0b, + 0x08, 0x06, 0xff, 0xf8, 0xfe, 0x01, 0x04, 0x0d, 0x13, 0x19, 0x16, 0x0f, + 0x0b, 0x02, 0xf8, 0xf6, 0xfc, 0x01, 0x01, 0x00, 0x01, 0x01, 0xfd, 0xf3, + 0xf4, 0xfa, 0x00, 0x0a, 0x0f, 0x0d, 0x06, 0x03, 0x02, 0x01, 0x08, 0x07, + 0x06, 0x07, 0x00, 0xfa, 0xfd, 0xfd, 0xfb, 0xf8, 0xf3, 0xf6, 0xf8, 0xfd, + 0x04, 0x01, 0xfe, 0x04, 0x0a, 0x11, 0x1b, 0x21, 0x21, 0x19, 0x0f, 0x0b, + 0x09, 0x0c, 0x0d, 0x10, 0x11, 0x09, 0x07, 0x0a, 0x0d, 0x0c, 0x08, 0x02, + 0xfb, 0xef, 0xe1, 0xdb, 0xe0, 0xe6, 0xe5, 0xe9, 0xf4, 0xfa, 0xfb, 0x05, + 0x0a, 0x09, 0x0d, 0x10, 0x0f, 0x11, 0x11, 0x0b, 0xfe, 0xf7, 0xf5, 0xf6, + 0x00, 0x0b, 0x16, 0x1d, 0x1c, 0x12, 0x0c, 0x07, 0x02, 0x04, 0x0c, 0x12, + 0x10, 0x06, 0x02, 0x06, 0x05, 0x03, 0x05, 0x0e, 0x10, 0x08, 0x02, 0x02, + 0xfe, 0xf3, 0xef, 0xec, 0xf0, 0xfd, 0x03, 0x00, 0xfe, 0xfe, 0xf7, 0xf4, + 0xf8, 0xfa, 0xfa, 0xfc, 0xfd, 0xff, 0x02, 0x05, 0x0c, 0x10, 0x13, 0x13, + 0x0e, 0x08, 0x02, 0xfe, 0xf9, 0xfc, 0x03, 0x05, 0x05, 0x00, 0x04, 0x11, + 0x13, 0x10, 0x12, 0x17, 0x1f, 0x24, 0x1b, 0x0d, 0x03, 0xfb, 0xf6, 0xf6, + 0xf9, 0xff, 0x04, 0xff, 0xfc, 0xfe, 0xff, 0x04, 0x05, 0x02, 0xff, 0xfa, + 0xee, 0xe2, 0xde, 0xda, 0xe5, 0xf9, 0x03, 0x08, 0x0f, 0x14, 0x18, 0x16, + 0x0d, 0x05, 0x06, 0x0f, 0x18, 0x13, 0x0b, 0x08, 0x05, 0xfe, 0xfc, 0xff, + 0x08, 0x14, 0x13, 0x0c, 0x0a, 0x07, 0x01, 0xfd, 0xfd, 0xfe, 0x02, 0x0a, + 0x07, 0x00, 0x01, 0x06, 0x06, 0x05, 0x04, 0x01, 0xf9, 0xf4, 0xf7, 0xf5, + 0xf2, 0xf9, 0x01, 0x08, 0x0f, 0x0e, 0x10, 0x0b, 0x03, 0xfc, 0xf7, 0xf8, + 0x02, 0x06, 0x02, 0xfd, 0x06, 0x13, 0x17, 0x19, 0x1c, 0x18, 0x11, 0x03, + 0xf3, 0xe9, 0xe4, 0xe4, 0xe8, 0xf0, 0xf8, 0xfb, 0xfb, 0xfd, 0x05, 0x09, + 0x0b, 0x11, 0x1a, 0x22, 0x21, 0x18, 0x0c, 0x05, 0xfb, 0xf3, 0xf8, 0x0e, + 0x1a, 0x19, 0x18, 0x18, 0x11, 0x08, 0x00, 0xfd, 0xfb, 0xfb, 0xfc, 0xf2, + 0xe6, 0xe9, 0xee, 0xef, 0xf8, 0x00, 0x04, 0x05, 0x07, 0x08, 0x08, 0x03, + 0xff, 0x01, 0x01, 0x01, 0xfe, 0x06, 0x09, 0x06, 0x02, 0xfe, 0x01, 0x08, + 0x09, 0x05, 0x01, 0xfe, 0xff, 0x01, 0x09, 0x12, 0x15, 0x16, 0x16, 0x10, + 0x0e, 0x0c, 0x0b, 0x07, 0x07, 0x07, 0x08, 0x00, 0xf5, 0xf2, 0xf9, 0x04, + 0x0c, 0x13, 0x18, 0x12, 0x0a, 0x01, 0xfa, 0xf0, 0xe3, 0xdf, 0xe7, 0xee, + 0xf4, 0xf8, 0xfa, 0x02, 0x08, 0x10, 0x13, 0x10, 0x0e, 0x07, 0xfa, 0xef, + 0xec, 0xe5, 0xe8, 0xf3, 0x01, 0x10, 0x16, 0x15, 0x19, 0x1a, 0x18, 0x14, + 0x19, 0x20, 0x1d, 0x17, 0x16, 0x0f, 0x0b, 0x07, 0x02, 0x03, 0x0e, 0x13, + 0x0f, 0x0b, 0x07, 0x00, 0xfa, 0xf5, 0xf2, 0xec, 0xe9, 0xe4, 0xe0, 0xe8, + 0xee, 0xf1, 0xf8, 0xfa, 0xfa, 0xf9, 0xf9, 0xf9, 0xf9, 0xf9, 0x00, 0x0c, + 0x17, 0x18, 0x0f, 0x10, 0x18, 0x15, 0x0f, 0x0e, 0x0b, 0x08, 0x0c, 0x0f, + 0x0c, 0x03, 0xff, 0x01, 0x0b, 0x1e, 0x24, 0x22, 0x1d, 0x12, 0x02, 0xfb, + 0xfa, 0xf5, 0xee, 0xef, 0xf5, 0xf6, 0xf6, 0xf2, 0xed, 0xf4, 0x02, 0x0b, + 0x0e, 0x0c, 0x0a, 0x05, 0xfd, 0xf5, 0xf1, 0xe7, 0xe8, 0xf0, 0xfc, 0x0a, + 0x12, 0x15, 0x19, 0x1b, 0x1d, 0x17, 0x0b, 0x03, 0xff, 0xf3, 0xf0, 0xf2, + 0xf6, 0xf9, 0xff, 0x0a, 0x13, 0x0f, 0x0b, 0x0a, 0x09, 0x0a, 0x12, 0x16, + 0x0f, 0x05, 0x04, 0x00, 0x03, 0x0d, 0x0e, 0x09, 0x05, 0x07, 0x08, 0x03, + 0xfd, 0xf6, 0xf3, 0xf3, 0xfc, 0xfe, 0x00, 0xff, 0xf6, 0xf6, 0xfb, 0xfc, + 0xfe, 0x01, 0x00, 0xfd, 0xfc, 0x00, 0xfd, 0xf4, 0xf9, 0x07, 0x16, 0x22, + 0x20, 0x18, 0x12, 0x0d, 0x0a, 0x04, 0xff, 0xf8, 0xf2, 0xf6, 0xfd, 0xfd, + 0xfb, 0xfc, 0x05, 0x15, 0x1b, 0x17, 0x15, 0x0e, 0x03, 0xfc, 0xfc, 0xfa, + 0xf2, 0xf1, 0xfa, 0xfe, 0x06, 0x11, 0x0d, 0x05, 0x09, 0x16, 0x19, 0x14, + 0x08, 0x02, 0xfc, 0xfa, 0xfa, 0xf9, 0xf8, 0xf2, 0xf7, 0x03, 0x07, 0x03, + 0x06, 0x0e, 0x12, 0x0c, 0x04, 0xf9, 0xeb, 0xe1, 0xe0, 0xe2, 0xf1, 0xff, + 0x03, 0x06, 0x09, 0x0a, 0x07, 0x01, 0xfb, 0x00, 0x0b, 0x1a, 0x21, 0x20, + 0x18, 0x14, 0x18, 0x1f, 0x1c, 0x19, 0x14, 0x0d, 0x0b, 0x0b, 0x07, 0xff, + 0xf4, 0xf1, 0xf8, 0xfc, 0x04, 0x0c, 0x06, 0xfa, 0xf0, 0xf1, 0xf4, 0xef, + 0xeb, 0xe9, 0xe3, 0xe4, 0xec, 0xf2, 0xf2, 0xfb, 0x0f, 0x1b, 0x16, 0x0c, + 0x09, 0x09, 0x08, 0x08, 0x09, 0x05, 0xfa, 0xfb, 0x02, 0x05, 0x0c, 0x17, + 0x1d, 0x20, 0x26, 0x27, 0x20, 0x16, 0x0a, 0x00, 0xfb, 0xfb, 0xfd, 0xfc, + 0xfd, 0xff, 0x09, 0x0e, 0x07, 0xfd, 0xf5, 0x01, 0x0f, 0x0b, 0x03, 0xf6, + 0xe9, 0xe7, 0xeb, 0xf0, 0xf9, 0xfe, 0xfa, 0xf7, 0xf8, 0xfb, 0xfe, 0x00, + 0x02, 0x06, 0x05, 0x01, 0x03, 0x03, 0xfb, 0xf8, 0x03, 0x0c, 0x09, 0x0d, + 0x12, 0x12, 0x11, 0x0d, 0x0b, 0xff, 0xfe, 0x11, 0x1d, 0x1b, 0x1d, 0x23, + 0x21, 0x1a, 0x14, 0x10, 0x0b, 0x03, 0xfb, 0xf9, 0xf4, 0xf0, 0xf0, 0xef, + 0xf2, 0xf8, 0xff, 0x00, 0xfe, 0xf9, 0xee, 0xec, 0xee, 0xf1, 0xf3, 0xef, + 0xe7, 0xe9, 0xf3, 0xfe, 0x04, 0x0c, 0x1b, 0x22, 0x20, 0x19, 0x13, 0x0e, + 0x0b, 0x0d, 0x0a, 0x07, 0x0a, 0x05, 0x03, 0x08, 0x12, 0x12, 0x0e, 0x11, + 0x16, 0x19, 0x15, 0x10, 0x08, 0xf7, 0xe5, 0xe6, 0xee, 0xf3, 0xf9, 0x01, + 0x05, 0x03, 0x01, 0xf9, 0xf1, 0xf1, 0xfe, 0x09, 0x07, 0x02, 0x00, 0x01, + 0x02, 0x07, 0x0f, 0x10, 0x09, 0x02, 0x00, 0x03, 0x04, 0x07, 0x09, 0x03, + 0xfb, 0xfb, 0xfd, 0x03, 0x08, 0x08, 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, + 0xff, 0xff, 0xf6, 0xef, 0xf5, 0x02, 0x12, 0x1b, 0x1c, 0x18, 0x16, 0x14, + 0x11, 0x0f, 0x0e, 0x0d, 0x04, 0xfc, 0xf8, 0xfa, 0xfd, 0x02, 0x07, 0x0b, + 0x0e, 0x0c, 0x09, 0x07, 0x00, 0xf3, 0xef, 0xf2, 0xed, 0xee, 0xef, 0xf1, + 0xf4, 0xfe, 0x05, 0x05, 0x03, 0x0a, 0x0f, 0x10, 0x0a, 0x08, 0x03, 0xfb, + 0xf4, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x0a, 0x06, 0x07, 0x07, 0x08, 0x0c, + 0x13, 0x17, 0x0f, 0x09, 0x06, 0x00, 0x04, 0x0a, 0x0d, 0x10, 0x11, 0x0f, + 0x0c, 0x0b, 0x03, 0xfc, 0xfc, 0xfe, 0xfc, 0xfc, 0xff, 0x03, 0x09, 0x0c, + 0x0a, 0x05, 0x00, 0xf8, 0xf0, 0xec, 0xf1, 0xf6, 0xf1, 0xef, 0xf3, 0xf8, + 0xfc, 0xff, 0x03, 0x04, 0xfe, 0xfa, 0xfe, 0x01, 0x02, 0x07, 0x07, 0x02, + 0xfe, 0xff, 0x05, 0x0f, 0x1f, 0x2c, 0x2c, 0x25, 0x22, 0x21, 0x1b, 0x15, + 0x11, 0x0f, 0x07, 0xff, 0xfd, 0x02, 0x05, 0x05, 0x04, 0x01, 0xfe, 0xfc, + 0xfe, 0x01, 0xfb, 0xf4, 0xe7, 0xe0, 0xd9, 0xdc, 0xe6, 0xe9, 0xed, 0xf2, + 0xf8, 0xf8, 0xfc, 0xff, 0xfe, 0x04, 0x0d, 0x0d, 0x0d, 0x0e, 0x11, 0x15, + 0x18, 0x1c, 0x19, 0x12, 0x12, 0x15, 0x16, 0x14, 0x12, 0x10, 0x0f, 0x0b, + 0x05, 0x03, 0x08, 0x08, 0x06, 0x05, 0x06, 0x06, 0x05, 0x01, 0xfc, 0xfa, + 0xf9, 0xf3, 0xec, 0xea, 0xf1, 0xfa, 0xfd, 0xfe, 0x04, 0x05, 0x02, 0x00, + 0x00, 0xfd, 0xf8, 0xf2, 0xf5, 0xf8, 0xf6, 0xf9, 0x00, 0x07, 0x0b, 0x10, + 0x14, 0x12, 0x10, 0x0a, 0x05, 0x04, 0x04, 0x06, 0x03, 0x02, 0x05, 0x08, + 0x07, 0x0e, 0x15, 0x16, 0x1c, 0x1b, 0x16, 0x17, 0x15, 0x0c, 0x04, 0xfd, + 0xf7, 0xf6, 0xf7, 0xfb, 0xfb, 0xfc, 0xfd, 0xfa, 0xf8, 0xf3, 0xf2, 0xfa, + 0x00, 0xff, 0xf6, 0xf1, 0xf7, 0xfe, 0x00, 0x01, 0x01, 0xfd, 0x00, 0x03, + 0x08, 0x08, 0x03, 0x02, 0x06, 0x06, 0x03, 0x0c, 0x13, 0x15, 0x12, 0x16, + 0x13, 0x0b, 0x08, 0x03, 0x03, 0x06, 0x03, 0x02, 0xff, 0x00, 0x04, 0x07, + 0x05, 0x05, 0x04, 0x01, 0x00, 0xff, 0x01, 0x07, 0x06, 0x00, 0xfd, 0xfa, + 0xf8, 0xfa, 0xfe, 0x05, 0x0b, 0x11, 0x15, 0x14, 0x11, 0x09, 0x04, 0x03, + 0xfc, 0xf3, 0xec, 0xee, 0xfa, 0xfe, 0xfe, 0x03, 0x03, 0x03, 0x04, 0x05, + 0x05, 0x07, 0x05, 0xfe, 0xf9, 0xf5, 0xf1, 0xf8, 0xfa, 0xfa, 0xfb, 0x05, + 0x0b, 0x0c, 0x0d, 0x0e, 0x14, 0x1a, 0x1d, 0x1a, 0x12, 0x0e, 0x14, 0x16, + 0x14, 0x11, 0x10, 0x0e, 0x0e, 0x09, 0x05, 0x01, 0xfb, 0xf7, 0xf6, 0xf4, + 0xef, 0xf4, 0xf8, 0xf4, 0xf6, 0xfb, 0xfb, 0xf5, 0xee, 0xe9, 0xef, 0xfa, + 0xfb, 0xf2, 0xf3, 0xfd, 0x06, 0x08, 0x0b, 0x11, 0x0f, 0x0d, 0x0e, 0x08, + 0x06, 0x08, 0x0c, 0x0b, 0x08, 0x05, 0x06, 0x0d, 0x14, 0x14, 0x13, 0x1a, + 0x1d, 0x17, 0x0e, 0x07, 0x09, 0x09, 0x05, 0xfe, 0xf7, 0xf9, 0x02, 0x01, + 0xfc, 0xfb, 0x00, 0x07, 0x07, 0x04, 0x02, 0x02, 0x00, 0xff, 0xf6, 0xe6, + 0xdf, 0xe4, 0xe6, 0xe5, 0xeb, 0xf7, 0xfc, 0xff, 0xfc, 0xfa, 0x03, 0x0d, + 0x14, 0x0c, 0x06, 0x0a, 0x10, 0x0e, 0x10, 0x13, 0x13, 0x14, 0x17, 0x16, + 0x14, 0x17, 0x18, 0x15, 0x12, 0x0d, 0x0a, 0x0c, 0x0f, 0x0d, 0x08, 0x0a, + 0x0c, 0x05, 0xfc, 0xf4, 0xf9, 0xfa, 0xf4, 0xed, 0xe7, 0xea, 0xf1, 0xf2, + 0xf4, 0xf6, 0xf8, 0xf6, 0xf2, 0xf0, 0xf0, 0xf3, 0xf4, 0xf9, 0xfc, 0xf9, + 0xfc, 0x0c, 0x15, 0x17, 0x1d, 0x25, 0x24, 0x22, 0x1d, 0x10, 0x08, 0x08, + 0x0a, 0x04, 0x02, 0x06, 0x08, 0x0c, 0x11, 0x11, 0x0d, 0x0d, 0x0c, 0x0a, + 0x08, 0x08, 0x04, 0xfe, 0xfc, 0xf0, 0xeb, 0xee, 0xef, 0xf2, 0xf5, 0xf6, + 0xf7, 0xfc, 0xfc, 0xfc, 0x01, 0x07, 0x0a, 0x07, 0x06, 0x04, 0x00, 0xfd, + 0xff, 0x00, 0xff, 0x01, 0x06, 0x0a, 0x0a, 0x08, 0x06, 0x06, 0x0a, 0x08, + 0x06, 0x03, 0x01, 0x01, 0x02, 0x07, 0x06, 0x04, 0x01, 0x02, 0x05, 0x0b, + 0x12, 0x10, 0x0b, 0x09, 0x06, 0x06, 0x0d, 0x12, 0x0d, 0x05, 0x00, 0x03, + 0x04, 0x05, 0x00, 0xfc, 0xfd, 0xf8, 0xf6, 0xf8, 0xfa, 0xfc, 0x07, 0x13, + 0x0d, 0x05, 0x01, 0xfa, 0xf2, 0xee, 0xec, 0xec, 0xf2, 0xfb, 0xfc, 0x00, + 0x0f, 0x18, 0x13, 0x11, 0x13, 0x13, 0x15, 0x17, 0x0f, 0x02, 0xfc, 0xf7, + 0xf1, 0xf1, 0xf2, 0xf8, 0x01, 0x09, 0x09, 0x05, 0x05, 0x0d, 0x13, 0x15, + 0x10, 0x09, 0x0d, 0x0e, 0x08, 0x08, 0x0b, 0x0e, 0x0c, 0x07, 0x04, 0x06, + 0x09, 0x04, 0xfc, 0xfe, 0x00, 0xfd, 0xff, 0x00, 0xf7, 0xf0, 0xf1, 0xf3, + 0xef, 0xed, 0xf2, 0xf8, 0xfd, 0x02, 0x01, 0xfd, 0x03, 0x07, 0x06, 0x03, + 0x04, 0x01, 0xfe, 0xfc, 0xfe, 0x03, 0x08, 0x0b, 0x0b, 0x0d, 0x13, 0x18, + 0x1b, 0x17, 0x17, 0x16, 0x1c, 0x24, 0x24, 0x1c, 0x10, 0x08, 0x00, 0x00, + 0xfe, 0xf9, 0xf9, 0xf7, 0xf2, 0xf0, 0xf4, 0xfa, 0xfe, 0x00, 0x02, 0x01, + 0xff, 0xfc, 0xf4, 0xeb, 0xe4, 0xdd, 0xdd, 0xe1, 0xea, 0xf0, 0xfc, 0x0a, + 0x0d, 0x0d, 0x11, 0x11, 0x15, 0x1c, 0x19, 0x10, 0x0c, 0x0a, 0x07, 0x09, + 0x10, 0x14, 0x15, 0x17, 0x19, 0x17, 0x12, 0x0e, 0x0f, 0x10, 0x0c, 0x04, + 0xfa, 0xfb, 0xfc, 0xfc, 0xfe, 0x01, 0xfd, 0xfb, 0xfc, 0xf7, 0xf8, 0xfe, + 0xfe, 0xf8, 0xf6, 0xf6, 0xf8, 0xfe, 0x00, 0xf7, 0xeb, 0xe8, 0xeb, 0xf3, + 0xf9, 0xfe, 0x02, 0x03, 0x08, 0x0d, 0x0e, 0x10, 0x17, 0x1a, 0x1c, 0x18, + 0x10, 0x0e, 0x08, 0xfe, 0xff, 0x01, 0x03, 0x08, 0x08, 0x07, 0x0e, 0x15, + 0x16, 0x18, 0x13, 0x12, 0x16, 0x18, 0x15, 0x07, 0xff, 0xfc, 0xf8, 0xf3, + 0xe9, 0xe5, 0xe4, 0xe0, 0xe8, 0xee, 0xef, 0xfd, 0x04, 0x01, 0x04, 0x03, + 0xff, 0xfc, 0xf7, 0xf1, 0xf6, 0xfd, 0x09, 0x0f, 0x0d, 0x18, 0x23, 0x21, + 0x19, 0x15, 0x10, 0x10, 0x11, 0x0b, 0xfb, 0xf4, 0xf6, 0xf8, 0xfe, 0x01, + 0x00, 0x04, 0x07, 0x07, 0x09, 0x0c, 0x12, 0x10, 0x0a, 0x03, 0xfd, 0xfa, + 0xfe, 0xfd, 0xf8, 0xfe, 0x02, 0x06, 0x04, 0xfd, 0xfa, 0xff, 0x04, 0x02, + 0xfe, 0x00, 0x07, 0x0d, 0x16, 0x12, 0x04, 0xfb, 0xf2, 0xe9, 0xec, 0xf5, + 0xfc, 0xfd, 0xfc, 0xfe, 0x04, 0x0f, 0x1a, 0x1a, 0x12, 0x11, 0x0c, 0x09, + 0x05, 0xfc, 0xfa, 0xfe, 0xff, 0xfb, 0xf5, 0xf6, 0xfb, 0x01, 0x0b, 0x0f, + 0x10, 0x13, 0x15, 0x15, 0x17, 0x14, 0x0f, 0x09, 0x05, 0x05, 0x04, 0x06, + 0x09, 0x04, 0x00, 0x01, 0x03, 0x05, 0x01, 0xfb, 0xff, 0xff, 0xfa, 0xf0, + 0xe3, 0xdc, 0xe3, 0xf0, 0xf8, 0xfb, 0xff, 0x02, 0x09, 0x10, 0x15, 0x18, + 0x15, 0x0d, 0x04, 0x02, 0xfb, 0xf6, 0xf6, 0xf6, 0xf8, 0xff, 0x05, 0x0d, + 0x0d, 0x0d, 0x0f, 0x14, 0x1b, 0x1d, 0x18, 0x14, 0x14, 0x12, 0x15, 0x14, + 0x0c, 0x07, 0x05, 0xff, 0xfd, 0xfc, 0xf7, 0xed, 0xee, 0xf4, 0xf8, 0xfe, + 0x02, 0x05, 0x07, 0x0a, 0x05, 0xfc, 0xf0, 0xe8, 0xeb, 0xf0, 0xf7, 0xf3, + 0xe8, 0xe8, 0xf2, 0xff, 0x0c, 0x10, 0x0f, 0x10, 0x0d, 0x09, 0x08, 0x08, + 0x02, 0x04, 0x0a, 0x0b, 0x0f, 0x14, 0x19, 0x21, 0x28, 0x2b, 0x25, 0x1d, + 0x11, 0x0a, 0x0d, 0x0c, 0x03, 0xf7, 0xf1, 0xef, 0xf4, 0xf7, 0xfd, 0xf4, + 0xee, 0xf1, 0xf3, 0xf9, 0xff, 0x00, 0xff, 0xfb, 0xf8, 0xee, 0xe5, 0xdf, + 0xe3, 0xee, 0xfc, 0x02, 0x06, 0x08, 0x06, 0x0f, 0x1b, 0x23, 0x23, 0x1c, + 0x13, 0x0e, 0x12, 0x12, 0x0f, 0x0a, 0x04, 0xfe, 0xfc, 0xfd, 0x00, 0x04, + 0x05, 0x02, 0x06, 0x0c, 0x11, 0x10, 0x14, 0x15, 0x13, 0x0e, 0x08, 0x04, + 0xfe, 0x02, 0x04, 0xff, 0xf4, 0xe5, 0xdb, 0xdc, 0xe8, 0xf0, 0xf8, 0xfa, + 0x02, 0x06, 0x05, 0x00, 0xf9, 0xf9, 0xf2, 0xf7, 0x00, 0x04, 0x04, 0x0a, + 0x17, 0x1f, 0x29, 0x2c, 0x23, 0x15, 0x08, 0x03, 0x02, 0xfd, 0xf3, 0xf0, + 0xf3, 0xf9, 0xf9, 0xfe, 0x05, 0x09, 0x12, 0x19, 0x18, 0x14, 0x12, 0x14, + 0x0f, 0x07, 0x00, 0xf7, 0xed, 0xed, 0xf6, 0xfc, 0x00, 0x00, 0xfc, 0xf5, + 0xf2, 0xfb, 0x09, 0x0d, 0x0b, 0x08, 0x04, 0x02, 0x00, 0xfd, 0xfa, 0xff, + 0x05, 0x03, 0xfd, 0xf7, 0xfb, 0x04, 0x09, 0x0c, 0x0d, 0x0d, 0x09, 0x0c, + 0x10, 0x11, 0x0b, 0x06, 0x00, 0xf9, 0xf5, 0xf7, 0x01, 0x07, 0x05, 0xfe, + 0xf7, 0xf9, 0x01, 0x06, 0x0e, 0x11, 0x11, 0x10, 0x06, 0xfd, 0x05, 0x14, + 0x12, 0x09, 0x02, 0xfc, 0xf7, 0x01, 0x11, 0x15, 0x15, 0x0f, 0x0a, 0xff, + 0xf9, 0xf9, 0xf6, 0xee, 0xe6, 0xe3, 0xe6, 0xed, 0xf6, 0xfa, 0x01, 0x08, + 0x10, 0x16, 0x13, 0x11, 0x11, 0x0d, 0x04, 0xf8, 0xec, 0xe3, 0xeb, 0xf6, + 0xff, 0x03, 0x0a, 0x13, 0x19, 0x1d, 0x1c, 0x1d, 0x21, 0x21, 0x1d, 0x1a, + 0x14, 0x0d, 0x07, 0x04, 0x06, 0x09, 0x08, 0x00, 0xf1, 0xe7, 0xe8, 0xec, + 0xef, 0xf1, 0xf6, 0xf8, 0xf8, 0xfe, 0x06, 0x03, 0xfc, 0xfc, 0x01, 0x01, + 0xfd, 0xfe, 0x00, 0x01, 0x08, 0x08, 0x00, 0xfb, 0xfb, 0xff, 0x07, 0x0c, + 0x0c, 0x05, 0xfa, 0xf5, 0xfc, 0x00, 0xff, 0x03, 0x0a, 0x11, 0x16, 0x21, + 0x2b, 0x2d, 0x2c, 0x26, 0x1c, 0x11, 0x04, 0xfe, 0xfa, 0xfe, 0x02, 0xfe, + 0xf8, 0xea, 0xe3, 0xea, 0xf9, 0x01, 0xff, 0xfe, 0xf9, 0xfc, 0x02, 0x00, + 0xfb, 0xf2, 0xdf, 0xd6, 0xdd, 0xed, 0x00, 0x06, 0x0a, 0x0d, 0x13, 0x18, + 0x16, 0x19, 0x1e, 0x1d, 0x16, 0x10, 0x0d, 0x01, 0xf9, 0x05, 0x0e, 0x09, + 0x01, 0xfe, 0x00, 0x09, 0x16, 0x13, 0x09, 0x07, 0x09, 0x09, 0x09, 0x10, + 0x16, 0x08, 0x00, 0xff, 0x04, 0x00, 0xf7, 0xf1, 0xec, 0xef, 0xf2, 0xf0, + 0xec, 0xea, 0xea, 0xf5, 0xfe, 0x04, 0x00, 0xf6, 0xf8, 0x02, 0x0b, 0x09, + 0x04, 0x06, 0x0b, 0x18, 0x1f, 0x23, 0x26, 0x27, 0x24, 0x18, 0x11, 0x0b, + 0xfa, 0xe8, 0xe5, 0xea, 0xf0, 0xf4, 0xf6, 0xf4, 0xfd, 0x0e, 0x18, 0x18, + 0x16, 0x14, 0x11, 0x0f, 0x0f, 0x06, 0xfb, 0xf5, 0xf7, 0xf7, 0xf2, 0xf2, + 0xf6, 0xf8, 0x00, 0x06, 0x08, 0x07, 0x04, 0x05, 0x08, 0x0b, 0x10, 0x0d, + 0x01, 0xeb, 0xee, 0x03, 0x0d, 0x0d, 0x03, 0xfe, 0x00, 0x05, 0x06, 0x04, + 0x04, 0x04, 0x02, 0x02, 0xff, 0x02, 0x02, 0x05, 0x08, 0x05, 0x02, 0x01, + 0xff, 0x08, 0x15, 0x1a, 0x15, 0x0b, 0x02, 0xf9, 0xff, 0x0b, 0x13, 0x0b, + 0xfa, 0xf0, 0xfc, 0x07, 0x04, 0xfa, 0xf3, 0xf7, 0xff, 0x01, 0x04, 0x0d, + 0x17, 0x16, 0x12, 0x09, 0x04, 0xff, 0xf6, 0xf5, 0xf7, 0xfb, 0xfe, 0xfd, + 0xfb, 0xfe, 0x07, 0x0e, 0x11, 0x0e, 0x09, 0x09, 0x0a, 0x08, 0x03, 0xf2, + 0xde, 0xda, 0xe5, 0xec, 0xef, 0xf6, 0x04, 0x15, 0x20, 0x21, 0x25, 0x24, + 0x1f, 0x1d, 0x1d, 0x18, 0x16, 0x12, 0x0d, 0x09, 0x0a, 0x0a, 0x02, 0xf8, + 0xf1, 0xf6, 0xf7, 0xf7, 0xf0, 0xed, 0xef, 0xf5, 0xf7, 0xfd, 0x03, 0xf6, + 0xf1, 0xfa, 0x04, 0x09, 0x0b, 0x08, 0x02, 0x04, 0x08, 0x08, 0x07, 0x05, + 0xff, 0xfa, 0xfa, 0xfc, 0xfe, 0x00, 0xfe, 0xfe, 0xfe, 0x05, 0x04, 0x04, + 0x0f, 0x1c, 0x24, 0x23, 0x1e, 0x22, 0x2b, 0x29, 0x1f, 0x18, 0x0b, 0xf3, + 0xe6, 0xed, 0xf3, 0xf1, 0xed, 0xe7, 0xe8, 0xf3, 0xf8, 0xfa, 0x00, 0x00, + 0xfb, 0xfd, 0xfe, 0xfd, 0xfa, 0xfa, 0xf8, 0xf3, 0xf8, 0xfc, 0xfc, 0x00, + 0x10, 0x1b, 0x1b, 0x17, 0x1d, 0x1b, 0x12, 0x10, 0x11, 0x0f, 0xff, 0xed, + 0xeb, 0xfb, 0x03, 0x06, 0x05, 0x06, 0x0b, 0x11, 0x0f, 0x0d, 0x09, 0x05, + 0x04, 0x02, 0x00, 0x00, 0x04, 0x0b, 0x0c, 0x07, 0x01, 0xfd, 0xfe, 0xfc, + 0xfb, 0xfc, 0xf9, 0xfa, 0xf8, 0xf2, 0xf0, 0xf8, 0xfe, 0xfb, 0xf1, 0xe9, + 0xf3, 0x02, 0x0b, 0x0a, 0x07, 0x0b, 0x0f, 0x10, 0x15, 0x1a, 0x18, 0x18, + 0x1d, 0x14, 0x07, 0x02, 0x06, 0xfc, 0xef, 0xf0, 0xf9, 0xfd, 0x00, 0x05, + 0x0f, 0x19, 0x17, 0x11, 0x10, 0x10, 0x0f, 0x0e, 0x08, 0xf7, 0xe6, 0xe3, + 0xe6, 0xea, 0xea, 0xe8, 0xec, 0xf5, 0xff, 0x08, 0x0a, 0x0e, 0x0f, 0x0a, + 0x08, 0x08, 0x0a, 0x11, 0x12, 0x0a, 0x09, 0x11, 0x12, 0x0e, 0x0d, 0x0c, + 0x09, 0x07, 0x02, 0xfc, 0xfa, 0xfc, 0xfa, 0xf8, 0xf1, 0xe5, 0xe0, 0xeb, + 0xfb, 0x03, 0x07, 0x15, 0x1b, 0x13, 0x13, 0x15, 0x13, 0x10, 0x0b, 0x03, + 0xfe, 0xff, 0xfe, 0x04, 0x08, 0x01, 0xfd, 0xfe, 0xff, 0xfb, 0xfe, 0x03, + 0x06, 0x06, 0x04, 0x06, 0x08, 0x0f, 0x15, 0x13, 0x03, 0xf9, 0xf3, 0xeb, + 0xf1, 0xfa, 0x03, 0x04, 0xfe, 0xfc, 0x06, 0x0b, 0x09, 0x06, 0x06, 0x03, + 0xfc, 0xf9, 0xf9, 0xfb, 0xf4, 0xef, 0xef, 0xfa, 0xff, 0x00, 0x0e, 0x1f, + 0x25, 0x25, 0x25, 0x29, 0x21, 0x17, 0x17, 0x0e, 0x00, 0xf9, 0xf6, 0xf3, + 0xfa, 0x01, 0xff, 0xfd, 0xfb, 0xfa, 0xf7, 0xf5, 0xf1, 0xee, 0xf0, 0xf3, + 0xf3, 0xf7, 0xfe, 0x06, 0x04, 0x04, 0x0c, 0x13, 0x13, 0x19, 0x17, 0x0e, + 0x08, 0x06, 0x06, 0x02, 0xfa, 0xf8, 0xf8, 0xec, 0xe1, 0xe5, 0xeb, 0xf4, + 0x00, 0x0d, 0x15, 0x17, 0x17, 0x1b, 0x1f, 0x1f, 0x1d, 0x19, 0x14, 0x12, + 0x12, 0x13, 0x19, 0x14, 0xfb, 0xeb, 0xeb, 0xec, 0xf0, 0xf6, 0xf8, 0xf8, + 0xfe, 0xff, 0xfa, 0xfc, 0x00, 0x05, 0xfe, 0xf2, 0xed, 0xeb, 0xe7, 0xf0, + 0xfe, 0x03, 0x01, 0xfe, 0x00, 0x06, 0x14, 0x1b, 0x1f, 0x19, 0x0a, 0x00, + 0x02, 0x0a, 0x10, 0x0a, 0x02, 0x03, 0x0e, 0x16, 0x18, 0x1f, 0x1f, 0x1b, + 0x13, 0x0a, 0x04, 0xfe, 0xfc, 0xfd, 0xf0, 0xe7, 0xe7, 0xe5, 0xe5, 0xed, + 0xff, 0x09, 0x0b, 0x05, 0xfc, 0xfa, 0xfc, 0xfc, 0xfc, 0xf8, 0xf6, 0xf8, + 0xff, 0x09, 0x0c, 0x0a, 0x07, 0x08, 0x0a, 0x10, 0x14, 0x13, 0x11, 0x11, + 0x11, 0x0f, 0x0c, 0x08, 0x06, 0xfe, 0xf6, 0xf8, 0xf9, 0xec, 0xe5, 0xf7, + 0x09, 0x11, 0x0d, 0x0a, 0x0c, 0x12, 0x18, 0x14, 0x06, 0x01, 0xfe, 0xff, + 0x03, 0x09, 0x00, 0xec, 0xe7, 0xe9, 0xed, 0xf2, 0xf7, 0xfc, 0xfe, 0x01, + 0x0a, 0x15, 0x19, 0x12, 0x06, 0x00, 0xfe, 0x00, 0xfe, 0xfd, 0x04, 0x14, + 0x1b, 0x13, 0x06, 0x04, 0x01, 0x03, 0x00, 0xf9, 0xee, 0xe8, 0xe9, 0xec, + 0xfa, 0xff, 0xfa, 0xf8, 0x00, 0x0c, 0x1e, 0x31, 0x33, 0x26, 0x1a, 0x17, + 0x13, 0x0b, 0x04, 0xfd, 0xf2, 0xea, 0xec, 0xeb, 0xe7, 0xe9, 0xf7, 0x00, + 0x02, 0x04, 0x02, 0xfd, 0x00, 0x04, 0x08, 0x03, 0x01, 0x05, 0x02, 0x0c, + 0x1d, 0x1e, 0x0d, 0xff, 0xfb, 0xff, 0x03, 0x09, 0x06, 0x01, 0x01, 0x02, + 0x04, 0x00, 0xfc, 0xf3, 0xeb, 0xeb, 0xea, 0xea, 0xea, 0xf0, 0x02, 0x10, + 0x14, 0x11, 0x0d, 0x0e, 0x18, 0x1f, 0x1f, 0x1e, 0x15, 0x0b, 0x0c, 0x17, + 0x17, 0x09, 0x00, 0xfc, 0xf9, 0x00, 0x0d, 0x0b, 0x03, 0xfe, 0xfb, 0xf8, + 0xf7, 0xfc, 0xf4, 0xe5, 0xe5, 0xe9, 0xec, 0xee, 0xf1, 0xfb, 0x07, 0x0c, + 0x16, 0x18, 0x0e, 0x06, 0x06, 0x03, 0xfb, 0xf4, 0xee, 0xf0, 0xf7, 0x04, + 0x08, 0x02, 0x04, 0x0b, 0x17, 0x23, 0x2d, 0x30, 0x27, 0x1e, 0x1a, 0x17, + 0x14, 0x0c, 0x01, 0xf8, 0xf4, 0xf2, 0xfa, 0xf8, 0xec, 0xea, 0xf0, 0xf4, + 0xf4, 0xf2, 0xf0, 0xf6, 0xf9, 0xff, 0xfe, 0xfa, 0xfb, 0xff, 0x0b, 0x13, + 0x0e, 0x06, 0xfe, 0xfa, 0xfc, 0x03, 0x08, 0x04, 0x00, 0x00, 0x04, 0x0c, + 0x14, 0x0e, 0x00, 0xf9, 0xf7, 0xfa, 0xfe, 0x00, 0x09, 0x19, 0x20, 0x26, + 0x26, 0x1b, 0x14, 0x11, 0x0a, 0xfe, 0xf7, 0xf8, 0xf1, 0xf6, 0x00, 0x00, + 0xf6, 0xee, 0xec, 0xee, 0xf8, 0x08, 0x17, 0x10, 0x04, 0x02, 0x04, 0x04, + 0x00, 0xf6, 0xec, 0xe8, 0xea, 0xfa, 0xfd, 0xfc, 0x04, 0x0c, 0x11, 0x11, + 0x12, 0x0e, 0x08, 0x05, 0x00, 0xfb, 0xfc, 0xfe, 0x00, 0x08, 0x0f, 0x0f, + 0x0f, 0x0d, 0x0c, 0x0e, 0x14, 0x1c, 0x1c, 0x13, 0x10, 0x0e, 0x0a, 0x08, + 0x00, 0xf2, 0xeb, 0xeb, 0xef, 0xee, 0xef, 0xee, 0xec, 0xef, 0xf2, 0xf4, + 0xf4, 0xf4, 0xf8, 0xfe, 0x00, 0x08, 0x16, 0x10, 0x14, 0x20, 0x1e, 0x15, + 0x0e, 0x0a, 0x09, 0x0b, 0x15, 0x1e, 0x13, 0x03, 0x00, 0xfc, 0xf7, 0xf0, + 0xee, 0xe4, 0xdc, 0xe1, 0xe8, 0xf3, 0xfd, 0x04, 0x0a, 0x12, 0x1b, 0x28, + 0x28, 0x20, 0x16, 0x0a, 0x00, 0xff, 0xfb, 0xf7, 0xff, 0x01, 0x00, 0x00, + 0xfc, 0xf7, 0xf9, 0x03, 0x0d, 0x10, 0x0e, 0x0b, 0x08, 0x0a, 0x06, 0x00, + 0xfc, 0xf8, 0xf4, 0xf6, 0xff, 0x05, 0x01, 0xff, 0x01, 0x01, 0x00, 0x00, + 0xfc, 0xf8, 0xf3, 0xee, 0xf0, 0xf8, 0xf8, 0x00, 0x0c, 0x0c, 0x0a, 0x0c, + 0x14, 0x11, 0x0e, 0x16, 0x1b, 0x18, 0x12, 0x10, 0x10, 0x0c, 0x0a, 0x0c, + 0x08, 0x00, 0xfc, 0xfc, 0xfe, 0xfc, 0xf5, 0xf6, 0xfc, 0x00, 0x04, 0x09, + 0x01, 0xfa, 0xf8, 0xf4, 0xf6, 0xfa, 0xff, 0x00, 0x03, 0x02, 0x00, 0xfe, + 0xfe, 0xfc, 0xfe, 0x05, 0x12, 0x14, 0x0e, 0x08, 0x04, 0xf8, 0xf3, 0xf6, + 0xee, 0xe6, 0xec, 0xf6, 0x04, 0x0e, 0x10, 0x16, 0x1f, 0x24, 0x28, 0x28, + 0x22, 0x12, 0x06, 0x00, 0x00, 0x02, 0x06, 0x0a, 0x08, 0x00, 0xfe, 0xfc, + 0xf4, 0xf2, 0xf8, 0xfc, 0xfc, 0xfc, 0xff, 0x03, 0x00, 0xf6, 0xf8, 0xfa, + 0xee, 0xef, 0xfa, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfe, 0x00, 0xfe, 0xfa, + 0xf4, 0xf0, 0xf0, 0xfa, 0x07, 0x10, 0x1a, 0x24, 0x1f, 0x1c, 0x1e, 0x1c, + 0x19, 0x1b, 0x24, 0x26, 0x24, 0x22, 0x16, 0x07, 0xf9, 0xf3, 0xf6, 0xf2, + 0xe7, 0xde, 0xe6, 0xeb, 0xea, 0xe8, 0xea, 0xee, 0xf0, 0xfc, 0x04, 0x06, + 0x04, 0x00, 0x00, 0xff, 0x00, 0x02, 0x08, 0x0a, 0x04, 0x02, 0x08, 0x0c, + 0x06, 0x0a, 0x12, 0x13, 0x14, 0x18, 0x10, 0xfe, 0xf4, 0xf6, 0xfc, 0xf9, + 0xf7, 0xfe, 0x04, 0x09, 0x08, 0x08, 0x14, 0x17, 0x14, 0x0e, 0x0b, 0x06, + 0x00, 0xfe, 0xfe, 0xf8, 0xfe, 0x06, 0x04, 0x00, 0xfe, 0xfc, 0xfc, 0xfe, + 0xfa, 0xf8, 0xfc, 0xfe, 0x00, 0x02, 0x01, 0xfd, 0xfb, 0x03, 0x03, 0xfe, + 0x06, 0x0d, 0x0d, 0x05, 0x03, 0x07, 0x09, 0x07, 0x07, 0x05, 0x05, 0xfb, + 0xed, 0xe9, 0xeb, 0xf5, 0x05, 0x15, 0x11, 0x07, 0x09, 0x0d, 0x0f, 0x0d, + 0x0f, 0x16, 0x1a, 0x1e, 0x1c, 0x19, 0x10, 0x02, 0xfb, 0xfb, 0xf1, 0xe7, + 0xe9, 0xef, 0xef, 0xeb, 0xf6, 0xfe, 0xfd, 0xff, 0x05, 0x09, 0x11, 0x15, + 0x0b, 0x00, 0xfb, 0x02, 0x0b, 0x13, 0x11, 0x0b, 0x05, 0x03, 0xfb, 0xfb, + 0x05, 0x07, 0x01, 0xfb, 0xfc, 0xf8, 0xef, 0xed, 0xf3, 0xf5, 0xf9, 0xfb, + 0xff, 0x07, 0x08, 0x09, 0x17, 0x21, 0x1a, 0x11, 0x0d, 0x0b, 0x05, 0x01, + 0x00, 0x00, 0x05, 0x0f, 0x11, 0x15, 0x17, 0x0d, 0x07, 0x00, 0xf9, 0xfb, + 0x03, 0x07, 0x06, 0x0b, 0x0f, 0x00, 0xee, 0xef, 0xf2, 0xef, 0x00, 0x00, + 0xc8, 0xcb, 0x0f, 0x20, 0xc0, 0xff, 0x50, 0xd8, 0xbb, 0x2f, 0x40, 0xe0, + 0xdf, 0xf1, 0x0f, 0x04, 0xf7, 0x0a, 0x0b, 0x00, 0xa7, 0x37, 0x28, 0xfb, + 0x13, 0xf4, 0xc2, 0xff, 0x5a, 0x18, 0xe8, 0xf7, 0x55, 0x4e, 0x42, 0x20, + 0x07, 0x3f, 0x00, 0xe2, 0xd7, 0x3f, 0x10, 0xf9, 0x03, 0xf0, 0x0f, 0x00, + 0xdb, 0xff, 0xf0, 0xdf, 0xe8, 0xe6, 0xf0, 0xd7, 0xf2, 0xcc, 0xbd, 0xe2, + 0xc0, 0x89, 0x80, 0xab, 0xa8, 0x9a, 0x97, 0xea, 0xc0, 0xa0, 0xbf, 0x00, + 0xb0, 0xbf, 0x00, 0xca, 0xed, 0xed, 0xf3, 0xf8, 0xef, 0x13, 0x04, 0xe7, + 0x37, 0x02, 0x1f, 0x37, 0x2f, 0x4f, 0x42, 0x3f, 0x58, 0x2d, 0x71, 0x20, + 0x3f, 0x7b, 0x50, 0x3f, 0x50, 0x39, 0x30, 0x2d, 0x4e, 0x20, 0x16, 0x22, + 0x23, 0x14, 0xff, 0x1e, 0x08, 0xca, 0xff, 0x28, 0xe0, 0xe3, 0x1f, 0xc0, + 0xbf, 0x2e, 0xd8, 0xf7, 0xc0, 0xbf, 0x13, 0x08, 0xdb, 0xfe, 0xf1, 0xe8, + 0xdf, 0xe0, 0xe7, 0xd0, 0xcf, 0x0c, 0x0b, 0xf2, 0xe4, 0xbf, 0xe7, 0x10, + 0xc8, 0xc5, 0xe8, 0xe7, 0xcc, 0xc9, 0xb6, 0xcf, 0x03, 0xea, 0xfb, 0x06, + 0xe0, 0xd5, 0xff, 0x00, 0xf1, 0xfb, 0x23, 0x04, 0xdf, 0x2f, 0x1c, 0xf4, + 0x17, 0x38, 0x05, 0x13, 0x21, 0x2f, 0x00, 0x1f, 0x48, 0xf0, 0x37, 0x48, + 0xf2, 0x2f, 0x38, 0x1c, 0x1f, 0x27, 0x37, 0x40, 0xff, 0x52, 0x20, 0x27, + 0x55, 0x64, 0x52, 0x20, 0x3b, 0x55, 0x69, 0x68, 0x17, 0x6f, 0x50, 0x2b, + 0x5b, 0x40, 0x14, 0x12, 0x27, 0x30, 0x02, 0x34, 0xf4, 0x07, 0x16, 0x00, + 0xff, 0xfb, 0x1a, 0xf4, 0xcf, 0x0a, 0x00, 0xe2, 0xe0, 0xbf, 0x0b, 0x00, + 0xde, 0xd9, 0xe1, 0xd8, 0xb6, 0xcf, 0xd5, 0xde, 0xd0, 0xdb, 0xc0, 0xaf, + 0xc8, 0xbd, 0xe5, 0xcc, 0x80, 0xbf, 0xe0, 0xc8, 0xaf, 0xb6, 0xe5, 0xd0, + 0xaf, 0xf7, 0xe4, 0xc8, 0xef, 0xe8, 0xfa, 0xd0, 0x0f, 0xf8, 0xe0, 0xfb, + 0x10, 0xec, 0xfb, 0x11, 0xfd, 0x08, 0x0b, 0x0c, 0xff, 0x0a, 0x15, 0x12, + 0x07, 0x26, 0x09, 0x1a, 0x19, 0x3b, 0x34, 0x1a, 0x34, 0x03, 0x30, 0xf3, + 0x7b, 0x48, 0x00, 0x2f, 0x30, 0x27, 0x37, 0x34, 0x01, 0x2b, 0x50, 0x2c, + 0xf0, 0x37, 0x14, 0x09, 0x0d, 0x2f, 0x08, 0x0f, 0x14, 0xfc, 0x0f, 0x04, + 0xb9, 0xff, 0x20, 0xd4, 0x17, 0xf0, 0xd4, 0xd7, 0x12, 0xf0, 0xd8, 0xdf, + 0xf0, 0xa8, 0xdf, 0xf8, 0xd0, 0xc7, 0xfb, 0xe0, 0xbf, 0xd4, 0xcb, 0xd9, + 0x02, 0xe5, 0xd5, 0xe2, 0xca, 0xcf, 0xeb, 0x04, 0xef, 0xe8, 0xd0, 0xcf, + 0x0c, 0xe2, 0xe7, 0x0f, 0xd0, 0xef, 0xf0, 0xe4, 0xe7, 0x00, 0xbb, 0xff, + 0x08, 0xd5, 0x0d, 0x13, 0xf0, 0xdf, 0x1f, 0x1a, 0x00, 0xdf, 0xf4, 0xfb, + 0x2f, 0x08, 0xdd, 0x0f, 0x05, 0x00, 0xdf, 0x1e, 0xf0, 0x0d, 0x00, 0x02, + 0xfb, 0x2b, 0x00, 0x0b, 0xf6, 0x2d, 0x2c, 0x08, 0xfd, 0x09, 0x1c, 0x0d, + 0x1f, 0x34, 0x1a, 0xea, 0x27, 0x28, 0x00, 0xe5, 0x1f, 0x4c, 0x1c, 0x06, + 0x06, 0x07, 0x10, 0x1b, 0x06, 0xf9, 0x15, 0x02, 0x0c, 0x0f, 0x00, 0xff, + 0x00, 0xcb, 0xff, 0x1c, 0x0a, 0xf8, 0xef, 0x13, 0x14, 0xec, 0xcb, 0xff, + 0xeb, 0x1f, 0x08, 0xdb, 0xff, 0x08, 0xf0, 0xe3, 0x0b, 0xe0, 0xcf, 0x0f, + 0x20, 0xec, 0xcb, 0xfd, 0xfc, 0xf6, 0xff, 0xc8, 0xcf, 0x17, 0xf0, 0xc8, + 0xdf, 0x07, 0xe4, 0xcf, 0xf7, 0xfa, 0xe0, 0xe7, 0xe3, 0xeb, 0xea, 0xe1, + 0xfe, 0xe0, 0xc1, 0xd3, 0x0c, 0xd4, 0xbf, 0xe3, 0xe3, 0xfd, 0xf0, 0xc7, + 0xff, 0xdd, 0xfd, 0xd2, 0xea, 0xc7, 0x17, 0xf4, 0xe1, 0xd3, 0x07, 0x00, + 0xda, 0xff, 0x12, 0xd8, 0xe3, 0xf7, 0x00, 0xef, 0x1c, 0x0c, 0xe0, 0xef, + 0x18, 0x00, 0xf7, 0x17, 0x02, 0xfe, 0x0a, 0xfa, 0x17, 0x14, 0x07, 0x13, + 0x17, 0x10, 0x0f, 0x14, 0x1f, 0x30, 0x16, 0x05, 0x25, 0x2e, 0x25, 0xf8, + 0x1f, 0x28, 0x10, 0x03, 0x2b, 0x2e, 0x18, 0x04, 0x07, 0x19, 0x1d, 0x37, + 0xf0, 0xe7, 0x3f, 0x20, 0xed, 0x12, 0x26, 0xf0, 0xdb, 0x15, 0xf8, 0xfb, + 0x0a, 0xf9, 0x00, 0xf3, 0xe0, 0xff, 0x09, 0xf0, 0xf5, 0xfb, 0xf4, 0xea, + 0xe3, 0x0d, 0x04, 0xee, 0x09, 0xcc, 0xf7, 0x1a, 0xf0, 0xe7, 0xef, 0xfe, + 0xfc, 0xf7, 0x0a, 0xd3, 0xef, 0x06, 0xf4, 0xf0, 0xd5, 0xfb, 0x00, 0xe6, + 0xff, 0xe4, 0xef, 0xf3, 0x00, 0xff, 0xf0, 0xff, 0x02, 0x0a, 0xd4, 0xef, + 0xff, 0x10, 0xdb, 0x13, 0xea, 0xfc, 0xe7, 0xf4, 0x07, 0x00, 0xfc, 0xe8, + 0xef, 0x13, 0x14, 0xe6, 0xf7, 0x27, 0x00, 0xdb, 0x15, 0x10, 0xea, 0x1f, + 0x18, 0xf2, 0xfb, 0x0f, 0x28, 0xf4, 0x0b, 0x22, 0xf8, 0xff, 0x00, 0xfe, + 0x07, 0x18, 0xf2, 0xf7, 0x1b, 0x0d, 0x1b, 0x00, 0xff, 0x2c, 0x06, 0xf2, + 0x0f, 0x22, 0x20, 0xf0, 0x0f, 0x30, 0x08, 0xea, 0x07, 0x1f, 0x22, 0x0c, + 0xe7, 0x17, 0x31, 0xf4, 0x0f, 0x30, 0x04, 0xfe, 0x2d, 0x10, 0xec, 0x13, + 0x14, 0x09, 0x22, 0x08, 0x17, 0x06, 0x03, 0x15, 0x00, 0xf2, 0x1b, 0x10, + 0x11, 0x07, 0x18, 0x02, 0x10, 0x07, 0x19, 0x12, 0xe3, 0x0a, 0x1f, 0x00, + 0xf7, 0x1f, 0x18, 0xfe, 0xfa, 0x13, 0x0c, 0x03, 0x16, 0x06, 0x04, 0x07, + 0x0a, 0x16, 0xe8, 0xff, 0x00, 0xe9, 0xff, 0x00, 0x0b, 0x0e, 0xf0, 0xff, + 0x08, 0xf8, 0xe0, 0xef, 0x0a, 0xfc, 0x06, 0xe9, 0x0b, 0xfa, 0xf0, 0xef, + 0xfe, 0xf8, 0xec, 0xdf, 0xf9, 0xfd, 0xfc, 0xfa, 0xf1, 0xf1, 0xf5, 0xf9, + 0xe0, 0xfb, 0x06, 0xfb, 0xe9, 0xfe, 0xff, 0x00, 0xf5, 0xff, 0x00, 0xf8, + 0xf5, 0x00, 0xe3, 0x0b, 0x18, 0x10, 0x00, 0x07, 0x04, 0x17, 0x00, 0xfb, + 0x09, 0xff, 0x20, 0xf0, 0x17, 0x18, 0xff, 0x1f, 0x20, 0xef, 0x13, 0xfa, + 0x0f, 0x10, 0x1b, 0x32, 0xfd, 0x1f, 0x22, 0x03, 0x09, 0x1b, 0x18, 0x19, + 0x1d, 0x25, 0x0c, 0x01, 0x1f, 0x28, 0x18, 0x05, 0x1e, 0x12, 0x00, 0x0c, + 0x0b, 0x1b, 0x12, 0x10, 0xf7, 0x2a, 0x12, 0xf5, 0x0d, 0x18, 0xec, 0xf7, + 0x0a, 0xff, 0x0e, 0x0c, 0xfd, 0xfe, 0xf0, 0xfb, 0x0a, 0xf1, 0xf7, 0x10, + 0xf0, 0xe7, 0x06, 0xfe, 0xf0, 0xee, 0xff, 0x03, 0xf2, 0xef, 0xff, 0xf0, + 0xdf, 0xff, 0x00, 0xee, 0xef, 0xe0, 0xe7, 0xef, 0xf3, 0xf9, 0xe4, 0xee, + 0xf3, 0xf8, 0xe6, 0xf0, 0xe5, 0xe4, 0xd3, 0xe5, 0x03, 0xfd, 0xec, 0xd7, + 0xef, 0xf8, 0xe9, 0xe6, 0xe9, 0xe6, 0xf3, 0x05, 0xfc, 0xea, 0xf1, 0xf3, + 0xf8, 0xfd, 0xf0, 0xeb, 0xf2, 0x12, 0x00, 0xee, 0xff, 0x08, 0x01, 0xf8, + 0xfb, 0x11, 0x09, 0x04, 0xef, 0x0f, 0x00, 0x03, 0x00, 0x12, 0x0a, 0x08, + 0x0a, 0xf9, 0xfb, 0xff, 0x01, 0x09, 0x12, 0x0e, 0x09, 0x14, 0x07, 0xfc, + 0x07, 0xfa, 0x05, 0x0e, 0x0d, 0xf9, 0x0d, 0x0c, 0xe7, 0xfb, 0x10, 0x02, + 0x03, 0x02, 0xf8, 0x0c, 0xf6, 0xfd, 0xfc, 0x00, 0xf5, 0x03, 0x10, 0xf6, + 0xdf, 0xff, 0x16, 0xf8, 0xef, 0x0b, 0xf8, 0xe2, 0xff, 0xf4, 0xf3, 0xf1, + 0xf5, 0xe6, 0xf3, 0x05, 0xf8, 0xf5, 0xe8, 0xf1, 0xf7, 0xf8, 0xe0, 0xe7, + 0xf8, 0xe7, 0xf3, 0xea, 0xeb, 0x00, 0xf2, 0xdc, 0xdf, 0xf5, 0xe9, 0xf0, + 0xe9, 0xf6, 0x02, 0xe0, 0xef, 0x0a, 0xe5, 0xf8, 0xe3, 0xf5, 0x00, 0xf8, + 0xf0, 0xe0, 0xef, 0x03, 0xec, 0xe5, 0xf3, 0xfe, 0xfc, 0xed, 0x01, 0xf4, + 0xe8, 0xf3, 0x01, 0xfc, 0x04, 0xe1, 0xfd, 0xfa, 0xf2, 0xe7, 0xf5, 0x07, + 0x08, 0xf8, 0xe8, 0xf6, 0xfb, 0x05, 0x01, 0x09, 0xf8, 0xf3, 0xfd, 0x00, + 0xed, 0xfb, 0x06, 0xf4, 0xf8, 0x02, 0xf8, 0xe8, 0xed, 0x0e, 0xfa, 0xf7, + 0x05, 0x07, 0xf0, 0xf3, 0x06, 0xf9, 0xf7, 0x01, 0xfc, 0xfc, 0xfc, 0xfc, + 0x02, 0xf2, 0xf5, 0xfd, 0x02, 0x0f, 0x04, 0xfb, 0xff, 0x0c, 0x02, 0x02, + 0x00, 0xf7, 0x0f, 0x08, 0x07, 0x03, 0x05, 0x0d, 0x00, 0xff, 0x13, 0x00, + 0x0f, 0x04, 0xfb, 0x08, 0xfe, 0x0a, 0x09, 0xfc, 0xfa, 0x03, 0x08, 0xff, + 0x09, 0x03, 0xf0, 0x03, 0x04, 0xfb, 0xf9, 0xee, 0x07, 0x09, 0xf8, 0xfa, + 0xf2, 0xf3, 0xec, 0xee, 0xf7, 0xff, 0x0c, 0xf4, 0xf2, 0xf7, 0x0c, 0xf2, + 0xf2, 0xf2, 0xf4, 0x02, 0x01, 0xf9, 0xf2, 0xf7, 0xf7, 0xf5, 0xf0, 0xfd, + 0x00, 0xf0, 0xf3, 0xf7, 0xf8, 0xf0, 0x03, 0xf4, 0xf9, 0x03, 0xf1, 0xff, + 0xf2, 0xde, 0xff, 0x04, 0xf5, 0xe8, 0xfd, 0x04, 0xfb, 0xfa, 0x03, 0xfb, + 0xf0, 0xf5, 0xfe, 0xfa, 0x05, 0xf8, 0xff, 0x12, 0x00, 0xf3, 0x05, 0x00, + 0xf7, 0x0a, 0x0a, 0xf8, 0x03, 0xfe, 0x0e, 0x0c, 0x02, 0xf6, 0x07, 0x10, + 0xf8, 0x0b, 0x06, 0xf8, 0xf7, 0x03, 0x0a, 0x09, 0x0b, 0x0b, 0x04, 0x02, + 0xf9, 0xf7, 0x0d, 0x06, 0x03, 0x00, 0xff, 0x06, 0x0f, 0x08, 0x07, 0x00, + 0xf9, 0x0b, 0x13, 0x00, 0x03, 0x0a, 0x00, 0x02, 0x05, 0x05, 0x0d, 0x0f, + 0x0f, 0x0c, 0x07, 0x00, 0x02, 0x03, 0x11, 0x16, 0x0c, 0xf6, 0x07, 0x18, + 0x06, 0x04, 0x08, 0x05, 0x15, 0x0e, 0x06, 0xf7, 0x0e, 0x06, 0x02, 0x03, + 0x07, 0x0a, 0x05, 0x00, 0x07, 0x00, 0x02, 0xfa, 0x06, 0x0e, 0x10, 0xfd, + 0xfd, 0x00, 0xf5, 0x03, 0xfa, 0xfc, 0x04, 0x03, 0xfb, 0x00, 0xfc, 0xfc, + 0x03, 0x04, 0x05, 0x01, 0xf6, 0xff, 0x02, 0xf8, 0xf1, 0xfb, 0x15, 0x0e, + 0xf8, 0xf9, 0x10, 0x02, 0xff, 0x06, 0xf0, 0xfd, 0x12, 0xfa, 0x07, 0xfc, + 0xfb, 0x11, 0x14, 0x00, 0xf9, 0x0d, 0x0b, 0x06, 0x00, 0xf5, 0x01, 0x0a, + 0x08, 0x07, 0x08, 0xfb, 0x0b, 0x0b, 0xf9, 0xff, 0x10, 0x0c, 0x14, 0x05, + 0xf7, 0xff, 0x12, 0x0c, 0x09, 0x12, 0x0c, 0xfc, 0x03, 0x00, 0x0f, 0x14, + 0x16, 0x12, 0xf8, 0xfd, 0x13, 0x1c, 0x0c, 0x11, 0x00, 0x02, 0x12, 0x0d, + 0x0f, 0x18, 0x03, 0x09, 0x12, 0x14, 0x08, 0xff, 0x02, 0x0f, 0x11, 0x07, + 0x05, 0x05, 0xfd, 0x17, 0x0c, 0x00, 0x03, 0x0e, 0x00, 0x07, 0x10, 0x07, + 0x00, 0x03, 0x09, 0x05, 0xf0, 0xf5, 0x0f, 0x18, 0x04, 0x04, 0xff, 0x02, + 0x06, 0x00, 0x01, 0x01, 0x03, 0xfc, 0xff, 0x03, 0x03, 0xf6, 0xf9, 0x01, + 0x0a, 0x04, 0x04, 0xf8, 0xfb, 0xfd, 0xf9, 0xfe, 0x00, 0x07, 0x00, 0xfa, + 0x05, 0x09, 0xf8, 0xfb, 0xfa, 0xf7, 0xf9, 0x04, 0x02, 0x02, 0xf7, 0x09, + 0x06, 0xf0, 0xea, 0xff, 0x00, 0xff, 0x10, 0x00, 0xec, 0xf3, 0xfe, 0x07, + 0x03, 0xf6, 0xff, 0xfe, 0xf4, 0xf8, 0xf7, 0x07, 0x05, 0xfc, 0xf2, 0x0b, + 0x0a, 0xf0, 0xf7, 0x09, 0x01, 0x01, 0xf5, 0xff, 0x05, 0x00, 0xf7, 0xfb, + 0xf8, 0x02, 0x00, 0xf4, 0x06, 0x09, 0xfd, 0x02, 0x00, 0x00, 0xf8, 0xfa, + 0xfe, 0xfc, 0xfd, 0x00, 0x01, 0x03, 0x04, 0x08, 0xf6, 0xf5, 0x0e, 0x00, + 0xf6, 0x09, 0x08, 0xf3, 0xff, 0x07, 0x09, 0x06, 0xfd, 0x07, 0x07, 0x05, + 0xff, 0xfd, 0x09, 0x0c, 0x0a, 0x07, 0x0a, 0x02, 0xfa, 0xff, 0x02, 0x0d, + 0x10, 0x08, 0xfb, 0xfd, 0x04, 0x07, 0x08, 0xfa, 0xfe, 0x05, 0xfc, 0xf9, + 0xfb, 0x03, 0x04, 0xf7, 0xf6, 0xf2, 0xf7, 0x04, 0x04, 0xfa, 0xf2, 0xf5, + 0xff, 0xfa, 0xea, 0xef, 0xfc, 0xf4, 0xee, 0x02, 0xf4, 0xef, 0xf1, 0xee, + 0xf9, 0xfe, 0xf7, 0xf1, 0xed, 0xf7, 0xfd, 0xfb, 0xf8, 0xf6, 0xf6, 0xef, + 0xf0, 0xf7, 0x05, 0xfd, 0xf6, 0xef, 0xf7, 0xf7, 0xfa, 0xed, 0xf5, 0xfe, + 0x00, 0xf5, 0xf6, 0xf4, 0xf5, 0xfc, 0xf9, 0xfa, 0xee, 0xf8, 0xf2, 0xf5, + 0xfb, 0x02, 0x04, 0xf4, 0xfb, 0xf0, 0xed, 0xfb, 0x03, 0x02, 0xfc, 0xf0, + 0xfb, 0x07, 0x00, 0xf0, 0xf7, 0x03, 0x02, 0x02, 0x00, 0xff, 0xfe, 0xf8, + 0xfa, 0x03, 0xfe, 0x05, 0x08, 0xfc, 0x05, 0x00, 0xf7, 0xf5, 0xf9, 0x08, + 0x00, 0x00, 0x02, 0x04, 0xf8, 0xf3, 0xf5, 0x09, 0x0a, 0x00, 0xfa, 0xfb, + 0xf8, 0xef, 0xf8, 0xff, 0x02, 0xfd, 0xfd, 0xfc, 0xed, 0xef, 0x01, 0x01, + 0x00, 0xec, 0xeb, 0x07, 0x0c, 0xf2, 0xff, 0x00, 0xf7, 0xfd, 0xfc, 0xf4, + 0xfe, 0x0a, 0xf4, 0xe6, 0x07, 0x0a, 0xf0, 0xf7, 0x04, 0x04, 0x04, 0xf8, + 0xff, 0x00, 0xf9, 0xf3, 0xfa, 0x03, 0x00, 0x03, 0x00, 0xf4, 0xee, 0xf2, + 0x0f, 0x08, 0xf8, 0xea, 0xef, 0x07, 0x04, 0xfd, 0xf6, 0xe6, 0xfd, 0x08, + 0xf1, 0xf5, 0x03, 0xfa, 0xf2, 0xfa, 0xf2, 0xff, 0xfc, 0xfa, 0xf8, 0xf1, + 0xfe, 0xf8, 0xf7, 0x08, 0xf4, 0xf5, 0xfb, 0xf9, 0xf2, 0xfa, 0xf5, 0xf9, + 0xf7, 0xf0, 0xff, 0x09, 0xf4, 0xf1, 0xfe, 0xf8, 0xef, 0x03, 0x00, 0xf8, + 0xff, 0x00, 0xf8, 0xf0, 0xfd, 0x0a, 0xfe, 0xfd, 0xf6, 0xf4, 0x07, 0x02, + 0xf5, 0xfb, 0xfc, 0x06, 0x03, 0xfe, 0x07, 0x0a, 0x00, 0xf2, 0x05, 0x06, + 0xff, 0x0b, 0x0a, 0xfc, 0xff, 0x0d, 0x09, 0x05, 0xfe, 0x0d, 0xf9, 0x06, + 0x04, 0xfe, 0x0d, 0x0c, 0x00, 0xf6, 0x03, 0x06, 0x07, 0x04, 0x05, 0x0d, + 0x08, 0xfa, 0xff, 0xf9, 0xfb, 0x0b, 0x04, 0xff, 0x02, 0x06, 0xfd, 0xff, + 0xfa, 0xff, 0x0a, 0x00, 0xff, 0xff, 0x06, 0x01, 0xfa, 0xf6, 0x0a, 0x00, + 0xf9, 0xff, 0xfe, 0xf2, 0xff, 0x0e, 0xf8, 0xf9, 0xf6, 0xf9, 0x05, 0x01, + 0xf1, 0xf6, 0xff, 0x02, 0xfc, 0xf2, 0xfd, 0xf4, 0xec, 0xfb, 0x09, 0xf6, + 0xf4, 0xfb, 0xfc, 0x00, 0xf4, 0xf5, 0x08, 0xf6, 0xf3, 0x03, 0x02, 0xf6, + 0xf0, 0xf3, 0xfe, 0x08, 0xfb, 0xf8, 0xef, 0xfd, 0x04, 0xf1, 0xff, 0x0b, + 0x00, 0xf2, 0xff, 0x02, 0x05, 0x06, 0x00, 0xf2, 0x07, 0x0e, 0xf8, 0x0b, + 0x0c, 0xf6, 0x05, 0x10, 0x08, 0xfc, 0xf5, 0x0d, 0x12, 0x04, 0xf9, 0x0b, + 0x12, 0x02, 0x08, 0x02, 0x07, 0x11, 0x04, 0x0d, 0x0a, 0x02, 0xfe, 0xfd, + 0xfe, 0x0b, 0x08, 0x03, 0x0f, 0x09, 0xfa, 0xf3, 0x07, 0x03, 0x02, 0x02, + 0xff, 0x09, 0x0a, 0x05, 0x03, 0xff, 0xfd, 0xfc, 0x02, 0xfd, 0x01, 0x08, + 0x00, 0xfa, 0x01, 0x04, 0x00, 0xf7, 0x0c, 0x08, 0xfd, 0x0c, 0x04, 0x01, + 0xf1, 0x07, 0x0a, 0xfc, 0x06, 0x03, 0x07, 0x05, 0x00, 0xf8, 0xfb, 0x04, + 0x00, 0x02, 0xfe, 0x00, 0x05, 0xfc, 0xfa, 0x02, 0x04, 0xf9, 0xff, 0x0a, + 0x02, 0xf0, 0xfc, 0x03, 0x07, 0xfc, 0xfc, 0xf3, 0xff, 0x09, 0xff, 0x05, + 0xf8, 0xfb, 0x09, 0x04, 0xf4, 0xed, 0xff, 0x0b, 0x08, 0x00, 0xf3, 0x05, + 0x08, 0xff, 0x00, 0xee, 0xfa, 0x0e, 0x02, 0xfa, 0x07, 0x06, 0xf4, 0xf5, + 0xf8, 0xff, 0x0b, 0x0a, 0xf4, 0xfd, 0x0b, 0x05, 0xf7, 0x02, 0xfc, 0xfa, + 0xf9, 0xfa, 0x09, 0x0b, 0x09, 0xf8, 0xef, 0x0d, 0x08, 0xf1, 0x0b, 0x10, + 0xfc, 0xf5, 0x07, 0x0e, 0xfa, 0xfb, 0x0e, 0x00, 0x02, 0x04, 0x07, 0x06, + 0x00, 0xff, 0x13, 0x00, 0xf9, 0x05, 0x06, 0x05, 0x05, 0x05, 0x02, 0x00, + 0x03, 0x09, 0x00, 0xf1, 0x05, 0x06, 0x06, 0x0d, 0xfa, 0xfb, 0x02, 0xfd, + 0xf4, 0xff, 0x0a, 0x00, 0xf8, 0xf8, 0xf8, 0xfd, 0x0a, 0xf9, 0xf1, 0xfc, + 0xfa, 0xf9, 0xfe, 0xf9, 0xfa, 0xfc, 0xfb, 0xf6, 0xef, 0xff, 0x00, 0xfd, + 0xf9, 0xfa, 0xfe, 0xf7, 0xf1, 0xf5, 0xf9, 0xfb, 0xff, 0xf8, 0xfa, 0x03, + 0x00, 0xed, 0xf7, 0xf5, 0xff, 0x04, 0xf4, 0xff, 0xff, 0xfb, 0xf5, 0xf9, + 0xf0, 0xf7, 0xfb, 0xf9, 0x0b, 0x04, 0xf3, 0xfa, 0xfc, 0xfb, 0xf0, 0xfd, + 0x0c, 0x01, 0xfa, 0xf0, 0xff, 0x04, 0xfd, 0xfa, 0xf8, 0xfb, 0xfe, 0x0a, + 0x0a, 0x04, 0xf4, 0xfa, 0xff, 0xff, 0x03, 0x02, 0xf7, 0x0d, 0x0c, 0xec, + 0xfd, 0x18, 0xf8, 0xf5, 0x11, 0x06, 0xf4, 0x03, 0x04, 0x02, 0x0a, 0x02, + 0xfd, 0xfd, 0xf6, 0xf7, 0x01, 0x09, 0x0a, 0x05, 0xfa, 0xf6, 0x05, 0x02, + 0x06, 0xf6, 0xfd, 0x04, 0x00, 0xf6, 0x02, 0x04, 0x01, 0xfe, 0xff, 0xfb, + 0xf9, 0xf9, 0xf8, 0xfa, 0xff, 0x06, 0xfe, 0xff, 0x01, 0xfc, 0xf8, 0xf5, + 0xfe, 0x00, 0x06, 0x00, 0xf3, 0xff, 0x01, 0xf5, 0x07, 0x04, 0xf4, 0xff, + 0x00, 0x00, 0xfb, 0xfd, 0x00, 0xff, 0xf2, 0xf9, 0x0c, 0x05, 0x03, 0x08, + 0xf6, 0xfd, 0x02, 0xfc, 0xfe, 0x06, 0x00, 0xf1, 0x09, 0x0c, 0xfc, 0xfa, + 0xf9, 0x03, 0x03, 0x01, 0xf8, 0xf5, 0x0a, 0x0b, 0xf6, 0xf5, 0x06, 0x05, + 0xf3, 0xff, 0x09, 0xfa, 0xff, 0x01, 0xfb, 0x09, 0x08, 0xfe, 0xfa, 0xf5, + 0xff, 0x04, 0xfe, 0xff, 0x06, 0xfa, 0xf9, 0x05, 0x02, 0xfe, 0xf8, 0xfa, + 0x07, 0x06, 0xfa, 0xf4, 0xfd, 0x03, 0xff, 0xf4, 0xf9, 0x0a, 0x04, 0xee, + 0xfd, 0x06, 0x00, 0xfa, 0xfa, 0xed, 0xff, 0x10, 0x04, 0xf4, 0xed, 0xff, + 0x0b, 0x02, 0xf8, 0xf7, 0x01, 0x06, 0x00, 0xfb, 0x09, 0x05, 0x02, 0x05, + 0xfa, 0x00, 0xfe, 0x06, 0x05, 0x0b, 0x08, 0x00, 0xf9, 0x0a, 0x0e, 0x00, + 0x02, 0x0c, 0x00, 0xf7, 0x13, 0x0a, 0x04, 0x06, 0x05, 0xfb, 0xff, 0x06, + 0x10, 0x04, 0xf8, 0xf4, 0xff, 0x0e, 0x04, 0x00, 0xfd, 0xf7, 0x07, 0x06, + 0xf6, 0xfa, 0x0b, 0xfc, 0xff, 0x05, 0xf6, 0xf9, 0x05, 0x05, 0x02, 0xf3, + 0xff, 0x02, 0xf3, 0x07, 0x04, 0xfb, 0xfd, 0x05, 0xfd, 0xf6, 0xf4, 0xfa, + 0xff, 0x08, 0xfc, 0xfb, 0x06, 0x05, 0xf8, 0xff, 0xf8, 0xf2, 0xff, 0x04, + 0xfe, 0x03, 0x03, 0x00, 0xf7, 0xfe, 0xfa, 0xf9, 0x05, 0x04, 0xf7, 0x05, + 0x05, 0xf6, 0xfa, 0x0b, 0x10, 0xfc, 0xff, 0x04, 0x02, 0x06, 0xfa, 0xfb, + 0x0b, 0x02, 0x00, 0xf5, 0x03, 0x10, 0x08, 0x05, 0xfc, 0xff, 0x12, 0x04, + 0x00, 0xf6, 0x05, 0x14, 0x08, 0x06, 0x04, 0xfb, 0x02, 0x03, 0x00, 0xfe, + 0x17, 0x10, 0xfc, 0x09, 0x04, 0xff, 0x03, 0x01, 0xf9, 0xff, 0x03, 0x01, + 0x07, 0x04, 0x07, 0x08, 0xf9, 0xf5, 0xfb, 0x04, 0x00, 0x09, 0x05, 0xf0, + 0x0f, 0x10, 0xf8, 0xf8, 0xf6, 0xff, 0x02, 0x01, 0x00, 0xfb, 0x05, 0x06, + 0xf6, 0xf1, 0xfc, 0xff, 0x07, 0x06, 0xff, 0xfb, 0xfc, 0xfd, 0x02, 0xf8, + 0xf5, 0x06, 0x04, 0xf1, 0xff, 0x0a, 0xf2, 0xee, 0x0b, 0x08, 0xfd, 0xfe, + 0xf6, 0x05, 0x07, 0xfa, 0xfd, 0xfe, 0xf7, 0xff, 0xf4, 0xf5, 0x03, 0x0b, + 0x00, 0xf3, 0x0e, 0x08, 0xf9, 0x01, 0xfe, 0x06, 0xfa, 0xf5, 0xfe, 0x02, + 0x00, 0xf7, 0xff, 0x03, 0x0b, 0x03, 0x02, 0x01, 0x02, 0xfc, 0xf9, 0x09, + 0x05, 0xf8, 0xfe, 0x04, 0xfd, 0xfe, 0xff, 0x07, 0x0e, 0xf8, 0xfb, 0x0c, + 0x03, 0x01, 0xf5, 0xff, 0x0a, 0xf8, 0xf7, 0x04, 0x00, 0xfb, 0x05, 0x01, + 0xf9, 0xfb, 0xfe, 0xf9, 0xfc, 0xfe, 0x04, 0x00, 0xf5, 0xfb, 0x00, 0xfb, + 0x07, 0x00, 0xf0, 0xed, 0x09, 0x02, 0xfb, 0x0d, 0x00, 0xf7, 0x04, 0xfc, + 0xf6, 0xf5, 0x02, 0x00, 0xfe, 0xfd, 0xf9, 0xf5, 0x05, 0x07, 0xf8, 0xf7, + 0x04, 0x02, 0x02, 0xfc, 0xf7, 0x00, 0x01, 0xfc, 0xf5, 0xfd, 0x06, 0x00, + 0xf6, 0xf7, 0x0a, 0x05, 0xf8, 0xfd, 0x0a, 0x06, 0xfd, 0x06, 0x08, 0xf4, + 0xfc, 0x01, 0x0a, 0x00, 0xf7, 0x06, 0x00, 0xfa, 0xfc, 0x00, 0xfc, 0xfe, + 0x05, 0xfe, 0x02, 0x00, 0xff, 0x0a, 0xf5, 0xff, 0x01, 0xf8, 0xf8, 0xf8, + 0x02, 0xff, 0x05, 0xfd, 0x01, 0xf3, 0x05, 0x00, 0xf6, 0xff, 0x00, 0x05, + 0x02, 0xfd, 0x00, 0xf3, 0xfb, 0x09, 0x02, 0xf2, 0xef, 0x05, 0x00, 0xfb, + 0x02, 0xfb, 0xfc, 0xfd, 0xf5, 0xf3, 0xfd, 0x02, 0x02, 0x00, 0xf0, 0xeb, + 0x0e, 0x04, 0xf6, 0xfe, 0xf4, 0xf5, 0x00, 0xf8, 0xfb, 0x05, 0x00, 0xea, + 0xf7, 0xff, 0xfc, 0xf0, 0xef, 0x09, 0x0a, 0xf0, 0xf7, 0x05, 0xfa, 0xfd, + 0x00, 0xf3, 0xfa, 0xf5, 0xfa, 0xfe, 0xfc, 0x04, 0x08, 0xfa, 0xfb, 0x03, + 0xfa, 0xfa, 0xf5, 0x05, 0x02, 0xff, 0xf4, 0xff, 0x08, 0xff, 0x01, 0x03, + 0xf9, 0xfc, 0xfe, 0xfe, 0x06, 0xfa, 0xf3, 0xf9, 0x08, 0x04, 0xfe, 0xfb, + 0xfc, 0xf7, 0x05, 0xfc, 0xf2, 0x03, 0x00, 0xfe, 0xfe, 0xf4, 0xf0, 0xf9, + 0x04, 0xee, 0xff, 0x12, 0xf8, 0xe7, 0x0a, 0x02, 0xf2, 0x07, 0x06, 0xf2, + 0xf7, 0x04, 0x04, 0x00, 0xf0, 0xff, 0x08, 0x00, 0xf8, 0xef, 0xff, 0x05, + 0x01, 0x0b, 0x04, 0xfc, 0xf0, 0xef, 0xff, 0x0b, 0x06, 0xfc, 0xf5, 0x03, + 0x06, 0x00, 0xf1, 0xfe, 0x06, 0x01, 0xfc, 0xf7, 0xff, 0xff, 0x00, 0x03, + 0x04, 0xf8, 0xf6, 0xff, 0x00, 0xfa, 0xfd, 0xfa, 0x06, 0x00, 0xff, 0x03, + 0x00, 0xf5, 0x06, 0x00, 0xfb, 0x04, 0xf8, 0xff, 0x01, 0xfd, 0x04, 0xf6, + 0xff, 0x06, 0xfd, 0x01, 0xfb, 0xf7, 0xfb, 0x00, 0xf8, 0xf2, 0xff, 0x0a, + 0x02, 0xf3, 0xf5, 0x0d, 0x0b, 0xf9, 0xff, 0x03, 0xfd, 0xff, 0x06, 0x02, + 0xf6, 0xff, 0x04, 0xf8, 0x0e, 0x08, 0xfc, 0xfa, 0x06, 0xfe, 0x05, 0x06, + 0x00, 0xf9, 0xfa, 0x02, 0x06, 0xfe, 0x02, 0x0b, 0x00, 0xee, 0x0e, 0x0f, + 0xfd, 0xfd, 0xf8, 0x05, 0x05, 0xf8, 0x0c, 0x00, 0xf6, 0x00, 0x0d, 0x01, + 0x00, 0x02, 0x00, 0xfe, 0xf7, 0xfe, 0x09, 0x00, 0xfb, 0x0a, 0x09, 0xf3, + 0xf4, 0x0c, 0x0b, 0xfc, 0x04, 0x00, 0xfb, 0xfd, 0x01, 0x01, 0xfa, 0xfc, + 0x03, 0x05, 0x00, 0xfd, 0xfd, 0x00, 0x00, 0xf4, 0x00, 0x07, 0x00, 0xfd, + 0x03, 0xfd, 0xfa, 0xfb, 0xf8, 0xfc, 0x05, 0x05, 0xfd, 0xf9, 0x05, 0x00, + 0xf9, 0xff, 0xfb, 0x00, 0x05, 0xfd, 0xf7, 0x01, 0x00, 0x00, 0xfd, 0xfc, + 0x01, 0x00, 0xfa, 0xfb, 0x00, 0xfc, 0x04, 0x04, 0x05, 0x03, 0xfd, 0xf8, + 0x00, 0x05, 0xfd, 0x00, 0x03, 0x01, 0x02, 0xfe, 0xfe, 0x00, 0xf6, 0xfd, + 0x07, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0xfe, 0x00, 0x02, 0x00, 0xfe, + 0x02, 0xfe, 0x00, 0x0d, 0x04, 0x00, 0xf9, 0xfb, 0x01, 0x08, 0x07, 0x04, + 0x00, 0xf7, 0xfd, 0x04, 0x04, 0x00, 0x02, 0xfa, 0x00, 0x06, 0x02, 0xfe, + 0xfa, 0x03, 0x05, 0xfe, 0xfc, 0x05, 0x00, 0xfb, 0x03, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x01, 0xfd, 0x00, 0x05, 0x00, 0xff, 0x01, 0x03, 0x05, 0x00, + 0x00, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x01, 0x02, 0x04, 0x00, 0x00, 0xfe, + 0x02, 0x07, 0x00, 0xf9, 0xfe, 0x01, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x06, 0x05, 0xfe, 0xfd, 0xfe, 0x01, 0x02, 0x01, 0x02, 0x02, + 0xfb, 0xfa, 0xfe, 0x01, 0x01, 0x04, 0xfd, 0xfe, 0x03, 0x01, 0xfc, 0xfe, + 0x01, 0x01, 0x00, 0xf9, 0x01, 0x01, 0xfe, 0xfd, 0x00, 0xfd, 0x00, 0x06, + 0x00, 0xf8, 0x02, 0x00, 0xfc, 0x03, 0x00, 0xfe, 0xfd, 0xff, 0xff, 0x01, + 0x00, 0x02, 0xfd, 0xfa, 0xfe, 0x03, 0x05, 0x00, 0xfd, 0x00, 0x00, 0xfd, + 0xfc, 0x01, 0x04, 0x00, 0xfe, 0x03, 0x00, 0xfe, 0x04, 0x01, 0xfe, 0xfe, + 0xff, 0x00, 0x04, 0x00, 0xff, 0xfd, 0x01, 0x02, 0xfe, 0xff, 0xfd, 0x03, + 0x03, 0x00, 0xfd, 0xff, 0x03, 0x00, 0x01, 0xfe, 0xfd, 0xfe, 0x01, 0xff, + 0x00, 0x02, 0xfe, 0xfd, 0x03, 0x00, 0xff, 0xfd, 0xfd, 0x02, 0x00, 0xfe, + 0xfd, 0x00, 0x02, 0xfd, 0x00, 0x01, 0xfd, 0xfe, 0x04, 0x00, 0xff, 0x00, + 0x00, 0x00, 0xff, 0xfe, 0xff, 0xfe, 0xfd, 0x01, 0x02, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0xfd, 0xff, 0x01, 0xff, 0x01, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, + 0x01, 0x01, 0xff, 0xff, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, + 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x00, 0xff, 0x01, 0x01, 0xff, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xf4, 0xf6, 0x03, 0x30, 0x32, 0x07, 0xca, + 0xba, 0xfd, 0x20, 0x54, 0x20, 0x01, 0xc9, 0x1b, 0x01, 0xf4, 0x36, 0x20, + 0x54, 0x3b, 0xf2, 0xc9, 0xa3, 0x03, 0x48, 0x49, 0xfd, 0xc1, 0xb3, 0x09, + 0x27, 0x42, 0x0c, 0x03, 0xa3, 0xf4, 0x27, 0x5b, 0xf6, 0xf6, 0xe4, 0x0c, + 0x07, 0x46, 0x44, 0x0e, 0xdc, 0x1c, 0xdb, 0xf9, 0x22, 0xd5, 0xce, 0xcc, + 0xfb, 0xf6, 0x1b, 0xe4, 0xcc, 0xf7, 0xe7, 0xf0, 0xee, 0xd9, 0xcc, 0xd2, + 0xf0, 0x1c, 0xdc, 0xf9, 0xed, 0x09, 0xdb, 0x1b, 0xe4, 0xb1, 0xbe, 0x19, + 0xed, 0xca, 0xff, 0xbe, 0xa1, 0x9f, 0x8f, 0x80, 0xd3, 0x13, 0x0c, 0xcc, + 0xd9, 0xdb, 0xf9, 0x05, 0xf7, 0xd2, 0xce, 0xc3, 0xba, 0xeb, 0xc1, 0xfd, + 0x07, 0xcc, 0xd5, 0xc1, 0x10, 0xd7, 0x17, 0x19, 0x05, 0xd2, 0x03, 0x2e, + 0xe0, 0xf6, 0x13, 0x15, 0x09, 0x22, 0xe5, 0x29, 0x1e, 0x10, 0xf4, 0x1c, + 0x03, 0x22, 0xf6, 0x1c, 0xf2, 0x2e, 0x32, 0x29, 0x07, 0x0a, 0x01, 0x22, + 0x10, 0x1e, 0x15, 0x1b, 0x34, 0x4d, 0x52, 0x49, 0x2d, 0x5b, 0x1b, 0x48, + 0x05, 0x48, 0x37, 0x4f, 0x36, 0x1c, 0x30, 0x30, 0x30, 0x5b, 0x20, 0x2e, + 0x03, 0x42, 0xff, 0x37, 0x42, 0x39, 0x49, 0x27, 0x13, 0x0a, 0x44, 0x34, + 0x58, 0x0a, 0x20, 0x4d, 0x1e, 0x3b, 0x00, 0x10, 0x49, 0x42, 0x03, 0xfb, + 0x0e, 0x3d, 0x20, 0x19, 0x1b, 0xdc, 0x1c, 0x29, 0x1c, 0xf4, 0x22, 0x05, + 0xdc, 0x0c, 0x2e, 0x24, 0x03, 0xe9, 0xc1, 0x01, 0xc9, 0x22, 0x1b, 0xe5, + 0xb3, 0xd7, 0x07, 0xf0, 0xc9, 0xde, 0xcc, 0x03, 0xf4, 0x00, 0xd5, 0x05, + 0xcc, 0xd0, 0xe7, 0xc1, 0xd0, 0xd9, 0xe9, 0xc5, 0xce, 0xd0, 0xb3, 0xca, + 0xc9, 0xca, 0xc0, 0xe9, 0xce, 0x9f, 0x9a, 0xd0, 0xbe, 0xbc, 0xc3, 0xbc, + 0x98, 0xb3, 0xca, 0xd2, 0xaf, 0xcc, 0xa8, 0xcc, 0xc7, 0xc7, 0xbc, 0xc5, + 0xd0, 0xb1, 0xb1, 0xd2, 0xe0, 0xeb, 0xee, 0xbc, 0xca, 0xa5, 0xd5, 0xf6, + 0x09, 0xe4, 0xd0, 0xd9, 0x00, 0xe0, 0xd5, 0xe0, 0xee, 0xf7, 0xd9, 0xf7, + 0xe4, 0xe0, 0xfb, 0xbe, 0xc0, 0x05, 0x17, 0xe7, 0xcc, 0xde, 0xdc, 0xce, + 0xf7, 0x0e, 0x00, 0xed, 0x01, 0xed, 0xf0, 0x0a, 0x07, 0xfb, 0x09, 0xfb, + 0x0a, 0x05, 0x20, 0x1c, 0x07, 0xf4, 0x09, 0x0c, 0x39, 0x27, 0xf2, 0xfb, + 0x1b, 0x3f, 0x2b, 0x42, 0x24, 0x29, 0x17, 0x4b, 0x32, 0x1b, 0x27, 0x51, + 0x48, 0x3b, 0x36, 0x39, 0x2e, 0x27, 0x15, 0x29, 0x3f, 0x5a, 0x2b, 0x22, + 0x25, 0x1e, 0x32, 0x42, 0x2d, 0x05, 0x20, 0x13, 0x22, 0x32, 0x13, 0x03, + 0x15, 0x15, 0x2b, 0x1b, 0x13, 0x1c, 0x27, 0x1b, 0x42, 0x34, 0x27, 0x2e, + 0x2e, 0xed, 0x1c, 0x3b, 0x30, 0x29, 0x3b, 0x32, 0x24, 0x22, 0x2b, 0x07, + 0x1e, 0x39, 0x30, 0x2d, 0x46, 0x40, 0x29, 0x24, 0x32, 0x2d, 0x19, 0x19, + 0x20, 0x1b, 0x17, 0x0c, 0xfb, 0x05, 0x10, 0x00, 0xff, 0x0a, 0xde, 0xfd, + 0x05, 0x0c, 0xee, 0x0c, 0x0c, 0xeb, 0x15, 0x2e, 0x03, 0xdc, 0xe9, 0x0a, + 0x00, 0x24, 0x24, 0xf9, 0x05, 0xff, 0xe2, 0xff, 0x27, 0x22, 0xeb, 0xf9, + 0x2d, 0x0c, 0xf7, 0xeb, 0xe5, 0xfb, 0x13, 0xf0, 0xde, 0xed, 0xe2, 0xca, + 0xce, 0xe7, 0x01, 0x19, 0xfb, 0xc5, 0xaf, 0xe0, 0xee, 0xcc, 0xd0, 0xeb, + 0xfd, 0xf7, 0xdc, 0xc3, 0xac, 0xd0, 0xf2, 0xde, 0xd2, 0xe7, 0xbe, 0xa1, + 0xc0, 0xdb, 0xd9, 0xde, 0xe0, 0xb3, 0x9c, 0xc5, 0xdc, 0xdb, 0xc9, 0xcc, + 0xb8, 0xcc, 0xe9, 0xee, 0xc9, 0xb3, 0xb7, 0xba, 0xc0, 0xdc, 0xf7, 0xd9, + 0xc9, 0xcc, 0xc3, 0xb3, 0xdb, 0xeb, 0xe5, 0xdb, 0xd3, 0xc9, 0xc5, 0xee, + 0xf6, 0xe9, 0xe2, 0xcc, 0xba, 0xd9, 0x03, 0xe5, 0xbc, 0xb8, 0xd3, 0x09, + 0x01, 0xca, 0xb1, 0xd5, 0xf2, 0xd0, 0xce, 0xdc, 0xd9, 0xf2, 0x03, 0xd9, + 0xc5, 0x00, 0x0e, 0x05, 0xf4, 0x07, 0x05, 0xfb, 0x0a, 0x05, 0xf0, 0x03, + 0x24, 0x24, 0x09, 0xed, 0xee, 0x05, 0x1b, 0x10, 0x17, 0x1e, 0x10, 0xfd, + 0x19, 0x13, 0xff, 0x22, 0x20, 0x01, 0x17, 0x2e, 0x1b, 0x05, 0x05, 0xf4, + 0xf6, 0x00, 0x17, 0x17, 0x07, 0x0a, 0x03, 0x0e, 0x22, 0x34, 0x29, 0x01, + 0x15, 0x37, 0x46, 0x44, 0x37, 0x25, 0x2e, 0x3b, 0x22, 0x17, 0x1c, 0x0e, + 0x22, 0x3b, 0xf9, 0x00, 0x3d, 0x46, 0x0a, 0xf0, 0x15, 0x1e, 0x30, 0x4d, + 0x24, 0x0a, 0x27, 0x34, 0x13, 0x17, 0x42, 0x37, 0x29, 0x29, 0x25, 0x1e, + 0x20, 0x29, 0x19, 0x00, 0x01, 0x10, 0x39, 0x3f, 0x19, 0xfd, 0x39, 0x4d, + 0x27, 0x10, 0x17, 0x24, 0x01, 0xfd, 0x03, 0x12, 0x24, 0x20, 0x17, 0x1b, + 0x0c, 0xeb, 0xf4, 0x17, 0x24, 0x0c, 0x13, 0x27, 0xf7, 0xeb, 0x17, 0x2e, + 0x0a, 0x0c, 0x29, 0x0a, 0x01, 0x17, 0x34, 0x27, 0x13, 0xf7, 0xee, 0x15, + 0x24, 0x0e, 0x13, 0x07, 0xeb, 0xee, 0xff, 0xff, 0x12, 0xfd, 0x00, 0xf9, + 0xd3, 0xde, 0x00, 0x1b, 0x13, 0xe0, 0xd2, 0xdc, 0xe4, 0x09, 0x0c, 0xcc, + 0xc5, 0x01, 0x1b, 0x12, 0xe0, 0xc5, 0xc5, 0xe0, 0xeb, 0xf6, 0x03, 0xed, + 0xe5, 0x19, 0xf4, 0xc9, 0xee, 0x2e, 0x03, 0xe2, 0xd5, 0xd0, 0xe2, 0xff, + 0xfd, 0xe0, 0xe5, 0xe9, 0xed, 0xf9, 0xe2, 0xba, 0xaf, 0xcc, 0xf4, 0x05, + 0xfd, 0xcc, 0xb1, 0xd3, 0x03, 0x01, 0xce, 0xb8, 0xe9, 0xe0, 0xf0, 0xf6, + 0xb3, 0xb5, 0xe7, 0xff, 0x07, 0xe5, 0xd5, 0xd0, 0xf2, 0x17, 0xf2, 0xe4, + 0xf2, 0xfd, 0xdb, 0xd7, 0xde, 0xc5, 0xbe, 0xf2, 0x01, 0xe2, 0xe7, 0x1b, + 0xe2, 0xcc, 0xfb, 0xff, 0xba, 0xca, 0xff, 0x17, 0x03, 0xce, 0xc5, 0xf0, + 0x19, 0x09, 0xeb, 0xcc, 0xcc, 0xfb, 0x1b, 0x12, 0xd9, 0xd3, 0x19, 0x17, + 0xe0, 0xc3, 0xd7, 0x09, 0x1b, 0x05, 0xce, 0xd2, 0xf2, 0x13, 0x24, 0x07, + 0xcc, 0xd3, 0x05, 0xfd, 0xd7, 0x2e, 0x17, 0xdc, 0xee, 0x1b, 0xf0, 0x05, + 0x0a, 0xe7, 0x00, 0x05, 0xe7, 0xfd, 0x07, 0x1c, 0xfd, 0xd9, 0xd5, 0xf7, + 0x1b, 0x29, 0x1c, 0xe7, 0xd2, 0xe9, 0x29, 0x36, 0x0e, 0xf0, 0x0c, 0xff, + 0xe9, 0xe0, 0xe7, 0x01, 0x24, 0x27, 0xf4, 0xce, 0xe4, 0x05, 0x1e, 0x2b, + 0x03, 0xd5, 0xe5, 0x1e, 0x36, 0x19, 0xee, 0xde, 0xe2, 0x1b, 0x2d, 0x12, + 0x00, 0xde, 0xd9, 0x10, 0x24, 0x01, 0x00, 0x1e, 0x0e, 0x01, 0xfb, 0xd3, + 0xf2, 0x27, 0x34, 0x1b, 0xff, 0x05, 0xe9, 0xf9, 0x15, 0xf6, 0xf6, 0x34, + 0x29, 0xe5, 0xd0, 0x03, 0x12, 0x12, 0x39, 0x0c, 0xdb, 0xff, 0x40, 0x3d, + 0x0e, 0xe5, 0xe4, 0x0a, 0x3d, 0x2d, 0x0e, 0xf0, 0xd9, 0xfb, 0x20, 0x30, + 0x39, 0x13, 0xfb, 0xed, 0x12, 0x2b, 0x10, 0xfb, 0x1b, 0x39, 0x03, 0xfd, + 0x0e, 0x01, 0x1c, 0x0c, 0xd7, 0xf4, 0x1c, 0x25, 0x22, 0x10, 0xe4, 0x01, + 0x39, 0x42, 0x12, 0xed, 0xf2, 0x03, 0x10, 0x2d, 0x15, 0x0a, 0x15, 0xf6, + 0x15, 0x3f, 0xfd, 0xd9, 0x01, 0x2b, 0x1e, 0x07, 0x29, 0x19, 0x09, 0x51, + 0x20, 0xf7, 0xf0, 0x20, 0x3f, 0x30, 0x1b, 0x07, 0xfd, 0x07, 0x24, 0xf0, + 0xe4, 0x0e, 0x24, 0x2e, 0x01, 0xdb, 0x0a, 0x2e, 0x3d, 0x2d, 0xfb, 0xe7, + 0xf4, 0x27, 0x3d, 0x0c, 0xdb, 0x13, 0x22, 0x12, 0x40, 0x25, 0xee, 0xf7, + 0x3b, 0x13, 0xeb, 0x37, 0x46, 0x19, 0x09, 0x05, 0xee, 0xf0, 0x25, 0x36, + 0xf7, 0xd5, 0xee, 0x0c, 0x12, 0x22, 0x24, 0xf0, 0xd5, 0xee, 0x24, 0x22, + 0xe9, 0xd0, 0xfb, 0xff, 0xff, 0x2b, 0x15, 0xe0, 0xce, 0x07, 0x15, 0xd3, + 0x01, 0x2d, 0x0e, 0xf4, 0xed, 0xdc, 0xde, 0x10, 0x25, 0x17, 0xf4, 0xe9, + 0xd9, 0xdc, 0x00, 0x01, 0xd9, 0xc7, 0x05, 0x0e, 0xce, 0xb3, 0xcc, 0xed, + 0x03, 0x12, 0xe9, 0xba, 0xcc, 0x07, 0x15, 0xe4, 0xb7, 0xcc, 0xf9, 0x0e, + 0xf6, 0xc7, 0xaf, 0xc0, 0xf9, 0x03, 0xd0, 0xb7, 0x03, 0xfd, 0xc7, 0xae, + 0xd3, 0x00, 0x09, 0xfd, 0xcc, 0xb8, 0xce, 0x0a, 0x13, 0xe7, 0xca, 0xcc, + 0xc5, 0xd2, 0x01, 0x03, 0xcc, 0xae, 0xc0, 0xe4, 0xf2, 0xee, 0xf0, 0xd5, + 0xba, 0xdc, 0x0e, 0xee, 0xb1, 0xd7, 0x19, 0xfb, 0xcc, 0xc7, 0xd2, 0xd0, + 0xf4, 0x0e, 0xde, 0xae, 0xd9, 0xff, 0x07, 0xf6, 0xce, 0xde, 0x13, 0x17, + 0xee, 0xd2, 0xed, 0xf7, 0xd7, 0x0a, 0x0a, 0xd5, 0xdb, 0xf9, 0xf2, 0xd2, + 0xb7, 0xd9, 0xfb, 0x0c, 0x10, 0xf2, 0xd5, 0xc5, 0xff, 0x22, 0x0e, 0xdc, + 0xc0, 0xe0, 0x20, 0x1b, 0xee, 0xcc, 0xde, 0x01, 0x1e, 0xfb, 0xc9, 0xe5, + 0x1e, 0x17, 0xd9, 0xc3, 0xf7, 0x29, 0x22, 0xff, 0xd9, 0xd0, 0xeb, 0x17, + 0x25, 0x12, 0xdc, 0xce, 0xd3, 0x00, 0x07, 0x03, 0x19, 0x1c, 0xe2, 0xdb, + 0x05, 0x25, 0xf6, 0xd2, 0x03, 0x2d, 0x00, 0xee, 0x12, 0x12, 0x13, 0x17, + 0x03, 0xd9, 0xf9, 0x32, 0x1b, 0xe2, 0xd5, 0x09, 0x37, 0x2b, 0xff, 0xe4, + 0xe9, 0xfd, 0xf9, 0x27, 0x1e, 0xe4, 0xfb, 0x3f, 0x1e, 0xe9, 0xdb, 0xf6, + 0x25, 0x32, 0x27, 0xfb, 0xe4, 0xee, 0x20, 0x39, 0x36, 0x15, 0x0e, 0xee, + 0xe5, 0x13, 0x40, 0x1e, 0xf6, 0x15, 0x32, 0xfd, 0xee, 0x22, 0x42, 0x07, + 0xd9, 0xf2, 0x27, 0x40, 0x3d, 0x0c, 0xeb, 0xf2, 0x15, 0x46, 0x3b, 0x19, + 0xee, 0xf2, 0x24, 0x49, 0x15, 0xeb, 0x20, 0x40, 0x05, 0xe4, 0x07, 0x29, + 0x39, 0x3b, 0x0c, 0xe7, 0x07, 0x3d, 0x3f, 0x1b, 0x1b, 0x20, 0xe4, 0x17, + 0x46, 0x46, 0x19, 0x01, 0xf9, 0xf9, 0x05, 0x1e, 0x3f, 0x24, 0xe9, 0x07, + 0x17, 0x13, 0x39, 0x2e, 0x19, 0x1b, 0xfb, 0xee, 0x22, 0x3f, 0x42, 0x17, + 0xf4, 0xfb, 0x2d, 0x4b, 0x19, 0xee, 0xf9, 0x2b, 0x12, 0xf2, 0x2e, 0x49, + 0x24, 0xf7, 0xeb, 0xfd, 0x2b, 0x00, 0xe2, 0x1c, 0x3d, 0x17, 0xdc, 0xde, + 0xf9, 0x1e, 0x32, 0x12, 0xd9, 0xd7, 0x05, 0x2b, 0x2d, 0x07, 0xd9, 0x03, + 0x29, 0xe9, 0xd9, 0x20, 0x39, 0x1c, 0xf2, 0xe2, 0xf2, 0x27, 0x25, 0xf2, + 0xd0, 0xde, 0x0e, 0x20, 0x1c, 0x17, 0xee, 0xd7, 0xf0, 0x34, 0x1c, 0xe2, + 0xe5, 0xfb, 0xcc, 0xe2, 0x00, 0x09, 0x15, 0x07, 0xd0, 0xc7, 0x01, 0x20, + 0x05, 0xeb, 0x25, 0x09, 0xca, 0xe2, 0x01, 0x20, 0x29, 0xf7, 0xd5, 0xe4, + 0x25, 0xfd, 0xce, 0x13, 0xf4, 0xb3, 0xe5, 0x05, 0x09, 0x1b, 0xeb, 0xc1, + 0xf6, 0x09, 0xce, 0x0a, 0x20, 0xee, 0xc0, 0xd9, 0x0e, 0x15, 0x0a, 0x00, + 0xe2, 0xd0, 0xca, 0xf4, 0xf4, 0xfd, 0x22, 0xee, 0xc5, 0xd0, 0xfd, 0x1c, + 0xee, 0xc1, 0xeb, 0x17, 0xd9, 0xb3, 0xdc, 0x0c, 0xfd, 0xf0, 0xf9, 0xc1, + 0xce, 0x00, 0x17, 0xeb, 0xb8, 0xce, 0xf2, 0xfb, 0x13, 0x01, 0xd7, 0xde, + 0xe5, 0xbe, 0xf4, 0x17, 0x0e, 0xe5, 0xdb, 0xce, 0xbe, 0xeb, 0x0e, 0x13, + 0xee, 0xc9, 0xcc, 0xc9, 0xf2, 0x17, 0x07, 0xd5, 0xba, 0xcc, 0x01, 0x07, + 0xe7, 0xce, 0xae, 0xd0, 0xfb, 0x0c, 0xee, 0xb5, 0xd7, 0x15, 0xf2, 0xb3, + 0xd0, 0x0e, 0x19, 0xff, 0xd5, 0xcc, 0xc7, 0xfd, 0x1e, 0xf2, 0xbc, 0xc3, + 0xe0, 0x07, 0x12, 0xdc, 0xbe, 0x01, 0x13, 0xdc, 0xf6, 0x12, 0xc9, 0xc5, + 0xff, 0x1e, 0xf7, 0xde, 0x0e, 0x09, 0xde, 0xee, 0xf9, 0xd7, 0xe0, 0x0c, + 0x20, 0xf4, 0xc5, 0xde, 0x15, 0x24, 0xf2, 0xcc, 0xd3, 0xe9, 0x00, 0x09, + 0xe0, 0xe7, 0x20, 0x15, 0xed, 0xc9, 0xd3, 0x03, 0x1b, 0x1e, 0xf7, 0xc9, + 0xd0, 0x03, 0x17, 0xf4, 0x30, 0x20, 0xe7, 0xd2, 0xe9, 0x15, 0x34, 0x19, + 0xeb, 0xe2, 0xed, 0xf9, 0xfb, 0x1c, 0x12, 0xe4, 0xd0, 0x01, 0x22, 0x2b, + 0x19, 0xf4, 0xdc, 0xee, 0x29, 0x36, 0x00, 0xd9, 0xd5, 0xff, 0x25, 0x2b, + 0x19, 0xff, 0x09, 0xe7, 0xf7, 0x3b, 0x1e, 0xe4, 0x05, 0x36, 0xe9, 0xe5, + 0x25, 0x37, 0xee, 0xd7, 0xf4, 0x0a, 0xf6, 0x0e, 0x2b, 0x12, 0xf9, 0x0e, + 0x25, 0xf7, 0x13, 0x27, 0xed, 0x0c, 0x17, 0x01, 0x27, 0x4d, 0x1b, 0x03, + 0xff, 0x13, 0x15, 0x34, 0x0e, 0xee, 0x19, 0x30, 0xf9, 0xe5, 0x15, 0x40, + 0x19, 0xe0, 0xe2, 0x12, 0x32, 0x37, 0x27, 0xf2, 0xfd, 0x05, 0x25, 0x3d, + 0xff, 0x01, 0x3d, 0x25, 0xf0, 0xf6, 0x3b, 0x25, 0xf0, 0x2d, 0x19, 0xe0, + 0x10, 0x3b, 0x2e, 0x12, 0x15, 0xff, 0x0c, 0x4d, 0x20, 0xf0, 0x15, 0x44, + 0x15, 0xfd, 0x39, 0x1b, 0xf2, 0x2e, 0x4b, 0x2d, 0x00, 0x01, 0x40, 0x34, + 0xf0, 0xf9, 0x07, 0x05, 0x22, 0x3d, 0x2d, 0xf4, 0xf9, 0x30, 0x3b, 0x01, + 0xe2, 0x10, 0x3b, 0x15, 0xfb, 0x44, 0x25, 0xed, 0x05, 0x19, 0x03, 0x2b, + 0x19, 0xe0, 0xfb, 0x19, 0x2d, 0x2e, 0x03, 0xde, 0x03, 0x36, 0x20, 0xe9, + 0xde, 0x09, 0x2e, 0x03, 0xe5, 0x34, 0x22, 0xe7, 0xfd, 0x0e, 0xcc, 0xfd, + 0x36, 0x10, 0xd7, 0xfd, 0xf2, 0x22, 0x2b, 0xff, 0xd7, 0xde, 0x15, 0x34, + 0x09, 0xd9, 0xd5, 0x07, 0x36, 0xf9, 0xcc, 0xdb, 0xf4, 0x07, 0x15, 0xd7, + 0xbc, 0xe5, 0x07, 0x07, 0xf4, 0xf0, 0xd3, 0xc1, 0xf6, 0x10, 0xe2, 0xb5, + 0xf4, 0x09, 0xeb, 0xdb, 0xfd, 0x1b, 0x0c, 0xed, 0xde, 0xc3, 0xd5, 0x03, + 0x12, 0x17, 0xed, 0xd2, 0xbe, 0xe0, 0x19, 0xff, 0xca, 0xc1, 0xf9, 0x1b, + 0xde, 0xaf, 0xe5, 0xf7, 0xb1, 0xf9, 0x07, 0xca, 0xdb, 0x15, 0xeb, 0xc9, + 0xf2, 0x20, 0xe7, 0xbc, 0xc9, 0xeb, 0xf0, 0x00, 0xe4, 0xbe, 0xfb, 0x17, + 0xf7, 0xce, 0xba, 0xd7, 0x0c, 0xfd, 0xe5, 0x09, 0xe9, 0xc5, 0xe2, 0xfd, + 0xd3, 0xc7, 0x0e, 0x01, 0xba, 0xd5, 0x15, 0x12, 0xe5, 0xba, 0xca, 0xf9, + 0x19, 0x13, 0xee, 0xd3, 0xe4, 0xf6, 0xce, 0xf2, 0x20, 0x05, 0xe9, 0xfb, + 0xd3, 0xee, 0x0a, 0xf4, 0xcc, 0xd3, 0x07, 0x24, 0xf9, 0xd7, 0x1c, 0x05, + 0xc1, 0xe0, 0x13, 0x27, 0x0a, 0xee, 0xe9, 0xd7, 0xe5, 0xf6, 0x09, 0x24, + 0xfd, 0xcc, 0xf4, 0x25, 0x09, 0xf4, 0x01, 0xeb, 0xe9, 0xf7, 0x07, 0x15, + 0x1c, 0xe5, 0xd3, 0xf4, 0x10, 0x20, 0x2d, 0x07, 0xe0, 0x01, 0x34, 0x07, + 0x03, 0x15, 0x10, 0xe9, 0xf4, 0x12, 0x05, 0xeb, 0x0c, 0xf6, 0xdb, 0x15, + 0x2b, 0x0a, 0xe4, 0xe5, 0x05, 0x30, 0x1b, 0xf4, 0xd9, 0xe4, 0x00, 0x09, + 0x27, 0x17, 0xde, 0xe4, 0x0e, 0x05, 0xf7, 0x25, 0x0a, 0xde, 0xdb, 0x09, + 0x2b, 0x2d, 0x03, 0xd5, 0xe2, 0x15, 0x2d, 0x1b, 0x09, 0x03, 0xe4, 0x05, + 0x27, 0xf0, 0xe2, 0x1b, 0x15, 0xe5, 0xdb, 0x0e, 0x24, 0xf7, 0xeb, 0x2e, + 0x15, 0xd9, 0xde, 0x0e, 0x2e, 0x20, 0xfd, 0xf0, 0xdb, 0xf4, 0x01, 0x17, + 0x17, 0xce, 0xd9, 0x0c, 0x1c, 0xe0, 0xf4, 0x15, 0x03, 0x0e, 0xd5, 0xee, + 0x2b, 0x2b, 0x07, 0xe4, 0xdc, 0xe9, 0x15, 0x29, 0x07, 0xd3, 0xd5, 0x09, + 0x30, 0x19, 0x00, 0xf0, 0xd7, 0x00, 0x20, 0x03, 0xe7, 0x27, 0x09, 0xe0, + 0x07, 0x20, 0xe5, 0x07, 0x2e, 0xfb, 0xdb, 0xe0, 0x19, 0x29, 0xff, 0xd7, + 0xf0, 0x24, 0xf0, 0xd5, 0x20, 0x19, 0xe4, 0xe0, 0x25, 0x10, 0xd7, 0xe2, + 0x1c, 0x36, 0x1e, 0xf6, 0xe2, 0xe9, 0xf4, 0xed, 0x25, 0x15, 0xdc, 0xed, + 0x32, 0x19, 0xd7, 0xdb, 0x1c, 0x29, 0xee, 0xd0, 0x00, 0x2b, 0x00, 0xd0, + 0x0c, 0x24, 0x00, 0xe0, 0xf6, 0x1e, 0x24, 0xf4, 0xd0, 0xf7, 0x2b, 0x34, + 0x20, 0xeb, 0xdb, 0xe5, 0x24, 0x30, 0x13, 0xde, 0x20, 0x3d, 0x00, 0xf2, + 0x13, 0xf6, 0xe9, 0x2d, 0x1b, 0xd7, 0xed, 0x2d, 0x24, 0xd5, 0xf7, 0x19, + 0x01, 0x34, 0xff, 0xd3, 0xfb, 0x34, 0x24, 0xe7, 0xdc, 0x25, 0x19, 0xd5, + 0x20, 0x2b, 0xe4, 0xe7, 0x2b, 0x3d, 0x17, 0xee, 0xde, 0x07, 0x34, 0xf7, + 0xf9, 0x30, 0x19, 0xd5, 0xed, 0x30, 0x3b, 0x0c, 0xe9, 0x13, 0x09, 0xf2, + 0x09, 0x36, 0x19, 0xe5, 0xdb, 0xf4, 0x2b, 0x32, 0x10, 0xe4, 0xdc, 0xe7, + 0x1c, 0x2b, 0x25, 0xf0, 0xdb, 0xde, 0x03, 0x07, 0xf6, 0x05, 0x15, 0xe2, + 0x12, 0x3b, 0xed, 0x00, 0x24, 0xdb, 0xd2, 0x05, 0x36, 0x2d, 0x01, 0xd9, + 0xd3, 0xf4, 0x24, 0x17, 0x00, 0x0c, 0xf6, 0xd7, 0x22, 0x27, 0xf0, 0xd2, + 0xff, 0x30, 0x2b, 0x00, 0xe7, 0xde, 0xe5, 0x05, 0x25, 0x20, 0xff, 0xde, + 0xd3, 0xd0, 0xf4, 0xfb, 0xf9, 0x19, 0x09, 0xe7, 0xdb, 0x05, 0x27, 0xff, + 0xd2, 0xd2, 0x09, 0x0a, 0xf2, 0x24, 0xed, 0xce, 0xc9, 0xf2, 0x19, 0x1e, + 0xfd, 0xc5, 0xc7, 0xf0, 0x0c, 0xfb, 0x12, 0x19, 0xed, 0xde, 0xf6, 0x00, + 0xd7, 0xf7, 0x24, 0xf7, 0xbe, 0xdb, 0x13, 0x20, 0x03, 0xee, 0xe4, 0xd3, + 0x05, 0x25, 0x0a, 0xdc, 0xd3, 0x01, 0x1c, 0xe9, 0xf9, 0x25, 0xe5, 0xd0, + 0x0a, 0x39, 0x0e, 0xe7, 0xe5, 0xd7, 0xe9, 0x07, 0x13, 0xf7, 0xfb, 0x01, + 0xc5, 0xe0, 0x10, 0x20, 0xe5, 0xbc, 0xe7, 0x19, 0x07, 0xc5, 0xde, 0x05, + 0x01, 0xed, 0xed, 0x13, 0xf7, 0xdc, 0x0e, 0x25, 0x0e, 0x03, 0xeb, 0x0a, + 0x30, 0xee, 0xde, 0x0e, 0x32, 0xf4, 0xe5, 0xe9, 0xf4, 0xf7, 0xf6, 0x17, + 0xdc, 0xc9, 0xf9, 0x1e, 0x0a, 0xc9, 0xc5, 0xf7, 0x1c, 0xf6, 0xbe, 0xfb, + 0x13, 0xf0, 0xfd, 0xf9, 0xc5, 0xfb, 0x20, 0xfb, 0xd0, 0xf0, 0x2e, 0xf6, + 0xc5, 0xf9, 0x17, 0xf6, 0xcc, 0xf7, 0x2e, 0xf9, 0xd2, 0xf2, 0x2b, 0x07, + 0xe0, 0xdc, 0xe4, 0x13, 0x12, 0xdc, 0xc0, 0xf0, 0x19, 0xfd, 0xf6, 0xfd, + 0xd5, 0xe7, 0x0e, 0x12, 0xd9, 0xd0, 0x10, 0xfb, 0xd0, 0x03, 0x17, 0xe2, + 0xf6, 0x22, 0xf7, 0xd5, 0xed, 0x24, 0x17, 0xe4, 0xfd, 0x1b, 0xdc, 0xd2, + 0x00, 0x24, 0x0a, 0xd9, 0xdb, 0x05, 0x22, 0x03, 0xe7, 0x05, 0xf0, 0xd3, + 0x10, 0x2d, 0x15, 0xeb, 0xee, 0xf2, 0xd5, 0xff, 0x1b, 0x24, 0x00, 0xe2, + 0xdc, 0xde, 0x0e, 0x2b, 0x1b, 0xe7, 0xce, 0xe7, 0x0e, 0x1e, 0x07, 0xf9, + 0x17, 0xf2, 0xe5, 0x1c, 0x2b, 0x00, 0xe5, 0x17, 0x22, 0xde, 0x0e, 0x3d, + 0x12, 0xeb, 0xe4, 0xf7, 0x15, 0xeb, 0x09, 0x32, 0x24, 0x0c, 0xe7, 0x07, + 0x3f, 0x12, 0xe2, 0x1e, 0x27, 0xe5, 0x0c, 0x32, 0x00, 0xdc, 0x10, 0x3b, + 0x1e, 0xff, 0x19, 0x12, 0xe4, 0x25, 0x46, 0x12, 0xe9, 0xe9, 0x01, 0x24, + 0x1c, 0xed, 0xf9, 0x36, 0x10, 0x24, 0x37, 0xfb, 0x0c, 0x42, 0x15, 0xe7, + 0xf7, 0x2b, 0x32, 0x0e, 0x1c, 0xf4, 0xdc, 0x0e, 0x42, 0x2d, 0xf2, 0xd5, + 0xf6, 0x2e, 0x36, 0x1b, 0xf4, 0xe2, 0xde, 0x0c, 0x1e, 0x17, 0x07, 0x1b, + 0xfd, 0xe0, 0x19, 0x34, 0x0c, 0x0a, 0x20, 0xe2, 0xeb, 0x24, 0x2e, 0xee, + 0xf4, 0x2b, 0xf6, 0xf0, 0x22, 0x2b, 0xfd, 0xd3, 0xdc, 0x0a, 0x1e, 0x15, + 0x10, 0xd7, 0xdc, 0x10, 0x32, 0x15, 0xe5, 0xed, 0xed, 0xfd, 0x25, 0xe5, + 0xd3, 0x09, 0x2e, 0xfd, 0xc7, 0xd2, 0x03, 0x24, 0x12, 0xf9, 0xe9, 0xc1, + 0xf4, 0x1e, 0x27, 0x0a, 0xd3, 0xdc, 0xeb, 0x0c, 0x27, 0x07, 0xe0, 0xee, + 0x25, 0x0c, 0xca, 0xf2, 0x1e, 0x00, 0xf9, 0x15, 0xfd, 0xe0, 0xd3, 0x0c, + 0x2b, 0xe2, 0xd5, 0x24, 0x20, 0xe2, 0xed, 0xe7, 0xfb, 0x2d, 0xf9, 0xca, + 0xe0, 0x13, 0xe9, 0xc9, 0x07, 0xfd, 0xed, 0x00, 0xf4, 0x05, 0x27, 0xf2, + 0xc1, 0xde, 0x1b, 0x2b, 0x1c, 0xf4, 0xd9, 0xde, 0x20, 0x32, 0x12, 0xe7, + 0xd7, 0xe2, 0x12, 0x29, 0x12, 0xd0, 0xf7, 0x0a, 0xd7, 0xd3, 0xff, 0x1c, + 0x17, 0xf2, 0xc3, 0xe9, 0x22, 0x27, 0x05, 0xd9, 0xd5, 0xee, 0x10, 0x22, + 0x1c, 0xe5, 0xc9, 0xe9, 0x24, 0x22, 0xf0, 0xc5, 0xe7, 0x05, 0xee, 0xe7, + 0x22, 0x15, 0xf2, 0x01, 0xfb, 0xde, 0xf9, 0x29, 0xf9, 0xd5, 0x17, 0xf9, + 0xce, 0x15, 0x20, 0xe2, 0xc7, 0xde, 0x12, 0x1c, 0xf4, 0x01, 0x0c, 0xc0, + 0xee, 0x15, 0xf6, 0xed, 0xf9, 0xf0, 0xf7, 0x25, 0xdc, 0xf0, 0x27, 0x12, + 0xd0, 0xdc, 0x1e, 0x10, 0xcc, 0x00, 0x2b, 0xe7, 0xc9, 0xfd, 0x03, 0x0a, + 0xff, 0xd7, 0xf6, 0x00, 0x2d, 0xff, 0xe2, 0xfb, 0x09, 0x2b, 0x10, 0xe9, + 0xed, 0xf0, 0xe5, 0x01, 0x0c, 0xd9, 0xf7, 0x17, 0x17, 0xe5, 0x03, 0x2b, + 0xdb, 0xd7, 0xf7, 0x15, 0x1c, 0x15, 0xe5, 0xce, 0x05, 0x32, 0x0a, 0xf4, + 0x20, 0xe9, 0xeb, 0x1c, 0xf6, 0xdc, 0x30, 0x2b, 0xf4, 0xd5, 0xdb, 0xff, + 0x20, 0x25, 0x01, 0xd0, 0xee, 0x0c, 0x00, 0x19, 0x03, 0xd7, 0xf9, 0x2d, + 0x1b, 0xd7, 0xe9, 0x2b, 0xff, 0xd2, 0x20, 0x1b, 0x01, 0x30, 0x07, 0xe4, + 0x01, 0x09, 0xff, 0x39, 0x09, 0xde, 0xd7, 0x05, 0x1e, 0x0c, 0x24, 0xde, + 0xcc, 0xe7, 0x1e, 0x24, 0x10, 0xdc, 0xd0, 0x01, 0x2d, 0x05, 0xce, 0xf4, + 0x2e, 0x22, 0xee, 0xd7, 0x05, 0x2e, 0x17, 0xf2, 0xd5, 0xde, 0x0a, 0x17, + 0x25, 0x0e, 0xf4, 0xe0, 0xf0, 0x32, 0x2d, 0xf7, 0xd7, 0xfd, 0x19, 0x0a, + 0x01, 0x00, 0xe2, 0xf7, 0x2b, 0x03, 0xd3, 0xf6, 0x34, 0x19, 0xe0, 0xd5, + 0x01, 0xff, 0xdc, 0x17, 0x1c, 0xf4, 0xca, 0xf9, 0x29, 0x12, 0xe5, 0xff, + 0x27, 0x03, 0xd0, 0xe7, 0x03, 0x05, 0x15, 0xfb, 0xe9, 0x07, 0x0e, 0xd3, + 0x00, 0x27, 0xf4, 0xe2, 0x2e, 0x0e, 0xd0, 0xfb, 0x27, 0xed, 0xc5, 0x00, + 0x27, 0x03, 0xf0, 0x24, 0xee, 0xc9, 0x00, 0x2e, 0x00, 0xcc, 0xfd, 0x2e, + 0xf6, 0xd0, 0xed, 0x19, 0x2d, 0xfd, 0xcc, 0xf2, 0x17, 0xfd, 0xfd, 0x29, + 0x01, 0xd0, 0xed, 0x25, 0x1c, 0xdb, 0xe5, 0xe9, 0xde, 0x1b, 0x0a, 0xe0, + 0xfd, 0x19, 0xe9, 0xe0, 0xe4, 0xfb, 0x22, 0x15, 0xf6, 0xd3, 0x07, 0x03, + 0xdc, 0x1b, 0x24, 0xf9, 0xd3, 0xff, 0x25, 0xe0, 0xf2, 0x32, 0x00, 0xd3, + 0xed, 0x27, 0xfb, 0xc7, 0xf6, 0x2b, 0x0a, 0xcc, 0xfd, 0x3b, 0xfd, 0xd0, + 0xde, 0x03, 0xfd, 0xee, 0x05, 0x29, 0xee, 0xc3, 0xe7, 0x13, 0x22, 0x0c, + 0xf9, 0x17, 0xe0, 0xd9, 0x17, 0x24, 0xdb, 0xe5, 0x32, 0x0c, 0xca, 0xde, + 0x15, 0x1c, 0xed, 0x20, 0x0a, 0xcc, 0x07, 0x36, 0xf7, 0xd0, 0xd7, 0x00, + 0x1c, 0x20, 0xfb, 0xdb, 0xe5, 0xfb, 0x0e, 0x00, 0x15, 0x20, 0x07, 0xfb, + 0xd7, 0xe2, 0x0e, 0x2e, 0x00, 0xd7, 0x15, 0x0e, 0xcc, 0x12, 0x24, 0xde, + 0xd3, 0x12, 0x32, 0x0a, 0xdb, 0xf0, 0x1c, 0xf0, 0xd7, 0xfb, 0x1c, 0x27, + 0xf0, 0xd0, 0x07, 0x2e, 0xf7, 0xe9, 0x20, 0xde, 0xdb, 0x1c, 0x27, 0xe5, + 0xc5, 0xfb, 0x27, 0x1c, 0x00, 0xe9, 0xf4, 0x12, 0xdb, 0xd7, 0x15, 0x20, + 0x19, 0x07, 0xed, 0xcc, 0xf4, 0x2b, 0x27, 0x00, 0xf4, 0xde, 0xe2, 0x24, + 0x2e, 0x00, 0xd3, 0xe2, 0x07, 0x00, 0xff, 0x1c, 0xf0, 0x00, 0xf7, 0xd3, + 0x2b, 0x32, 0x0a, 0xf0, 0xde, 0xd0, 0xf0, 0x0e, 0x24, 0x19, 0xdb, 0xc9, + 0xff, 0x27, 0x19, 0x00, 0xff, 0xd7, 0xe2, 0x0e, 0x2b, 0x27, 0xf7, 0xf4, + 0x03, 0xe5, 0x15, 0x27, 0xf4, 0xd0, 0xe5, 0x20, 0x00, 0xd3, 0x2b, 0x24, + 0xe5, 0xd0, 0x00, 0x2b, 0xe2, 0xc5, 0x0e, 0x2b, 0x03, 0xe2, 0x12, 0xfb, + 0xc5, 0xf0, 0x03, 0x0a, 0x1c, 0xf7, 0xe5, 0x1c, 0xed, 0xe9, 0x07, 0x36, + 0x07, 0xdb, 0x00, 0x0e, 0xcc, 0xfb, 0x32, 0x12, 0xe2, 0x03, 0x19, 0xdb, + 0xd7, 0x0e, 0x24, 0x19, 0xf4, 0xe5, 0x19, 0x0a, 0xd0, 0xfb, 0x15, 0xd0, + 0xf0, 0x20, 0x27, 0xf4, 0xcc, 0xe5, 0x24, 0x00, 0xed, 0x32, 0xed, 0xc5, + 0xe5, 0x07, 0x07, 0xf4, 0x07, 0x20, 0xfb, 0xe5, 0x03, 0x20, 0xe9, 0x0a, + 0x0e, 0xd0, 0xf0, 0x2b, 0x27, 0xe5, 0xd7, 0x0e, 0xff, 0x15, 0x2e, 0xfb, + 0xfb, 0xe9, 0xe2, 0xed, 0x27, 0x0e, 0xd0, 0xfb, 0x27, 0xf4, 0xd3, 0x19, + 0x27, 0xf0, 0xc9, 0xf4, 0x24, 0xff, 0xf0, 0x3d, 0x00, 0xdb, 0xd3, 0xf7, + 0x15, 0x19, 0x00, 0xf4, 0x03, 0xde, 0xfb, 0x32, 0x24, 0xf7, 0xdb, 0xf0, + 0x03, 0xe2, 0x03, 0x1c, 0x20, 0xe2, 0xc9, 0xf0, 0x24, 0x20, 0x03, 0x00, + 0xe9, 0xc9, 0xe9, 0x19, 0x24, 0x00, 0xcc, 0xd7, 0x07, 0x24, 0x00, 0xe9, + 0x32, 0x19, 0xe2, 0x00, 0x07, 0xe9, 0x1c, 0x12, 0xde, 0xe9, 0xfb, 0xe5, + 0x1c, 0x1c, 0x24, 0xf0, 0xdb, 0x00, 0x20, 0xd7, 0xf7, 0x20, 0xd3, 0xe5, + 0x27, 0x07, 0xc5, 0xe9, 0x20, 0x20, 0xfb, 0xc9, 0xe2, 0x12, 0x1c, 0x20, + 0x00, 0xd7, 0xe9, 0x2e, 0x15, 0xd3, 0xde, 0x19, 0x20, 0xed, 0xd3, 0x00, + 0x24, 0x27, 0x03, 0xe2, 0xd3, 0xde, 0x15, 0x20, 0x03, 0xf7, 0xe9, 0xfb, + 0xf0, 0xfb, 0x15, 0x03, 0x2b, 0xf4, 0xd3, 0x00, 0x32, 0x0a, 0xe5, 0xd0, + 0xe9, 0x0e, 0x07, 0x1c, 0x00, 0xc9, 0xd7, 0x03, 0x1c, 0x24, 0x15, 0xff, + 0xe5, 0xd3, 0xf7, 0x20, 0x24, 0x00, 0xd3, 0xdb, 0x03, 0x27, 0x27, 0x0e, + 0xf4, 0xe5, 0xd0, 0xf4, 0x20, 0x2b, 0x19, 0xed, 0xe2, 0xd3, 0x0a, 0x2b, + 0x1c, 0xf7, 0xe2, 0xfb, 0xe9, 0xe2, 0x20, 0x20, 0xf7, 0xc9, 0xd3, 0xff, + 0x12, 0x20, 0x20, 0xe9, 0xcc, 0xde, 0x07, 0x19, 0x24, 0x07, 0xe2, 0xf7, + 0x2b, 0xe5, 0xdb, 0x2b, 0x32, 0x00, 0xe5, 0xde, 0x0e, 0x2e, 0xe5, 0xcc, + 0x07, 0x32, 0x07, 0xcc, 0xed, 0x2e, 0x0e, 0xc9, 0xf0, 0x2b, 0x00, 0xd3, + 0x24, 0x27, 0xe5, 0xcc, 0xd3, 0x00, 0x15, 0x1c, 0x12, 0x00, 0xf7, 0xdb, + 0xd7, 0x19, 0x24, 0x0a, 0x0a, 0xe5, 0xcc, 0xf7, 0x24, 0x2b, 0x03, 0xe5, + 0x0e, 0xe2, 0xde, 0x24, 0x27, 0xe9, 0xc5, 0xf0, 0x20, 0x2b, 0x0e, 0xf0, + 0xff, 0xc9, 0xe2, 0x12, 0x27, 0x19, 0x00, 0x00, 0xd0, 0xe2, 0x12, 0x32, + 0x19, 0xed, 0xdb, 0xd3, 0xff, 0x24, 0x2b, 0x00, 0xcc, 0xff, 0x24, 0xf0, + 0xcc, 0x19, 0x27, 0xe2, 0xc9, 0xff, 0x0e, 0x19, 0x0a, 0x00, 0xe9, 0xe9, + 0xff, 0xf7, 0x2b, 0x2b, 0x03, 0xde, 0xe2, 0x03, 0xfb, 0x0e, 0x39, 0xed, + 0xd0, 0xed, 0x1c, 0xf7, 0x00, 0x3d, 0x00, 0xd7, 0xed, 0x00, 0xde, 0x1c, + 0x27, 0xed, 0xc1, 0xfb, 0x27, 0x1c, 0xf7, 0xde, 0xe2, 0x27, 0x19, 0xd7, + 0x03, 0x2b, 0xe5, 0xc9, 0xde, 0x07, 0x15, 0xff, 0x0a, 0x19, 0xc5, 0xe5, + 0x20, 0x2b, 0xf0, 0xcc, 0x00, 0x20, 0xf4, 0xdb, 0x36, 0x15, 0xde, 0xed, + 0x1c, 0x27, 0xf0, 0xd7, 0xf4, 0x0e, 0xf0, 0x1c, 0x15, 0xf4, 0xfb, 0xf7, + 0xff, 0x0e, 0xdb, 0xcc, 0x12, 0x27, 0x0a, 0xed, 0x03, 0xe2, 0xcc, 0x03, + 0x0e, 0x03, 0x0e, 0xf7, 0xf4, 0xf0, 0xd7, 0x0a, 0x27, 0x27, 0xff, 0xe5, + 0xf7, 0xe9, 0x0e, 0x32, 0x00, 0xd0, 0xde, 0x1c, 0x19, 0xf7, 0x0a, 0xf0, + 0xcc, 0xff, 0x24, 0x2e, 0x19, 0xf0, 0xf4, 0xde, 0xd7, 0x12, 0x2b, 0x27, + 0xf7, 0xe2, 0xe9, 0xe9, 0x00, 0x2b, 0x03, 0xd3, 0xc9, 0xf4, 0x19, 0x0e, + 0xed, 0xe9, 0xfb, 0x27, 0xde, 0xd3, 0x24, 0x24, 0xf0, 0xcc, 0xed, 0x24, + 0x1c, 0xfb, 0x0a, 0x24, 0xde, 0xe5, 0x00, 0x1c, 0xf7, 0xdb, 0x12, 0x0e, + 0xf4, 0xd0, 0x0e, 0x36, 0x0e, 0xed, 0xe2, 0xdb, 0x0e, 0x19, 0xd3, 0xe2, + 0x2b, 0x12, 0xd0, 0xf0, 0x2e, 0xe5, 0xc9, 0x0a, 0x20, 0xe9, 0x07, 0x36, + 0xed, 0xd0, 0xe2, 0x0e, 0x07, 0x12, 0x27, 0xe9, 0xdb, 0x0e, 0x20, 0xd3, + 0xfb, 0x2b, 0x0a, 0xdb, 0xe9, 0x19, 0x03, 0xf4, 0x0a, 0xdb, 0x00, 0x32, + 0x03, 0xd7, 0xd3, 0xfb, 0x03, 0xe5, 0x12, 0x27, 0xff, 0xed, 0xf7, 0xf0, + 0xfb, 0x32, 0x00, 0xc5, 0xff, 0x32, 0x19, 0xe2, 0xcc, 0xed, 0x0e, 0x20, + 0x27, 0xf0, 0xed, 0x0e, 0xed, 0xdb, 0x27, 0x32, 0x1c, 0xf7, 0xf4, 0xe5, + 0xd3, 0xff, 0x20, 0x27, 0x07, 0xe5, 0xdb, 0xdb, 0x0e, 0x1c, 0x0a, 0xd7, + 0xe9, 0x07, 0x15, 0x0a, 0xff, 0xc9, 0xd7, 0x07, 0x1c, 0xf0, 0xe5, 0x00, + 0x15, 0x20, 0xf0, 0xd3, 0x07, 0x3d, 0x0a, 0xe5, 0xd7, 0xe9, 0x24, 0x2b, + 0x00, 0xcc, 0x00, 0x3d, 0x15, 0xe5, 0xfb, 0x0e, 0xdb, 0xf7, 0x32, 0x20, + 0xed, 0xdb, 0x0e, 0x24, 0xd3, 0xd7, 0x07, 0x2b, 0xff, 0xc5, 0x00, 0x2b, + 0xe9, 0xde, 0x32, 0x00, 0xc1, 0xd0, 0xf7, 0x0a, 0x19, 0x19, 0xde, 0xe2, + 0x32, 0x15, 0xde, 0x12, 0x12, 0xcc, 0xf7, 0x27, 0xfb, 0xd7, 0x2b, 0x27, + 0xe9, 0xd3, 0x00, 0x2e, 0xed, 0xed, 0x39, 0x07, 0xd7, 0x00, 0x39, 0xff, + 0xd7, 0xed, 0x24, 0xf7, 0xcc, 0x20, 0x0e, 0xd0, 0xfb, 0x32, 0x07, 0xd3, + 0xf0, 0x0e, 0xc9, 0xf0, 0x24, 0x20, 0xed, 0xe5, 0x1c, 0xcc, 0xf0, 0x2b, + 0x0a, 0xf7, 0xff, 0xf4, 0xde, 0x0a, 0x32, 0x20, 0xf0, 0xdb, 0xdb, 0x07, + 0x32, 0x15, 0xdb, 0xd0, 0x0a, 0x27, 0x00, 0x2b, 0x07, 0xe9, 0xe2, 0xf4, + 0xf0, 0xff, 0x1c, 0x0a, 0xe5, 0xf4, 0xe5, 0x00, 0x2b, 0xff, 0xc5, 0xf4, + 0x24, 0x03, 0x00, 0x15, 0x0e, 0xe9, 0xd7, 0x00, 0x39, 0x15, 0xde, 0xde, + 0x03, 0xf4, 0x03, 0x36, 0xf7, 0xd0, 0xf4, 0x20, 0xe5, 0xf0, 0x36, 0xfb, + 0xc9, 0xe5, 0x24, 0x2b, 0x07, 0xf7, 0x00, 0xd7, 0xe9, 0x1c, 0x27, 0xfb, + 0xf4, 0xe2, 0xde, 0x12, 0x27, 0xff, 0xfb, 0x24, 0xe2, 0xd0, 0x03, 0x36, + 0x0e, 0xd7, 0xd7, 0x00, 0x1c, 0x03, 0x00, 0xff, 0xd7, 0x0a, 0x20, 0xd0, + 0xe5, 0x27, 0x20, 0xe9, 0xd0, 0x00, 0x07, 0xf4, 0x00, 0x19, 0xfb, 0xd7, + 0x12, 0x2b, 0xf4, 0xc9, 0xe9, 0x20, 0x27, 0x15, 0x00, 0xe9, 0xe5, 0x27, + 0x19, 0xd0, 0x03, 0x19, 0xde, 0xf0, 0x24, 0xed, 0xdb, 0x12, 0x24, 0xf0, + 0xc9, 0x07, 0x00, 0x1c, 0x19, 0xd0, 0xe5, 0x24, 0x24, 0xe2, 0xc9, 0xed, + 0x1c, 0x27, 0x19, 0xfb, 0xe2, 0xd3, 0xf7, 0x19, 0x19, 0xe5, 0xde, 0x27, + 0x19, 0xd3, 0xe5, 0xff, 0x00, 0x2e, 0x0e, 0xd7, 0xd7, 0x19, 0x32, 0x0e, + 0x00, 0xe9, 0xe9, 0xff, 0x0e, 0x0e, 0x03, 0xde, 0xd0, 0x12, 0x2b, 0x15, + 0xe2, 0xd3, 0x12, 0x2b, 0xdb, 0xcc, 0x07, 0x2b, 0x1c, 0xe2, 0xcc, 0xf4, + 0x15, 0x2b, 0x1c, 0xe9, 0xf7, 0xe9, 0xdb, 0x15, 0x0a, 0x03, 0x00, 0xf0, + 0x36, 0xff, 0xc9, 0xff, 0x32, 0x07, 0xd3, 0xf0, 0x15, 0x1c, 0x0e, 0xd0, + 0xdb, 0x03, 0x00, 0xf7, 0x32, 0x0e, 0xd0, 0xd0, 0x03, 0x24, 0x0e, 0x03, + 0x19, 0x00, 0xfb, 0xff, 0xe5, 0xdb, 0x03, 0x0e, 0xdb, 0x03, 0x15, 0xde, + 0xfb, 0x07, 0xf4, 0x0e, 0x00, 0xff, 0x00, 0x07, 0x1c, 0xc9, 0xdb, 0x15, + 0x2b, 0x19, 0x00, 0xff, 0xde, 0xf4, 0x19, 0xf4, 0x00, 0x0e, 0x12, 0xff, + 0xed, 0xc5, 0xe2, 0x00, 0x0e, 0x15, 0x12, 0xe5, 0xd0, 0x0e, 0x0a, 0xff, + 0x36, 0x0a, 0xe9, 0xe9, 0x00, 0xed, 0xf7, 0x00, 0x07, 0x1c, 0xf0, 0xe5, + 0x00, 0x19, 0xfb, 0xff, 0xf4, 0xde, 0x2b, 0x2b, 0x00, 0xd7, 0xf7, 0x12, + 0x07, 0x0e, 0xf4, 0xed, 0xf4, 0x2e, 0x07, 0xe9, 0xd0, 0x03, 0x32, 0x03, + 0xcc, 0xd0, 0xfb, 0x15, 0x0e, 0x00, 0xd7, 0x00, 0x2e, 0x00, 0xc9, 0xdb, + 0x07, 0x07, 0xfb, 0x27, 0x12, 0xed, 0xf7, 0x2b, 0xe5, 0xd0, 0x1c, 0x2e, + 0xf0, 0xed, 0x19, 0xd3, 0xff, 0x39, 0x1c, 0xe9, 0xf0, 0x19, 0xf7, 0xd0, + 0x03, 0xfb, 0x00, 0x36, 0x0a, 0xd7, 0xd7, 0x07, 0x0e, 0xf4, 0x0e, 0xe2, + 0xd3, 0x0e, 0x2e, 0x15, 0xdb, 0xd0, 0xe9, 0xff, 0x0e, 0x24, 0xe2, 0xe9, + 0x36, 0x00, 0xc9, 0xf7, 0x20, 0x24, 0x12, 0x00, 0xdb, 0xdb, 0x07, 0x2e, + 0x1c, 0xe2, 0xdb, 0x24, 0x2e, 0xed, 0xdb, 0xd3, 0xf4, 0x15, 0x1c, 0xe9, + 0xd3, 0x12, 0x24, 0x0e, 0xd7, 0xde, 0x00, 0x19, 0x15, 0xf7, 0xd3, 0xe9, + 0x2e, 0x07, 0xc9, 0xf4, 0x2b, 0xff, 0x07, 0x15, 0xc9, 0xde, 0x15, 0x27, + 0x0a, 0x00, 0x19, 0xde, 0xd3, 0xf0, 0x27, 0x19, 0xed, 0xf4, 0x07, 0x20, + 0xd7, 0xdb, 0x27, 0x15, 0xd0, 0xfb, 0x32, 0x07, 0xf7, 0xff, 0xe2, 0xcc, + 0xf0, 0x12, 0x20, 0x19, 0xf0, 0xd0, 0xd3, 0x0a, 0x24, 0x15, 0xff, 0x00, + 0xd3, 0xde, 0x1c, 0x27, 0x00, 0xf4, 0xff, 0xde, 0x0a, 0x3d, 0x0a, 0xdb, + 0xe5, 0x12, 0xf4, 0xf0, 0x40, 0x0a, 0xdb, 0xfb, 0xfb, 0xd0, 0x19, 0x2e, + 0x1c, 0xe9, 0xd3, 0xd7, 0x0e, 0x2e, 0x1c, 0xe9, 0xd7, 0xde, 0xff, 0x20, + 0x1c, 0xdb, 0xd7, 0x00, 0x0e, 0xf0, 0xff, 0x2b, 0x12, 0xde, 0xc9, 0xf7, + 0x27, 0x19, 0x00, 0x0e, 0x03, 0xd0, 0xe9, 0x20, 0x27, 0xed, 0xf7, 0x20, + 0xfb, 0xdb, 0x03, 0x2e, 0xde, 0xc5, 0xf4, 0x19, 0x15, 0xff, 0x15, 0xff, + 0xd3, 0x07, 0x00, 0xff, 0x19, 0xe2, 0x00, 0x27, 0xde, 0xd0, 0x0a, 0x27, + 0xe9, 0xed, 0x32, 0xf4, 0xcc, 0x00, 0x32, 0x15, 0xde, 0xff, 0x27, 0xd3, + 0xd7, 0x0a, 0x15, 0xff, 0x03, 0xf0, 0x19, 0x20, 0xe2, 0xed, 0x19, 0xf4, + 0xd0, 0x00, 0x32, 0x12, 0xf7, 0xed, 0xd0, 0xf4, 0x19, 0x2e, 0x12, 0xe5, + 0xd7, 0xdb, 0x15, 0x1c, 0xf0, 0x03, 0x24, 0xd7, 0xc9, 0xf7, 0x1c, 0xff, + 0x19, 0x19, 0xd7, 0xe5, 0x2b, 0x20, 0xe5, 0xd0, 0xff, 0x1c, 0xd7, 0x03, + 0x2e, 0xff, 0xd7, 0x03, 0x0a, 0xd3, 0x00, 0x36, 0x0a, 0xe9, 0xe2, 0xdb, + 0xff, 0x03, 0xff, 0x0e, 0x19, 0x00, 0xd7, 0xd7, 0x07, 0x19, 0x2b, 0x00, + 0xdb, 0xff, 0x1c, 0x03, 0x00, 0xdb, 0xdb, 0x24, 0x27, 0xde, 0xcc, 0x0a, + 0x2b, 0xf0, 0xff, 0x15, 0xd3, 0x07, 0x1c, 0xd7, 0xd7, 0x12, 0x27, 0xed, + 0xe5, 0x36, 0xf4, 0xd0, 0x19, 0x1c, 0xc9, 0xed, 0x2e, 0x27, 0xf0, 0xdb, + 0xde, 0xfb, 0x20, 0x27, 0xed, 0xc9, 0xf0, 0x19, 0x0a, 0x19, 0x12, 0xe9, + 0xde, 0x0e, 0x36, 0xfb, 0xdb, 0x00, 0x24, 0xde, 0xe2, 0x24, 0x0a, 0xcc, + 0xf0, 0x2e, 0x00, 0xc1, 0xf4, 0x2b, 0x0a, 0xd3, 0xf7, 0x00, 0xd7, 0x1c, + 0x27, 0xfb, 0xe9, 0x24, 0xf7, 0xc5, 0xf4, 0x24, 0x24, 0x0a, 0x00, 0xe5, + 0xde, 0x07, 0x24, 0xf7, 0xde, 0x15, 0x1c, 0xe5, 0xc5, 0xf4, 0x19, 0x19, + 0x20, 0xfb, 0xd3, 0xf0, 0x2e, 0x0a, 0xd0, 0x00, 0x24, 0xe2, 0x0a, 0x07, + 0xd7, 0xfb, 0xff, 0xe5, 0xf0, 0x07, 0x24, 0x19, 0xde, 0xd7, 0x0a, 0x00, + 0xf4, 0x0e, 0x27, 0xf0, 0xcc, 0x00, 0x2b, 0x03, 0xf4, 0x32, 0x0a, 0xdb, + 0xed, 0x03, 0x00, 0x12, 0xff, 0xd0, 0x00, 0x32, 0x0e, 0xd7, 0xe9, 0x27, + 0xf7, 0xc1, 0x00, 0x1c, 0x00, 0x0a, 0x03, 0xc9, 0xe2, 0x19, 0x2b, 0x15, + 0xed, 0xe9, 0xdb, 0xf7, 0x27, 0x1c, 0xf0, 0xe5, 0x03, 0xff, 0x00, 0xf4, + 0xed, 0x39, 0x12, 0xd7, 0xde, 0x0e, 0x24, 0xff, 0xe5, 0x07, 0x15, 0x00, + 0xd3, 0xfb, 0x2e, 0x15, 0xd7, 0xe5, 0x2b, 0x24, 0xd7, 0xde, 0x1c, 0x19, + 0xd3, 0x00, 0x2b, 0xed, 0xd0, 0x15, 0x19, 0xff, 0xf0, 0xdb, 0xfb, 0x27, + 0x0e, 0xe2, 0x03, 0x32, 0xff, 0xde, 0xe5, 0x0a, 0x00, 0x0e, 0x00, 0xc9, + 0x07, 0x2b, 0x07, 0xd0, 0xe2, 0x19, 0x0e, 0xf4, 0x03, 0x00, 0xf4, 0xe2, + 0x15, 0x15, 0xed, 0xe9, 0x24, 0x2e, 0xf0, 0xd3, 0x00, 0x39, 0x00, 0xd3, + 0x0a, 0x27, 0xf4, 0xd7, 0xf0, 0xf4, 0xff, 0x12, 0xfb, 0xf4, 0xd7, 0x0e, + 0x27, 0xff, 0xd0, 0xed, 0x2b, 0x2b, 0x00, 0xe2, 0xed, 0xed, 0xf7, 0x24, + 0x27, 0xe9, 0xe5, 0x24, 0xf4, 0xcc, 0x03, 0x2e, 0x20, 0xed, 0x03, 0x0e, + 0xde, 0xdb, 0xe9, 0x19, 0x1c, 0xe9, 0xf7, 0x36, 0xf0, 0xde, 0x20, 0xff, + 0xd0, 0x0e, 0x32, 0x00, 0xd3, 0xd7, 0x00, 0x03, 0xf4, 0x32, 0xfb, 0xd7, + 0x19, 0x0a, 0xc1, 0xe9, 0x20, 0x27, 0x00, 0xed, 0x07, 0xf0, 0xf0, 0x03, + 0x19, 0xdb, 0xed, 0x32, 0x20, 0xf0, 0xe9, 0x12, 0xe5, 0xed, 0x2b, 0xff, + 0xdb, 0x00, 0x1c, 0xed, 0xcc, 0x0a, 0x20, 0xe2, 0xf0, 0x3d, 0x03, 0xd3, + 0xd0, 0xf4, 0x19, 0x1c, 0x07, 0xe9, 0xed, 0x19, 0x0e, 0xd7, 0xde, 0x19, + 0x24, 0x0a, 0xe9, 0xe2, 0x15, 0xfb, 0xfb, 0x27, 0x00, 0xd7, 0xd7, 0x0e, + 0x2b, 0xf0, 0xc9, 0x03, 0x32, 0x07, 0xd3, 0x07, 0x24, 0xdb, 0xe9, 0x00, + 0xff, 0xfb, 0xf4, 0xed, 0x0a, 0x2b, 0x0e, 0xf0, 0xd7, 0xed, 0x19, 0x0a, + 0x00, 0x0e, 0xff, 0xf0, 0x03, 0x27, 0xe2, 0xe5, 0x0e, 0x32, 0xe9, 0xd0, + 0x12, 0x2b, 0xdb, 0xe2, 0x12, 0xfb, 0x03, 0x19, 0xd7, 0xc9, 0xe9, 0x0e, + 0x12, 0x03, 0x07, 0xf0, 0x0a, 0x07, 0xde, 0xdb, 0x00, 0x27, 0x15, 0xd7, + 0xdb, 0x07, 0x03, 0xe5, 0x19, 0x20, 0xdb, 0xf7, 0x3d, 0x07, 0xd7, 0xd3, + 0x00, 0x20, 0xfb, 0x19, 0x20, 0x00, 0xe9, 0xd0, 0xf0, 0x24, 0x00, 0x03, + 0x36, 0xff, 0xdb, 0x07, 0x19, 0xde, 0xff, 0xf0, 0xed, 0x24, 0xfb, 0xc5, + 0x0a, 0x24, 0xe5, 0xf7, 0x39, 0xf4, 0xcc, 0xe9, 0x1c, 0xfb, 0xd3, 0x0e, + 0x24, 0x19, 0x00, 0xff, 0xde, 0xd7, 0x0a, 0x1c, 0x00, 0x0a, 0x12, 0xde, + 0x24, 0x15, 0xd3, 0xf4, 0x2b, 0x12, 0xe5, 0xed, 0xf4, 0xde, 0x00, 0x27, + 0x12, 0xf7, 0xdb, 0x07, 0x24, 0xd7, 0xc9, 0xff, 0x15, 0xfb, 0xf4, 0x19, + 0x0a, 0xd0, 0x0e, 0x20, 0xde, 0xf4, 0x27, 0x0e, 0xdb, 0x12, 0x07, 0xd7, + 0x00, 0x36, 0x15, 0xde, 0xde, 0xf7, 0x00, 0x2b, 0x0e, 0xe9, 0xf4, 0x0e, + 0xf7, 0x07, 0x19, 0xd0, 0xd3, 0x0e, 0x2e, 0x07, 0xdb, 0xe2, 0xff, 0x24, + 0x15, 0xe9, 0xd7, 0x00, 0x12, 0x19, 0xf7, 0xd3, 0xfb, 0x24, 0x20, 0xed, + 0xc9, 0xe5, 0x1c, 0x1c, 0x00, 0xf7, 0xf4, 0xed, 0x32, 0x0e, 0xd3, 0xde, + 0x1c, 0x32, 0xff, 0xde, 0xf7, 0x07, 0x15, 0xfb, 0xe9, 0x2e, 0x00, 0xcc, + 0xf4, 0x27, 0xfb, 0xd0, 0x24, 0x1c, 0xd3, 0xed, 0x36, 0xfb, 0xcc, 0x0e, + 0x32, 0xe5, 0xd3, 0x19, 0x27, 0xd0, 0xd3, 0x0a, 0x0a, 0xe2, 0x32, 0x24, + 0xe9, 0xd0, 0xe9, 0x24, 0x0e, 0xdb, 0x00, 0x32, 0x0e, 0xde, 0xd7, 0xff, + 0x12, 0x0e, 0x20, 0x00, 0xfb, 0xf4, 0xdb, 0x15, 0x36, 0x0a, 0xde, 0xfb, + 0x00, 0xe5, 0xe5, 0x15, 0x15, 0xd0, 0xf4, 0x32, 0x12, 0xed, 0x00, 0xdb, + 0xd7, 0x07, 0x2b, 0x15, 0xdb, 0xde, 0x19, 0x0e, 0xc5, 0xed, 0x27, 0x20, + 0xf7, 0xe5, 0x20, 0x00, 0xcc, 0xf0, 0x32, 0x1c, 0xed, 0xfb, 0xf4, 0xe2, + 0x00, 0xff, 0xed, 0x0a, 0x2e, 0x07, 0xe9, 0xf7, 0xde, 0xed, 0x15, 0x12, + 0x00, 0xe5, 0xe2, 0x2b, 0x19, 0xf4, 0xd3, 0xed, 0x27, 0x2b, 0x00, 0xd3, + 0xde, 0x12, 0x12, 0xfb, 0xff, 0xde, 0x2b, 0x27, 0xe2, 0xd7, 0xf7, 0x00, + 0xf4, 0x0a, 0xff, 0xe9, 0xf7, 0x24, 0x07, 0xf4, 0xc9, 0x00, 0x27, 0xff, + 0x00, 0x00, 0xc9, 0xe9, 0x20, 0x20, 0x03, 0x00, 0x27, 0x00, 0xde, 0xf0, + 0x12, 0xf7, 0xf4, 0x20, 0x07, 0xd0, 0xd3, 0x0a, 0x24, 0xf0, 0xf7, 0x12, + 0xc5, 0x03, 0x32, 0x03, 0xd0, 0xcc, 0x00, 0x20, 0x24, 0x12, 0xd7, 0xe2, + 0x0e, 0x03, 0xe2, 0x1c, 0x1c, 0xed, 0xf7, 0x20, 0xde, 0xd3, 0x19, 0x20, + 0xe2, 0x00, 0x24, 0xe2, 0xe9, 0xf7, 0xff, 0x24, 0xe5, 0xed, 0x39, 0x1c, + 0xed, 0xd7, 0xe9, 0x1c, 0xff, 0xed, 0x2b, 0xe9, 0xc9, 0x15, 0x2b, 0xf7, + 0xe9, 0x24, 0xf7, 0xf4, 0x0e, 0xe2, 0x00, 0x00, 0xf7, 0xf7, 0xf4, 0xfb, + 0x24, 0x24, 0xe5, 0xd0, 0xe9, 0x1c, 0x2b, 0x03, 0xd7, 0x00, 0x00, 0xd0, + 0xe9, 0x1c, 0x1c, 0x00, 0xf4, 0x00, 0xf7, 0xed, 0xff, 0x27, 0x03, 0xd3, + 0x0e, 0x32, 0xf7, 0xde, 0xfb, 0xed, 0xf7, 0x27, 0x15, 0xde, 0x07, 0x1c, + 0xd0, 0xd7, 0x0a, 0x2e, 0x15, 0xf7, 0xe2, 0xd7, 0xfb, 0x1c, 0x15, 0xe9, + 0xe9, 0x0e, 0xed, 0xe9, 0x2b, 0x12, 0xd7, 0x00, 0x3d, 0x00, 0xdb, 0xff, + 0xff, 0xdb, 0x00, 0x2b, 0xfb, 0xc9, 0x00, 0x24, 0x00, 0x0a, 0x12, 0xd0, + 0xde, 0x19, 0x2e, 0x00, 0xcc, 0xe9, 0x27, 0x19, 0xd3, 0xf4, 0x39, 0x19, + 0xed, 0xd3, 0xe9, 0x27, 0x2e, 0x03, 0xf0, 0xdb, 0xd7, 0x03, 0x24, 0x12, + 0xde, 0xde, 0xf0, 0x20, 0x07, 0xed, 0x20, 0xf0, 0xd7, 0x00, 0x2e, 0xfb, + 0xd3, 0x19, 0x12, 0xc5, 0xed, 0x2b, 0x19, 0xe5, 0xf4, 0x24, 0xfb, 0xfb, + 0x0e, 0x07, 0xf4, 0x0a, 0xe9, 0xe2, 0x12, 0x24, 0xfb, 0xfb, 0x15, 0xe2, + 0x00, 0x20, 0xed, 0xd7, 0x07, 0x00, 0xf7, 0x0e, 0xf7, 0xf4, 0x00, 0xed, + 0xf0, 0x1c, 0x19, 0xd7, 0xde, 0x12, 0x00, 0x19, 0x1c, 0xe2, 0xe2, 0x12, + 0x2e, 0xe5, 0xdb, 0xff, 0xed, 0xff, 0x27, 0xf0, 0xf0, 0x39, 0xf7, 0xcc, + 0xd7, 0x0a, 0x20, 0x1c, 0x00, 0xd0, 0xd3, 0x0a, 0x27, 0x0a, 0xff, 0x1c, + 0xdb, 0xe5, 0x2e, 0x27, 0xde, 0xe5, 0x0e, 0xe9, 0xfb, 0x2e, 0x1c, 0xf0, + 0xe2, 0xd7, 0xff, 0x27, 0x1c, 0xfb, 0x03, 0xf4, 0xc9, 0x00, 0x2e, 0x03, + 0xd7, 0x12, 0x00, 0xbe, 0xf7, 0x20, 0x07, 0x00, 0x07, 0xd0, 0x1c, 0x2b, + 0xe5, 0xcc, 0xff, 0x20, 0xe9, 0x12, 0x32, 0xf0, 0xd7, 0x15, 0x20, 0xd3, + 0xff, 0x32, 0xe5, 0xe9, 0x2b, 0x03, 0xc9, 0xe5, 0x0a, 0x1c, 0x0e, 0xdb, + 0xe2, 0x24, 0x0e, 0xd0, 0xdb, 0x15, 0x2b, 0x20, 0x03, 0xed, 0xd7, 0xde, + 0x0a, 0x20, 0xed, 0xd3, 0x27, 0x20, 0xe5, 0xf4, 0x24, 0xed, 0xd0, 0x12, + 0x20, 0xe5, 0xde, 0x19, 0x1c, 0xd7, 0xe2, 0x12, 0x32, 0x1c, 0xfb, 0xf4, + 0xd7, 0xe2, 0x12, 0x2e, 0x1c, 0xe2, 0xe9, 0x1c, 0xfb, 0xc1, 0x00, 0x2b, + 0x03, 0xcc, 0xfb, 0x15, 0x03, 0x15, 0xf7, 0xe5, 0xde, 0x00, 0x24, 0x20, + 0xf7, 0xc9, 0xdb, 0x0a, 0x15, 0x15, 0x15, 0x07, 0xed, 0xdb, 0xf7, 0xff, + 0x07, 0x32, 0x19, 0xf0, 0xe9, 0xe9, 0xe5, 0x19, 0x12, 0xd0, 0x03, 0x32, + 0x0a, 0xde, 0xe2, 0x0e, 0xff, 0x0a, 0x24, 0xd7, 0xd0, 0x07, 0x27, 0xf4, + 0xf7, 0x07, 0xe2, 0x19, 0x36, 0xf7, 0xdb, 0xde, 0xf4, 0x00, 0x12, 0x12, + 0x0e, 0x03, 0xd0, 0xd7, 0x0a, 0x19, 0xfb, 0x24, 0x0e, 0xcc, 0xdb, 0x12, + 0x24, 0xf4, 0x00, 0x00, 0xd7, 0x0e, 0x32, 0xfb, 0xc5, 0xe5, 0x15, 0x15, + 0x15, 0x19, 0xed, 0xd7, 0xe2, 0x07, 0x00, 0x24, 0x24, 0xe9, 0xf0, 0xff, + 0xf0, 0xfb, 0xff, 0x24, 0x0e, 0xfb, 0xf4, 0xdb, 0x1c, 0x00, 0xc9, 0x07, + 0x32, 0x00, 0xd3, 0xf7, 0x07, 0xe9, 0xf0, 0x07, 0x0e, 0x1c, 0xed, 0xde, + 0x0a, 0x27, 0xe2, 0xf0, 0x0a, 0xe2, 0xff, 0x24, 0x1c, 0xd7, 0xe2, 0x20, + 0x0e, 0xf4, 0x0e, 0x12, 0xf7, 0xcc, 0x00, 0x24, 0xd3, 0xe9, 0x2e, 0x15, + 0xdb, 0xcc, 0xff, 0x2b, 0x24, 0xff, 0xc9, 0xed, 0x20, 0xfb, 0xed, 0x32, + 0x07, 0xd3, 0xe5, 0x27, 0x15, 0xcc, 0x00, 0x32, 0xf0, 0xdb, 0x27, 0x15, + 0xd0, 0x03, 0x24, 0xd0, 0xd3, 0x0e, 0x24, 0xd7, 0xe2, 0x27, 0x03, 0xde, + 0x27, 0x20, 0xd7, 0xdb, 0x1c, 0x2e, 0xf0, 0xde, 0x00, 0x0a, 0x0e, 0xf4, + 0xe9, 0xed, 0x00, 0x2b, 0x27, 0xf0, 0xd3, 0xed, 0x15, 0xfb, 0x20, 0x0e, + 0xd7, 0xd3, 0x03, 0x20, 0xf4, 0x07, 0xff, 0xd3, 0x07, 0x15, 0xde, 0x07, + 0x24, 0xdb, 0xc9, 0x00, 0x1c, 0xf7, 0x12, 0x20, 0xcc, 0xd0, 0x00, 0x1c, + 0x15, 0x0e, 0x03, 0xf0, 0xf4, 0x36, 0xfb, 0xf0, 0x12, 0xfb, 0xf7, 0x00, + 0xff, 0x0a, 0x00, 0x03, 0xde, 0xf7, 0x0e, 0x07, 0x19, 0xde, 0xd3, 0x03, + 0x07, 0xe2, 0x19, 0x12, 0xd3, 0xe5, 0x2b, 0x15, 0xd3, 0xde, 0x27, 0x0a, + 0xd3, 0x12, 0x1c, 0xcc, 0xd3, 0x0a, 0x19, 0xff, 0x20, 0x15, 0xd7, 0xde, + 0x1c, 0x2b, 0xe2, 0x03, 0x32, 0xe5, 0xd0, 0xed, 0x27, 0x15, 0xdb, 0xfb, + 0x20, 0xe2, 0x00, 0x36, 0xf0, 0xdb, 0xe9, 0xf0, 0x0a, 0x19, 0x2b, 0xf0, + 0xd3, 0xde, 0x00, 0x12, 0x00, 0x19, 0x0e, 0xed, 0xd0, 0xf0, 0x24, 0x27, + 0x15, 0xed, 0xdb, 0xf0, 0x2b, 0x00, 0xc1, 0x00, 0x27, 0xf7, 0xf4, 0x3d, + 0x00, 0xd7, 0xf0, 0x1c, 0x12, 0xdb, 0xe9, 0x2b, 0x03, 0xd7, 0xde, 0x19, + 0xff, 0x03, 0x20, 0xf0, 0x00, 0xf4, 0x0e, 0x0a, 0xc9, 0xed, 0x27, 0x24, + 0xed, 0xde, 0x00, 0xe9, 0xe5, 0x24, 0x20, 0xe2, 0xdb, 0x2b, 0x20, 0xde, + 0xe5, 0x24, 0x0e, 0xf7, 0xf7, 0xf7, 0xff, 0x1c, 0xf4, 0xe9, 0xff, 0xed, + 0xf7, 0x24, 0x19, 0xde, 0xd0, 0x00, 0x2e, 0xff, 0xe2, 0xf7, 0x12, 0xf4, + 0xdb, 0x20, 0x03, 0xe5, 0xf4, 0x24, 0x12, 0xde, 0xe2, 0xfb, 0x20, 0x1c, + 0xf7, 0xed, 0x07, 0xf7, 0xed, 0x2e, 0x0e, 0xf7, 0x0e, 0x03, 0xde, 0xf0, + 0x2e, 0x1c, 0xde, 0xd3, 0xf4, 0x0a, 0xf0, 0x12, 0x15, 0xd7, 0xdb, 0x00, + 0x20, 0x19, 0xde, 0xcc, 0xf0, 0x12, 0xf7, 0x03, 0x32, 0x03, 0xf7, 0xf7, + 0xdb, 0xfb, 0x32, 0x20, 0xf0, 0xd3, 0xe2, 0x0a, 0x20, 0x07, 0x00, 0x19, + 0xed, 0xcc, 0xf4, 0x27, 0x1c, 0xe9, 0xe2, 0x19, 0x1c, 0xf4, 0xff, 0x07, + 0x00, 0xcc, 0xde, 0x15, 0x2b, 0x1c, 0xf0, 0xe9, 0xe2, 0xde, 0x12, 0x2e, + 0x0a, 0xd3, 0xe2, 0xf4, 0xed, 0x0a, 0x24, 0xff, 0xcc, 0x00, 0x36, 0xfb, + 0xc9, 0xed, 0x27, 0x0e, 0xe5, 0x0a, 0x15, 0x00, 0xc9, 0xf0, 0x24, 0xfb, + 0xe5, 0x24, 0x2e, 0xf7, 0xdb, 0xed, 0x0a, 0x00, 0x00, 0xfb, 0xfb, 0x07, + 0x19, 0x07, 0xe9, 0xcc, 0x00, 0x27, 0xf0, 0x03, 0x0e, 0xc1, 0xe2, 0x0e, + 0x24, 0x15, 0xf0, 0x00, 0xf0, 0x07, 0x00, 0xe2, 0xf0, 0x07, 0x27, 0xe5, + 0xe5, 0x27, 0x03, 0xd7, 0xde, 0x19, 0xff, 0xfb, 0x32, 0x0e, 0xde, 0xd0, + 0xed, 0x20, 0x24, 0x12, 0xf4, 0xdb, 0xf0, 0x19, 0x19, 0xff, 0xde, 0x0e, + 0x24, 0xdb, 0xde, 0x20, 0xf7, 0xc9, 0x20, 0x20, 0xd7, 0xd7, 0x24, 0x0e, + 0xc9, 0xf7, 0x32, 0xf7, 0xe5, 0x0e, 0x03, 0xf4, 0xf7, 0xf4, 0x00, 0x03, + 0xff, 0xf4, 0x12, 0x24, 0xff, 0xe5, 0xde, 0x03, 0x2e, 0x12, 0xe2, 0xcc, + 0xff, 0x24, 0xf4, 0x00, 0x19, 0xd7, 0xe9, 0x36, 0x27, 0xed, 0xe2, 0x03, + 0xed, 0xe2, 0x24, 0xfb, 0xde, 0x0e, 0x0e, 0xf0, 0xd7, 0x19, 0x32, 0x00, + 0xd0, 0xdb, 0x12, 0x32, 0x0a, 0xdb, 0xed, 0xf7, 0xfb, 0x32, 0x20, 0xed, + 0xd0, 0xde, 0x12, 0x27, 0x19, 0x03, 0xf4, 0xfb, 0xde, 0xe2, 0x00, 0x1c, + 0x24, 0xf4, 0xcc, 0xde, 0x0a, 0x12, 0xf7, 0x1c, 0x00, 0xc5, 0x00, 0x39, + 0x0a, 0xe9, 0xf4, 0xe2, 0xf0, 0x19, 0x20, 0xed, 0xf0, 0x03, 0xde, 0x00, + 0x2e, 0x27, 0x00, 0xf0, 0xe5, 0xe2, 0xff, 0x1c, 0x20, 0xe5, 0xd7, 0xf0, + 0x12, 0x2e, 0x0e, 0xf0, 0xe9, 0xdb, 0xfb, 0x2b, 0x15, 0xd3, 0xcc, 0x03, + 0x19, 0xdb, 0x07, 0x36, 0xfb, 0xcc, 0xf0, 0x2b, 0x07, 0xe5, 0xff, 0x19, + 0x00, 0xd3, 0x07, 0x2b, 0xf0, 0xc9, 0x00, 0x2e, 0x00, 0xde, 0x1c, 0x0a, + 0xc9, 0x03, 0x32, 0x00, 0xdb, 0x19, 0xff, 0xc9, 0x07, 0x2b, 0xe9, 0xd7, + 0x19, 0xff, 0xde, 0x19, 0x03, 0x00, 0x07, 0xf4, 0xd7, 0x12, 0x2b, 0xf4, + 0xe9, 0x20, 0xe9, 0xd7, 0x27, 0x19, 0xd3, 0xed, 0x27, 0x03, 0xf0, 0x15, + 0xe2, 0xe2, 0x03, 0x07, 0xff, 0x19, 0x00, 0xd0, 0x0a, 0x27, 0xe2, 0xed, + 0x2b, 0x0a, 0xd3, 0xed, 0x27, 0x00, 0xc9, 0xff, 0x2b, 0x03, 0xd7, 0x24, + 0x20, 0xd7, 0xd0, 0xf4, 0x20, 0x15, 0x03, 0x03, 0xe2, 0xde, 0x03, 0x32, + 0x12, 0xd7, 0xd7, 0x0a, 0x24, 0xf0, 0xe5, 0x12, 0x1c, 0xd0, 0xfb, 0x2e, + 0x27, 0xf4, 0xdb, 0xe2, 0xf0, 0xf4, 0x19, 0x2b, 0x12, 0xde, 0xdb, 0xf4, + 0x07, 0x15, 0x12, 0xf4, 0xde, 0xde, 0x15, 0x2b, 0x0e, 0xe5, 0xdb, 0xf0, + 0x0e, 0x32, 0x0e, 0xdb, 0xdb, 0x03, 0x0e, 0x0a, 0x2e, 0x00, 0xe9, 0xf4, + 0xdb, 0xf4, 0x15, 0x27, 0x00, 0xf0, 0x00, 0xf7, 0xdb, 0x03, 0x2b, 0xed, + 0xc9, 0x03, 0x2e, 0x19, 0xf0, 0xf0, 0xdb, 0xe2, 0x19, 0x27, 0x12, 0xd7, + 0xd3, 0xed, 0x12, 0x19, 0x0a, 0x19, 0x00, 0xd3, 0xed, 0x20, 0xfb, 0xed, + 0x1c, 0x0a, 0xde, 0xfb, 0x2e, 0x00, 0x0a, 0xf0, 0xcc, 0xff, 0x20, 0x24, + 0xf7, 0xfb, 0xe2, 0xd7, 0x19, 0x2e, 0x03, 0xd7, 0x00, 0xf4, 0xc9, 0x15, + 0x27, 0x03, 0xc9, 0xff, 0x2e, 0xfb, 0xde, 0xff, 0x00, 0xf4, 0x07, 0x00, + 0x03, 0x00, 0xf7, 0x0a, 0x24, 0xe5, 0xdb, 0x20, 0x2b, 0xf7, 0xf7, 0xf0, + 0xd3, 0x12, 0x32, 0x0e, 0xd3, 0xe9, 0x20, 0x0e, 0xe5, 0xed, 0xe9, 0xfb, + 0x19, 0x1c, 0xe9, 0xe9, 0x20, 0xed, 0xde, 0x0e, 0xed, 0xf7, 0x36, 0x19, + 0xde, 0xd7, 0x00, 0x03, 0xed, 0x27, 0x12, 0xd3, 0xe5, 0x15, 0xf0, 0xe5, + 0x12, 0x24, 0x0a, 0xf0, 0xfb, 0x07, 0xfb, 0xe2, 0xf7, 0x19, 0x15, 0x0a, + 0xf4, 0xff, 0x20, 0xf7, 0xe2, 0xe9, 0x07, 0x1c, 0x0e, 0x00, 0xe9, 0xd0, + 0xe5, 0x12, 0x27, 0x0a, 0xd0, 0xd3, 0x00, 0x0e, 0xff, 0x03, 0xe2, 0xff, + 0x27, 0x24, 0xf4, 0xd3, 0xff, 0x0a, 0xff, 0x19, 0xfb, 0xed, 0x15, 0x1c, + 0xf0, 0xde, 0xf7, 0x2b, 0x19, 0xd7, 0xd3, 0x03, 0x07, 0xe2, 0x24, 0x19, + 0xd7, 0xdb, 0x20, 0x2e, 0xf7, 0xd0, 0xf0, 0x20, 0x1c, 0xe2, 0xd7, 0x03, + 0xff, 0x12, 0x19, 0xd3, 0xd7, 0x12, 0x27, 0x03, 0xde, 0xfb, 0xf7, 0x07, + 0x24, 0x03, 0xde, 0xe2, 0x19, 0x19, 0x07, 0xe9, 0xe9, 0x19, 0x15, 0xff, + 0xd7, 0xdb, 0x15, 0x2e, 0x03, 0xdb, 0xdb, 0xfb, 0x0e, 0x00, 0x00, 0xff, + 0xe9, 0xf7, 0x15, 0x07, 0xed, 0xf7, 0x00, 0xff, 0x00, 0x0e, 0xf7, 0xe9, + 0x2b, 0x03, 0xd0, 0xf7, 0x0a, 0x19, 0x0a, 0x00, 0xf7, 0xdb, 0xf0, 0x32, + 0x12, 0xe2, 0x00, 0x0a, 0xd3, 0xed, 0x24, 0x15, 0xe2, 0xf4, 0x2e, 0x07, + 0xf0, 0xe5, 0xde, 0x07, 0x27, 0xf4, 0xe2, 0x1c, 0xfb, 0xc9, 0x00, 0x2e, + 0x00, 0xe9, 0x07, 0x0a, 0xe2, 0xd7, 0x03, 0x1c, 0x15, 0xf4, 0xe5, 0x0e, + 0x15, 0xfb, 0xed, 0xed, 0x12, 0xed, 0x1c, 0x32, 0xf7, 0xdb, 0xde, 0xf0, + 0x0a, 0x27, 0x12, 0x03, 0xfb, 0xd7, 0xe5, 0x07, 0x20, 0x1c, 0xf4, 0xf4, + 0xe5, 0xf0, 0x24, 0x00, 0xfb, 0xf7, 0xf7, 0xf0, 0x1c, 0x20, 0xd3, 0xd0, + 0x0a, 0x07, 0xe2, 0x2e, 0x24, 0xf7, 0xd7, 0xe9, 0xff, 0xf7, 0x12, 0x24, + 0x00, 0xcc, 0xe2, 0x20, 0x2b, 0x00, 0xd7, 0xf4, 0x0e, 0xed, 0x0e, 0x24, + 0xe9, 0xcc, 0xff, 0x2b, 0x15, 0x00, 0x00, 0x03, 0xd3, 0xdb, 0x03, 0x24, + 0x24, 0xff, 0xd7, 0x00, 0x00, 0xe5, 0x2e, 0x12, 0xd3, 0xde, 0x12, 0x1c, + 0xf7, 0x07, 0xf0, 0xd3, 0x00, 0x24, 0x15, 0xe2, 0xf7, 0x19, 0xe2, 0xd7, + 0x12, 0x27, 0x0e, 0xfb, 0xd7, 0xe5, 0x0e, 0x00, 0x0a, 0x19, 0xe9, 0xcc, + 0x00, 0x27, 0x0e, 0xe9, 0xe9, 0xed, 0x07, 0x27, 0x0e, 0xdb, 0xf4, 0x15, + 0xed, 0xf7, 0x19, 0xff, 0xff, 0x27, 0xf4, 0xdb, 0xff, 0x32, 0x20, 0xff, + 0xf4, 0xed, 0xde, 0xff, 0x2e, 0xff, 0xc5, 0xfb, 0x27, 0x00, 0xcc, 0x0e, + 0x1c, 0xd0, 0xe2, 0x1c, 0x07, 0xdb, 0x0a, 0x2b, 0x00, 0xf4, 0xed, 0xed, + 0x15, 0x0e, 0xf0, 0xf4, 0xed, 0xff, 0x15, 0x15, 0xff, 0x12, 0x00, 0xe9, + 0x00, 0x07, 0xf7, 0xe9, 0x1c, 0x24, 0xe5, 0xe9, 0x15, 0x07, 0xe5, 0x0e, + 0x07, 0xcc, 0x03, 0x39, 0x07, 0xd7, 0xe9, 0x0e, 0xf4, 0xfb, 0x2b, 0xed, + 0xc1, 0xe2, 0x07, 0x15, 0x19, 0x00, 0xff, 0xe5, 0xe5, 0x00, 0x00, 0x00, + 0xed, 0x03, 0x0a, 0xd3, 0x07, 0x2b, 0x00, 0xf4, 0xed, 0x00, 0x00, 0x03, + 0x27, 0x07, 0xde, 0xe2, 0x00, 0x27, 0x27, 0xf7, 0xd7, 0xd7, 0x0e, 0x2e, + 0x03, 0xf4, 0xf7, 0xe2, 0x0a, 0x20, 0xfb, 0xed, 0x19, 0xf7, 0xc1, 0xff, + 0x19, 0xfb, 0xff, 0x03, 0xd0, 0x03, 0x27, 0xe2, 0xf4, 0x20, 0xd3, 0xe2, + 0x24, 0x2b, 0xfb, 0xd3, 0x1c, 0x07, 0xc9, 0x19, 0x36, 0x07, 0xd7, 0x00, + 0x15, 0xe9, 0x27, 0x0a, 0xcc, 0xf0, 0x2b, 0x07, 0xe2, 0x19, 0x00, 0xf0, + 0xfb, 0xd0, 0x00, 0x2e, 0x19, 0xdb, 0xd3, 0xe9, 0xf4, 0x07, 0x20, 0x07, + 0xed, 0xf7, 0xe2, 0xf7, 0x27, 0x03, 0xdb, 0x03, 0x15, 0xf7, 0xf4, 0x0a, + 0x00, 0xe9, 0xff, 0xff, 0x0a, 0x07, 0x07, 0xe9, 0xed, 0x1c, 0x0a, 0xed, + 0x03, 0x1c, 0xe2, 0xdb, 0x20, 0x19, 0xd7, 0xf7, 0x36, 0x0a, 0xdb, 0xf0, + 0x12, 0xe9, 0xfb, 0x1c, 0x0e, 0xf7, 0xed, 0x00, 0xe9, 0xf4, 0x03, 0x00, + 0x20, 0xff, 0xcc, 0xe5, 0x12, 0x20, 0x03, 0xfb, 0xe2, 0xe9, 0x15, 0x12, + 0xfb, 0xd3, 0xf4, 0x24, 0x0e, 0x00, 0x07, 0xfb, 0xdb, 0xf0, 0x07, 0x19, + 0x27, 0xf4, 0xdb, 0x03, 0x0e, 0xe5, 0x0a, 0x20, 0xe2, 0xdb, 0x19, 0x1c, + 0xd7, 0xf4, 0x19, 0xe2, 0xe9, 0x12, 0x20, 0x00, 0xf0, 0xf7, 0xdb, 0xed, + 0x20, 0x27, 0x00, 0xcc, 0xdb, 0x0e, 0x24, 0x00, 0xe9, 0xf7, 0x0a, 0xff, + 0x0e, 0x27, 0xf4, 0xd3, 0xe9, 0x0a, 0x07, 0x12, 0x0a, 0x03, 0x00, 0xe9, + 0xd3, 0x00, 0x20, 0x1c, 0x00, 0xe5, 0xd7, 0xf0, 0x20, 0x2b, 0xff, 0xe2, + 0xed, 0xdb, 0x15, 0x2b, 0xf7, 0xcc, 0xff, 0x07, 0x07, 0x03, 0x0e, 0xf7, + 0xdb, 0x15, 0x00, 0xd0, 0x0a, 0x32, 0x03, 0xf4, 0xf4, 0xe9, 0x0e, 0x2b, + 0xf0, 0xc9, 0xe2, 0x15, 0x27, 0x15, 0xfb, 0xed, 0xe2, 0xe9, 0x12, 0x1c, + 0xe5, 0xed, 0x12, 0xfb, 0xe9, 0x07, 0x0e, 0x0e, 0xff, 0xf7, 0xff, 0xdb, + 0x0a, 0x15, 0xe2, 0xed, 0x07, 0x15, 0x19, 0x0a, 0xe2, 0xf0, 0xf0, 0xed, + 0x27, 0x24, 0xed, 0xe2, 0x12, 0xf7, 0xff, 0x1c, 0x00, 0xd0, 0xf0, 0x2b, + 0x03, 0xdb, 0x07, 0x2b, 0xf0, 0xd0, 0xfb, 0x0e, 0x03, 0x12, 0xfb, 0xe5, + 0xf7, 0xff, 0x2b, 0x2b, 0xf7, 0xe2, 0xe9, 0xf7, 0xed, 0xff, 0x0e, 0x24, + 0xf7, 0xd7, 0xf4, 0x0e, 0x15, 0x0e, 0xf4, 0xd3, 0xe2, 0x12, 0x19, 0x0e, + 0x12, 0xe5, 0xcc, 0xf7, 0x20, 0xff, 0x03, 0x1c, 0xdb, 0xe2, 0x27, 0x32, + 0x00, 0xe9, 0x15, 0xe9, 0xc9, 0x00, 0x27, 0x12, 0xf0, 0x00, 0xf7, 0xd7, + 0x15, 0x2b, 0x00, 0xd7, 0xe2, 0xf7, 0x15, 0x27, 0xf4, 0xe9, 0x0a, 0xe2, + 0xf4, 0x19, 0x12, 0xed, 0xd7, 0xff, 0x0a, 0xf4, 0x12, 0x2b, 0xfb, 0xe2, + 0xd0, 0xf4, 0x24, 0x0e, 0xf4, 0xf4, 0xe5, 0x0e, 0x2e, 0x00, 0xd0, 0xf4, + 0x2b, 0x00, 0xed, 0x19, 0x00, 0xd7, 0x19, 0x24, 0xe5, 0xf4, 0x19, 0x19, + 0xe9, 0xcc, 0xe5, 0x0a, 0x15, 0x20, 0x00, 0xdb, 0xe9, 0x0a, 0x20, 0x12, + 0xe5, 0xd0, 0xf0, 0x15, 0x2b, 0x12, 0xdb, 0xf0, 0x15, 0xe5, 0xe9, 0x15, + 0x12, 0xe2, 0xf0, 0x24, 0xf0, 0xd7, 0x07, 0x27, 0x0a, 0xcc, 0xe2, 0x24, + 0x1c, 0xe9, 0x07, 0x00, 0xd3, 0x24, 0x36, 0x00, 0xe2, 0xf7, 0x0e, 0xe9, + 0xe9, 0x07, 0x24, 0x12, 0xf7, 0xed, 0x00, 0xfb, 0x00, 0x2b, 0xed, 0xe2, + 0x20, 0x03, 0xd3, 0xf7, 0x00, 0xf7, 0x12, 0x0e, 0xe2, 0xde, 0x03, 0x2b, + 0x00, 0xde, 0xf0, 0x00, 0xf0, 0x12, 0xff, 0xde, 0x0a, 0x0e, 0xff, 0xe2, + 0xfb, 0x1c, 0x1c, 0xff, 0xed, 0xf0, 0x12, 0x19, 0x19, 0x00, 0xdb, 0xe9, + 0x27, 0x0a, 0xd0, 0x0a, 0x27, 0xe9, 0xe2, 0x2e, 0x19, 0xe2, 0xf4, 0x00, + 0xdb, 0x07, 0x15, 0xe2, 0xde, 0x00, 0x03, 0x07, 0x03, 0xf7, 0xe5, 0xf0, + 0x20, 0x03, 0xdb, 0x0e, 0x2e, 0xf7, 0xe5, 0xff, 0xe5, 0x00, 0x12, 0x07, + 0xf4, 0xf7, 0x2e, 0x19, 0xed, 0xf4, 0xfb, 0xf7, 0x03, 0x1c, 0x0e, 0xed, + 0xcc, 0xe9, 0x1c, 0x27, 0x15, 0xe2, 0xde, 0xfb, 0x15, 0x00, 0xe2, 0x00, + 0x03, 0x00, 0x0e, 0xfb, 0xd3, 0x07, 0x0e, 0xf4, 0xf4, 0xe2, 0x00, 0x2b, + 0x1c, 0xf7, 0xd3, 0xdb, 0x15, 0x32, 0x15, 0xde, 0xd0, 0xf7, 0x24, 0xf4, + 0xf4, 0x27, 0x12, 0xf4, 0x00, 0xff, 0xd0, 0x00, 0x2e, 0x1c, 0xe5, 0xd3, + 0xf7, 0x2e, 0x15, 0xe5, 0xde, 0xed, 0xf0, 0x15, 0x2b, 0x0a, 0xe2, 0xd7, + 0xff, 0x20, 0xf4, 0xde, 0x12, 0x07, 0xd0, 0xf0, 0x24, 0x07, 0xe2, 0x15, + 0x2b, 0xe5, 0xdb, 0x03, 0x0e, 0xff, 0xed, 0x0e, 0x03, 0xfb, 0x19, 0x0a, + 0xe2, 0xd3, 0x07, 0x12, 0xf7, 0x0a, 0x0a, 0x00, 0xfb, 0xfb, 0x00, 0x00, + 0xe2, 0xed, 0x0e, 0x1c, 0xde, 0xd7, 0x19, 0x0e, 0xf4, 0x0e, 0x0a, 0xf7, + 0xd0, 0xf0, 0x15, 0xf7, 0x00, 0x27, 0x12, 0xe2, 0xe2, 0x00, 0x0a, 0xf7, + 0x12, 0x20, 0xed, 0xd7, 0xf4, 0x15, 0x12, 0x00, 0xf4, 0x03, 0xe9, 0xe2, + 0x00, 0x1c, 0x15, 0xe9, 0xf0, 0x12, 0xf4, 0xfb, 0x27, 0x07, 0xd7, 0xe2, + 0xf7, 0xff, 0x27, 0x12, 0xff, 0xf4, 0xd3, 0xff, 0x07, 0x24, 0x12, 0xd7, + 0xe2, 0x07, 0xff, 0x07, 0x27, 0x00, 0xe9, 0xd0, 0xe9, 0x1c, 0x20, 0x12, + 0xf4, 0xd3, 0xe5, 0x1c, 0x2b, 0x07, 0xe5, 0xed, 0xf4, 0xf0, 0x15, 0x15, + 0xf0, 0x03, 0xfb, 0xfb, 0x00, 0x12, 0xed, 0x03, 0x24, 0xe2, 0xd0, 0x00, + 0x2e, 0x0e, 0xe2, 0xd7, 0xe5, 0x0a, 0x24, 0x0e, 0xe5, 0xd7, 0x03, 0x20, + 0xf0, 0x00, 0x19, 0xd0, 0x00, 0x36, 0x00, 0xd0, 0xe2, 0x07, 0x20, 0x12, + 0xe5, 0xff, 0xfb, 0x07, 0x19, 0xe9, 0xe2, 0x0a, 0x15, 0xed, 0xf4, 0xfb, + 0x00, 0xff, 0x19, 0x15, 0xdb, 0xd7, 0x15, 0x39, 0x12, 0xe9, 0xe9, 0xf7, + 0xed, 0x20, 0x27, 0xed, 0xd7, 0xf0, 0xfb, 0xf7, 0xff, 0x20, 0x07, 0xed, + 0xff, 0xe5, 0xff, 0x2b, 0x03, 0xd7, 0xf0, 0x00, 0xe9, 0x15, 0x2e, 0x07, + 0xde, 0xde, 0x03, 0x0a, 0x03, 0x24, 0x00, 0xd7, 0xed, 0x0a, 0x20, 0x19, + 0xdb, 0xde, 0x07, 0x00, 0xf4, 0x0e, 0xff, 0xf0, 0x15, 0x19, 0xe5, 0xe2, + 0x12, 0x19, 0xff, 0xfb, 0xde, 0xf0, 0x15, 0x1c, 0xe9, 0xe2, 0x24, 0x00, + 0xc9, 0x03, 0x20, 0xf7, 0xf0, 0x0a, 0xf0, 0xf0, 0x07, 0x07, 0xed, 0x00, + 0x19, 0xfb, 0xdb, 0x00, 0x0e, 0x00, 0x15, 0x0e, 0xdb, 0xe9, 0x0e, 0x12, + 0x0e, 0xf7, 0xd3, 0x0a, 0x36, 0x0e, 0xe5, 0xf7, 0x03, 0xde, 0x03, 0x32, + 0xf7, 0xd0, 0xed, 0x0e, 0xf7, 0xfb, 0x0a, 0xf4, 0x0a, 0x15, 0xed, 0xd3, + 0xed, 0x00, 0x0e, 0x27, 0x00, 0xcc, 0xf7, 0x32, 0x03, 0xd0, 0xf0, 0x20, + 0x1c, 0x07, 0x03, 0xde, 0xd3, 0x00, 0x24, 0x20, 0xf4, 0xd7, 0x07, 0x36, + 0x00, 0xd3, 0xfb, 0x15, 0x03, 0xff, 0x19, 0x00, 0xd7, 0xf4, 0x12, 0xed, + 0xe5, 0x24, 0x27, 0xf4, 0xed, 0xff, 0xd7, 0xed, 0x20, 0x24, 0xff, 0xdb, + 0xf0, 0xed, 0x03, 0x2b, 0x00, 0xde, 0xe5, 0x00, 0x24, 0x15, 0xff, 0xed, + 0xe5, 0x00, 0x0e, 0x15, 0xff, 0xe2, 0x07, 0x07, 0xe2, 0xf7, 0x27, 0x27, + 0x00, 0xf7, 0xde, 0xde, 0x15, 0x32, 0x00, 0xe5, 0x0e, 0xde, 0xde, 0x19, + 0x19, 0xe2, 0xc9, 0x07, 0x20, 0x03, 0xf7, 0x03, 0xe5, 0xd3, 0x0e, 0x20, + 0x0a, 0xe2, 0xed, 0x0e, 0x07, 0xf7, 0x03, 0x15, 0x0a, 0xff, 0xfb, 0xed, + 0xe2, 0x0a, 0x27, 0x12, 0xde, 0xf7, 0x20, 0xff, 0xdb, 0xe2, 0x19, 0x27, + 0x03, 0xe5, 0xf0, 0x00, 0x03, 0x03, 0xf7, 0xff, 0x07, 0xe5, 0xd3, 0x15, + 0x1c, 0xd7, 0xf0, 0x32, 0xff, 0xe2, 0x12, 0x07, 0xe2, 0x00, 0xff, 0xf4, + 0x2e, 0x1c, 0xe2, 0xd7, 0x0a, 0x19, 0xed, 0xf4, 0xff, 0xf4, 0x2b, 0x0e, + 0xd7, 0xed, 0x20, 0x00, 0xdb, 0x0e, 0x12, 0xe9, 0x00, 0x00, 0xf4, 0xff, + 0x15, 0xff, 0x0e, 0x0e, 0xe9, 0xe2, 0xe2, 0x00, 0x1c, 0x19, 0xf7, 0xe2, + 0x15, 0x19, 0xd7, 0xe9, 0x19, 0xf4, 0xde, 0x24, 0x20, 0xe9, 0xde, 0x07, + 0x0e, 0xfb, 0x03, 0xff, 0xe5, 0x12, 0xff, 0xd3, 0x0e, 0x36, 0x20, 0xfb, + 0xed, 0xf0, 0xe5, 0xf4, 0x24, 0x15, 0xde, 0xed, 0x07, 0xf4, 0x1c, 0x24, + 0xe9, 0xd0, 0xde, 0x0e, 0x24, 0x07, 0xe9, 0xf0, 0xf7, 0xf0, 0x15, 0x2b, + 0xff, 0xd7, 0xf4, 0x00, 0xde, 0x03, 0x2e, 0x20, 0xf4, 0xd3, 0xdb, 0x07, + 0x27, 0x24, 0xe9, 0xc9, 0xf4, 0x2b, 0x24, 0x00, 0xfb, 0xf4, 0xe5, 0xfb, + 0x12, 0x24, 0xe9, 0xe2, 0x0a, 0x00, 0xd7, 0x07, 0x2b, 0x03, 0xe5, 0xd0, + 0xf4, 0x0a, 0x1c, 0x00, 0xf0, 0x12, 0x00, 0xed, 0x0a, 0x12, 0xd0, 0xde, + 0x1c, 0x24, 0xff, 0xff, 0x2e, 0xf7, 0xd7, 0xf4, 0x0e, 0xf4, 0x00, 0x27, + 0xf7, 0xd3, 0x00, 0x12, 0x00, 0xff, 0xed, 0xe2, 0x1c, 0x1c, 0xfb, 0xfb, + 0xe2, 0xed, 0x20, 0x32, 0xff, 0xdb, 0xe9, 0xed, 0x00, 0x15, 0xfb, 0xfb, + 0x20, 0x03, 0xd0, 0xe5, 0x07, 0x07, 0x15, 0x12, 0xe9, 0xdb, 0x19, 0x24, + 0xfb, 0xf4, 0xfb, 0xed, 0xed, 0x0a, 0x1c, 0x00, 0xe5, 0xfb, 0x07, 0x0e, + 0x00, 0xfb, 0x03, 0xff, 0xdb, 0xe2, 0x00, 0x0a, 0x0a, 0x24, 0x0a, 0xde, + 0xde, 0x0a, 0x20, 0x03, 0x00, 0xed, 0xe5, 0x03, 0x24, 0x07, 0xdb, 0xf0, + 0xf7, 0x0a, 0x03, 0xfb, 0x00, 0x0a, 0x15, 0xe9, 0xd7, 0x03, 0x12, 0x00, + 0x0e, 0xf7, 0xcc, 0xff, 0x24, 0x00, 0xe9, 0x12, 0x0a, 0xed, 0xff, 0xed, + 0xff, 0x2b, 0x12, 0xd3, 0xe9, 0x0a, 0xf0, 0x03, 0x03, 0xfb, 0xf7, 0x0e, + 0x12, 0x07, 0x07, 0xed, 0xed, 0x03, 0x0a, 0xf4, 0x00, 0x12, 0xe2, 0xd0, + 0x0e, 0x12, 0xff, 0x0e, 0x0a, 0xf0, 0xf4, 0xfb, 0xfb, 0x00, 0xff, 0x15, + 0x03, 0xe2, 0xf0, 0x1c, 0x07, 0xe5, 0xe9, 0x1c, 0x20, 0xe5, 0xe5, 0x0a, + 0x00, 0x00, 0x24, 0xf4, 0xcc, 0xe2, 0x0a, 0x15, 0x15, 0x15, 0xe2, 0xde, + 0x15, 0x12, 0xf0, 0xfb, 0x1c, 0x00, 0xf7, 0xf0, 0xff, 0x07, 0x19, 0x00, + 0xcc, 0xf4, 0x20, 0x00, 0xf7, 0xfb, 0xfb, 0x0e, 0xf0, 0xf7, 0x20, 0x1c, + 0xde, 0xd0, 0xe5, 0x0e, 0x12, 0x0e, 0x12, 0xed, 0xde, 0x07, 0x1c, 0xed, + 0xe5, 0x0e, 0x20, 0xed, 0xdb, 0x0e, 0x00, 0xfb, 0x2e, 0x03, 0xd7, 0xf7, + 0x1c, 0x0a, 0xe2, 0xf4, 0x27, 0x03, 0xe9, 0x03, 0x0e, 0xff, 0xd7, 0xe2, + 0x07, 0xfb, 0x07, 0x20, 0xe9, 0xf7, 0x19, 0xf4, 0xed, 0x03, 0xff, 0x00, + 0xfb, 0xe9, 0x12, 0x12, 0xf0, 0xf7, 0x15, 0x00, 0xdb, 0x00, 0x0e, 0x00, + 0xf7, 0x15, 0x0a, 0xf7, 0xf7, 0xed, 0x00, 0x19, 0x00, 0xfb, 0xdb, 0xf7, + 0x20, 0x07, 0xfb, 0x19, 0xe5, 0xd3, 0x00, 0x12, 0x12, 0x0a, 0x03, 0xde, + 0xde, 0x00, 0x1c, 0x20, 0x00, 0xe9, 0xe2, 0x03, 0x0a, 0xf4, 0xff, 0xfb, + 0x12, 0x07, 0xe5, 0xe9, 0x07, 0x0a, 0x0a, 0x00, 0xd7, 0xfb, 0x20, 0x24, + 0xf0, 0xd3, 0xf7, 0x1c, 0x0e, 0x00, 0x00, 0xf7, 0xe2, 0x00, 0x1c, 0x00, + 0xe2, 0x0e, 0x0a, 0xff, 0x03, 0xd3, 0xfb, 0x2e, 0xff, 0xe2, 0x0a, 0x00, + 0xd0, 0x00, 0x20, 0x03, 0xff, 0x07, 0xf0, 0xcc, 0x0a, 0x32, 0x00, 0xd7, + 0xff, 0x03, 0xf0, 0xf0, 0x1c, 0x15, 0xe5, 0xed, 0xf4, 0xf7, 0x12, 0x03, + 0xf4, 0x07, 0xff, 0xf4, 0x0e, 0xf7, 0x00, 0x03, 0xe5, 0xed, 0x12, 0x27, + 0x12, 0xf0, 0xde, 0xf7, 0x15, 0x00, 0xf0, 0x0e, 0x15, 0xf4, 0xe9, 0x00, + 0xfb, 0xed, 0xf7, 0x1c, 0x24, 0xe9, 0xcc, 0xed, 0x27, 0x12, 0xdb, 0xfb, + 0x19, 0x12, 0x0e, 0xf0, 0xdb, 0xdb, 0x00, 0x27, 0x12, 0xde, 0xe2, 0x1c, + 0x27, 0xf4, 0xe5, 0xed, 0xff, 0x00, 0x20, 0x1c, 0xde, 0xd7, 0x15, 0x36, + 0x00, 0xd7, 0xfb, 0x20, 0x00, 0xed, 0xf7, 0xed, 0x03, 0x32, 0x0e, 0xf4, + 0xe2, 0xd0, 0x00, 0x24, 0x1c, 0xe9, 0xde, 0xf7, 0x00, 0x24, 0x00, 0xd3, + 0xed, 0x12, 0x0e, 0xde, 0xff, 0x0a, 0x03, 0xff, 0xe5, 0xf4, 0x03, 0x24, + 0x12, 0xe2, 0xd7, 0xe9, 0x0e, 0x24, 0x27, 0xfb, 0xe2, 0x0e, 0x00, 0xde, + 0x00, 0x1c, 0xff, 0xf7, 0x1c, 0xe5, 0xe5, 0x20, 0x20, 0xe9, 0xe5, 0xf7, + 0xe5, 0x00, 0x15, 0xff, 0xf0, 0x15, 0x15, 0xf0, 0xde, 0x00, 0x19, 0xf0, + 0xe5, 0x07, 0x03, 0xe2, 0x0a, 0x20, 0xf4, 0xdb, 0xf0, 0x0e, 0x0e, 0x00, + 0x0a, 0xf7, 0xd0, 0x03, 0x32, 0x07, 0xdb, 0xff, 0x19, 0x03, 0xdb, 0xed, + 0x1c, 0x24, 0x00, 0xfb, 0xf0, 0xd3, 0x03, 0x2b, 0x03, 0xe5, 0xe2, 0xed, + 0x0e, 0x24, 0x0e, 0xe9, 0xed, 0x07, 0x07, 0xff, 0xed, 0xe5, 0xf7, 0x19, + 0x19, 0xe5, 0xed, 0x1c, 0x00, 0xc5, 0xe2, 0x15, 0x12, 0x03, 0x03, 0xf0, + 0xf4, 0x1c, 0x19, 0xe2, 0xed, 0x12, 0x00, 0xfb, 0x03, 0x12, 0x12, 0xed, + 0xdb, 0x0e, 0x2e, 0xf4, 0xd7, 0xff, 0xfb, 0xdb, 0x0e, 0x2b, 0x12, 0xe5, + 0xe5, 0x03, 0xff, 0xdb, 0x19, 0x0e, 0xe9, 0xf7, 0x00, 0x03, 0x15, 0x00, + 0xd7, 0xe2, 0x0a, 0x03, 0x00, 0x12, 0xf7, 0xe2, 0x00, 0x15, 0xff, 0x0e, + 0x1c, 0xff, 0xd7, 0xe2, 0x0e, 0x24, 0x12, 0xf7, 0xf4, 0xfb, 0x00, 0x07, + 0x00, 0xe2, 0xed, 0x03, 0x07, 0x0a, 0x00, 0xff, 0xff, 0xe9, 0xe9, 0x03, + 0x07, 0xf7, 0x0e, 0x03, 0xd7, 0xf4, 0x24, 0x0a, 0xe5, 0x07, 0xfb, 0xed, + 0xed, 0x07, 0x1c, 0x00, 0xfb, 0xde, 0xfb, 0x20, 0x15, 0xfb, 0xde, 0xed, + 0x0e, 0x20, 0x0e, 0xf4, 0xd7, 0xe9, 0x12, 0x19, 0x0a, 0xff, 0xe5, 0xe9, + 0x1c, 0x19, 0xde, 0xe2, 0x12, 0x12, 0xe9, 0xed, 0xf7, 0x0e, 0x15, 0xf7, + 0xed, 0xed, 0xf0, 0x12, 0x27, 0x00, 0xd7, 0xe9, 0x07, 0x2b, 0x03, 0xe5, + 0xf4, 0x00, 0xf4, 0x19, 0x1c, 0xe9, 0xd7, 0x00, 0x32, 0x1c, 0xf0, 0xde, + 0xf0, 0x0a, 0x0e, 0xed, 0xde, 0x0a, 0x2b, 0x03, 0xde, 0xd3, 0x00, 0x2b, + 0x12, 0xf4, 0xe9, 0xf4, 0x07, 0x07, 0x07, 0x00, 0xd0, 0xf4, 0x1c, 0x0e, + 0xf0, 0xe9, 0xf4, 0xf4, 0x20, 0x20, 0xfb, 0xf0, 0xed, 0xff, 0x0a, 0x00, + 0xf4, 0x00, 0x00, 0xff, 0x0a, 0xf7, 0xe9, 0xff, 0x24, 0x1c, 0xde, 0xde, + 0x15, 0x1c, 0x00, 0xed, 0xf4, 0xff, 0x0a, 0x0e, 0xed, 0xfb, 0xff, 0xf0, + 0xf0, 0x15, 0x12, 0xe2, 0x00, 0x1c, 0xed, 0xde, 0x07, 0xf7, 0xe9, 0x00, + 0x12, 0x00, 0x0a, 0x0a, 0xf7, 0xe9, 0x0a, 0x24, 0xf4, 0xd7, 0x03, 0x20, + 0xf7, 0x00, 0x15, 0xd7, 0xf0, 0x27, 0xf4, 0xd7, 0x19, 0x12, 0xde, 0xf0, + 0x15, 0x24, 0x03, 0xf0, 0xe5, 0xf0, 0x00, 0x00, 0x20, 0x03, 0xd7, 0xf0, + 0x20, 0x1c, 0xff, 0xe9, 0xf4, 0x03, 0xff, 0xe2, 0xff, 0x24, 0x07, 0xe5, + 0xe5, 0x0e, 0x27, 0x00, 0xd7, 0xdb, 0x15, 0x12, 0x00, 0x03, 0xf0, 0xff, + 0xfb, 0x0a, 0x00, 0xff, 0xe2, 0xfb, 0x20, 0xf7, 0xed, 0x00, 0x0e, 0x19, + 0xf7, 0xe9, 0xfb, 0x00, 0x0e, 0x12, 0xe5, 0xd7, 0x19, 0x2b, 0x00, 0xf0, + 0xf0, 0xe5, 0xf7, 0x12, 0x2b, 0x07, 0xde, 0xd7, 0xfb, 0x2e, 0x15, 0xdb, + 0xcc, 0x00, 0x27, 0x03, 0xe2, 0xde, 0x00, 0x1c, 0x03, 0xe2, 0xf7, 0x0e, + 0x00, 0xff, 0xf4, 0xff, 0xf4, 0x20, 0x24, 0xfb, 0xdb, 0xe2, 0x0a, 0x27, + 0x20, 0xe9, 0xd3, 0xf7, 0x32, 0x12, 0xdb, 0xed, 0x07, 0xf7, 0x0a, 0x0e, + 0x03, 0xfb, 0xe2, 0x03, 0x03, 0x0a, 0x03, 0xf0, 0x03, 0x00, 0xe5, 0xe5, + 0x0a, 0x24, 0xff, 0xf4, 0xe2, 0xe9, 0x00, 0x20, 0x12, 0xde, 0xe9, 0x0a, + 0x03, 0x03, 0x1c, 0xf0, 0xcc, 0xf7, 0x27, 0x2b, 0x0e, 0xf0, 0xde, 0xf7, + 0x07, 0x0a, 0xff, 0x0a, 0x00, 0xe2, 0x00, 0x0e, 0x0a, 0x03, 0xf7, 0xd7, + 0xe9, 0x0e, 0x07, 0xfb, 0x12, 0xfb, 0xd3, 0x0a, 0x24, 0x00, 0x00, 0xfb, + 0xd0, 0xde, 0x15, 0x27, 0x12, 0xed, 0xe9, 0xdb, 0x0e, 0x32, 0x0a, 0xdb, + 0xe5, 0x00, 0x00, 0x0a, 0x20, 0x03, 0xde, 0xed, 0x07, 0xf4, 0x0a, 0x15, + 0xf7, 0xd7, 0xff, 0x19, 0x0e, 0x0e, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0xf7, + 0x0e, 0xfb, 0xd7, 0xfb, 0x19, 0x1c, 0x0a, 0xf4, 0xd7, 0xe2, 0xff, 0x20, + 0x27, 0x00, 0xd7, 0xde, 0x19, 0x27, 0xe2, 0xd7, 0x07, 0xff, 0xff, 0x1c, + 0x0e, 0xf7, 0xed, 0x00, 0x00, 0xf0, 0x00, 0x0a, 0x07, 0x00, 0xd3, 0xe9, + 0x27, 0x20, 0x0a, 0x00, 0xe9, 0xd3, 0xf0, 0x20, 0x24, 0xe9, 0xd3, 0x07, + 0x07, 0x00, 0x07, 0xf0, 0xdb, 0xf4, 0x19, 0xff, 0x00, 0xf4, 0xf7, 0x15, + 0x19, 0xf4, 0xd0, 0x0e, 0x2b, 0x07, 0xe5, 0xd3, 0x03, 0x2e, 0x19, 0xfb, + 0xfb, 0x00, 0xe5, 0xf0, 0x19, 0x12, 0xe5, 0xff, 0x15, 0xe2, 0xe5, 0x15, + 0x0a, 0x00, 0xed, 0xdb, 0x00, 0x15, 0x12, 0xed, 0xe9, 0x12, 0xff, 0xcc, + 0x00, 0x27, 0x0a, 0xe2, 0xe2, 0x0a, 0x15, 0x0e, 0x19, 0xf7, 0xdb, 0xed, + 0x1c, 0x07, 0xe9, 0x00, 0xf7, 0xf7, 0x20, 0x0e, 0xdb, 0xe2, 0x12, 0xfb, + 0xed, 0x27, 0x12, 0xe5, 0xe5, 0x00, 0x03, 0x0e, 0x00, 0x00, 0xff, 0xdb, + 0xf7, 0x1c, 0x20, 0xe2, 0xed, 0x2b, 0x00, 0xd0, 0x03, 0x20, 0xe9, 0xe9, + 0xf7, 0xf4, 0x07, 0x20, 0x0e, 0xe5, 0xd3, 0x00, 0x12, 0x0a, 0x0e, 0xe2, + 0xdb, 0x15, 0x24, 0xe9, 0xf7, 0x24, 0xf4, 0xcc, 0xf4, 0x0e, 0x24, 0x0e, + 0xf0, 0xf7, 0xfb, 0x00, 0xf7, 0x15, 0x00, 0xf4, 0xff, 0x00, 0x00, 0xe9, + 0x0e, 0x20, 0xe9, 0xdb, 0xfb, 0x19, 0x1c, 0xf7, 0xd7, 0xe9, 0x07, 0x2b, + 0x19, 0xdb, 0xd3, 0x00, 0x19, 0x00, 0xf4, 0xf4, 0x0a, 0x0a, 0xf7, 0x07, + 0x12, 0xe9, 0xde, 0xf7, 0x07, 0x1c, 0x03, 0xed, 0xde, 0x07, 0x15, 0xf0, + 0xf0, 0x24, 0x1c, 0xdb, 0xde, 0x07, 0x15, 0x03, 0x0a, 0xf7, 0xc5, 0xfb, + 0x20, 0x20, 0x03, 0xd3, 0xd7, 0x00, 0x2b, 0x20, 0xf0, 0xd3, 0xf4, 0x03, + 0xf7, 0x15, 0x19, 0xf7, 0xed, 0xff, 0x0e, 0xf7, 0xe9, 0x12, 0x12, 0xf4, + 0xe9, 0xfb, 0x0e, 0x20, 0x0e, 0xe2, 0xd3, 0xfb, 0x20, 0x20, 0x00, 0xe9, + 0xdb, 0xf4, 0x20, 0x24, 0xff, 0xd7, 0xe9, 0x0e, 0x00, 0xff, 0x19, 0xff, + 0xde, 0xff, 0x1c, 0x00, 0xe5, 0x03, 0x03, 0xe9, 0x0e, 0xff, 0xe9, 0x19, + 0x20, 0xe5, 0xdb, 0x00, 0x15, 0x00, 0xde, 0x00, 0x00, 0xf7, 0x0e, 0x12, + 0xfb, 0x00, 0x00, 0xe9, 0x00, 0x0a, 0x12, 0xff, 0xe5, 0xe9, 0x00, 0x1c, + 0x15, 0xe5, 0xcc, 0x03, 0x2b, 0x03, 0xde, 0xed, 0x19, 0x1c, 0x00, 0xf7, + 0xed, 0xe9, 0x0e, 0x0e, 0xf7, 0xe5, 0xf4, 0x0e, 0x20, 0x07, 0xe9, 0xe5, + 0x00, 0x1c, 0x00, 0xd7, 0xe2, 0xfb, 0x03, 0x15, 0x27, 0xfb, 0xcc, 0xf4, + 0x1c, 0x0a, 0xdb, 0xf0, 0x12, 0x20, 0x0e, 0xe5, 0xe9, 0x03, 0x19, 0x00, + 0x00, 0xf4, 0xf0, 0xff, 0x15, 0x07, 0xf0, 0x03, 0x20, 0x07, 0xe2, 0xd7, + 0xed, 0x0e, 0x00, 0xed, 0x03, 0x0e, 0x07, 0xff, 0xf7, 0xe5, 0xde, 0x07, + 0x19, 0xed, 0x00, 0x24, 0xfb, 0xe5, 0x00, 0x0e, 0x00, 0xfb, 0x00, 0xf7, + 0xf0, 0xfb, 0x19, 0x19, 0xff, 0xf7, 0xf0, 0x00, 0x12, 0x00, 0xcc, 0xf7, + 0x2b, 0x0e, 0xf4, 0x0a, 0x12, 0xf4, 0xf4, 0x00, 0xf4, 0xe9, 0x03, 0x20, + 0xff, 0xd3, 0xe9, 0x0a, 0x12, 0x03, 0xf4, 0xde, 0xfb, 0x19, 0x0a, 0xde, + 0xf0, 0x19, 0x03, 0x03, 0x19, 0xf4, 0xd3, 0xed, 0x0e, 0x27, 0x00, 0xdb, + 0x03, 0x27, 0xff, 0xde, 0x00, 0x0e, 0xff, 0xfb, 0x00, 0x00, 0x03, 0x00, + 0xf4, 0xf7, 0xff, 0x07, 0x12, 0x0a, 0xd3, 0xd7, 0x19, 0x24, 0xe5, 0xde, + 0x1c, 0x0e, 0xf0, 0xe9, 0xf7, 0xf4, 0x0a, 0x15, 0x03, 0xf0, 0xe2, 0x03, + 0x15, 0x0a, 0xde, 0xf0, 0x1c, 0x15, 0xf4, 0xd7, 0x07, 0x12, 0x00, 0x00, + 0xf4, 0x1c, 0xff, 0xe2, 0x12, 0x12, 0xe2, 0xe2, 0x27, 0x1c, 0xe2, 0xde, + 0x0a, 0x20, 0x15, 0xf0, 0xdb, 0xdb, 0x0e, 0x19, 0xfb, 0x03, 0xf4, 0xe5, + 0x0a, 0x2b, 0x00, 0xd3, 0xe9, 0x19, 0x24, 0xf7, 0xf4, 0xf7, 0xde, 0x1c, + 0x19, 0xf7, 0xf4, 0x12, 0x00, 0xf4, 0xde, 0xe5, 0x0a, 0x24, 0x19, 0xf4, + 0xe9, 0xe9, 0xfb, 0x24, 0x12, 0xed, 0xe5, 0xfb, 0x0e, 0x15, 0x12, 0xfb, + 0xf4, 0xe5, 0xe5, 0x0a, 0x20, 0x0e, 0xe2, 0xd3, 0xfb, 0x12, 0x1c, 0x0e, + 0xde, 0xde, 0xfb, 0x07, 0x00, 0x00, 0x00, 0xff, 0xf4, 0x07, 0x20, 0x00, + 0xe9, 0x0e, 0xf7, 0xd3, 0x03, 0x2e, 0x0e, 0xde, 0xf4, 0x12, 0xfb, 0x00, + 0x0a, 0xed, 0xf4, 0x0e, 0xed, 0xf4, 0x0e, 0x12, 0x03, 0xe9, 0xf0, 0x00, + 0x00, 0x03, 0x00, 0xe5, 0xdb, 0x12, 0x2b, 0x00, 0xe2, 0x00, 0x0e, 0xd3, + 0xe5, 0x19, 0x20, 0xfb, 0xde, 0xf0, 0x15, 0x20, 0x0a, 0xf0, 0xd3, 0xf0, + 0x0a, 0x19, 0x12, 0xf7, 0xfb, 0x00, 0x00, 0xed, 0x03, 0x0e, 0x0e, 0xf7, + 0xde, 0xf7, 0x00, 0x12, 0x07, 0xff, 0xfb, 0xf4, 0x00, 0x03, 0xf7, 0xf0, + 0x00, 0x0a, 0x00, 0x00, 0xf7, 0x0e, 0x0e, 0xe9, 0xd0, 0xf4, 0x19, 0x19, + 0x0e, 0xfb, 0xe5, 0xe2, 0x0e, 0x24, 0xf7, 0xe9, 0x03, 0x03, 0xff, 0xf7, + 0xf0, 0x00, 0x15, 0x15, 0x00, 0xed, 0xe2, 0xfb, 0x00, 0x0a, 0x15, 0x0e, + 0xff, 0xe2, 0xf7, 0x1c, 0x07, 0xde, 0xe5, 0x00, 0x12, 0x19, 0xff, 0xed, + 0x03, 0x00, 0xe9, 0xed, 0xf7, 0x24, 0x12, 0xff, 0xe5, 0xde, 0xf4, 0x1c, + 0x20, 0xed, 0xd7, 0x0a, 0x20, 0xf0, 0xe5, 0x0a, 0x0a, 0xf0, 0x03, 0x00, + 0xff, 0xff, 0x00, 0xff, 0xe5, 0x03, 0x12, 0x12, 0x0e, 0xe5, 0xe2, 0xfb, + 0xff, 0xff, 0x0e, 0x19, 0xff, 0xff, 0xf7, 0xe5, 0x00, 0x07, 0x0e, 0x00, + 0xe9, 0x00, 0x15, 0xff, 0xf4, 0xe5, 0xf4, 0x24, 0x15, 0xed, 0xf7, 0xe5, + 0xed, 0x03, 0x15, 0x07, 0xfb, 0x07, 0xfb, 0xff, 0x00, 0xf0, 0xf4, 0x07, + 0x15, 0x00, 0x00, 0xf4, 0xf7, 0xff, 0xe9, 0x03, 0x0e, 0x03, 0x00, 0x0a, + 0x0a, 0x00, 0xed, 0xe2, 0xfb, 0x27, 0x1c, 0xe5, 0xd0, 0xff, 0x1c, 0x00, + 0x00, 0xfb, 0xed, 0xf4, 0x0a, 0x0e, 0xfb, 0xe5, 0xf7, 0x03, 0xff, 0xe5, + 0x12, 0x27, 0xf7, 0xc9, 0xf0, 0x24, 0x00, 0xf7, 0x15, 0x15, 0xf4, 0xe2, + 0x03, 0x00, 0x00, 0x15, 0x00, 0xe9, 0xed, 0x12, 0x19, 0x00, 0xde, 0xed, + 0x27, 0x19, 0xf4, 0xed, 0xe2, 0x0a, 0x0e, 0xed, 0xf4, 0x0a, 0x15, 0xf7, + 0xe5, 0xe9, 0xff, 0x0e, 0x03, 0x15, 0xf7, 0xd3, 0x00, 0x1c, 0xf7, 0xf0, + 0x12, 0xff, 0xde, 0x07, 0x27, 0x00, 0xe9, 0xf4, 0x27, 0x0e, 0xd3, 0xe2, + 0x0e, 0x1c, 0xed, 0xe5, 0x0e, 0x00, 0xfb, 0x15, 0x00, 0xf0, 0xf7, 0x07, + 0x12, 0xf7, 0xfb, 0xf4, 0x00, 0x0a, 0x12, 0x0a, 0xe5, 0xe5, 0xff, 0xff, + 0x03, 0x03, 0x0a, 0x00, 0xff, 0xf4, 0xff, 0x0a, 0xfb, 0xfb, 0xfb, 0xe9, + 0x00, 0x15, 0x07, 0x07, 0xe9, 0xed, 0x12, 0x00, 0xf0, 0x00, 0x00, 0x00, + 0x0a, 0xf4, 0xfb, 0x0a, 0xf7, 0xed, 0x12, 0x07, 0xe5, 0xf4, 0x1c, 0x15, + 0xe5, 0xf7, 0x20, 0x00, 0xed, 0xff, 0xe9, 0xf0, 0x0e, 0x07, 0xfb, 0xf4, + 0x15, 0x03, 0x00, 0xf4, 0xe2, 0x03, 0x0e, 0x00, 0x07, 0xf7, 0xf4, 0xf4, + 0x00, 0x19, 0x15, 0xe9, 0xdb, 0x07, 0x19, 0x07, 0xd7, 0xf0, 0x27, 0x19, + 0xe9, 0xe5, 0xf4, 0x07, 0x07, 0xf0, 0x00, 0x00, 0x00, 0x1c, 0x07, 0xdb, + 0xe2, 0x00, 0x0e, 0x20, 0xfb, 0xdb, 0x00, 0x00, 0xfb, 0x00, 0x07, 0xff, + 0xe9, 0xfb, 0x12, 0xfb, 0x00, 0x00, 0xf0, 0xff, 0x0a, 0x24, 0xfb, 0xe2, + 0xe2, 0xfb, 0x12, 0xff, 0x07, 0x1c, 0xfb, 0xdb, 0xff, 0x1c, 0xf0, 0xf0, + 0x12, 0x03, 0xed, 0xf0, 0xfb, 0x20, 0x07, 0xe5, 0xed, 0x07, 0x1c, 0xf7, + 0xf7, 0x19, 0xff, 0xd3, 0x03, 0x24, 0xf0, 0xe5, 0x0a, 0x12, 0xde, 0xde, + 0x15, 0x0e, 0xe5, 0x00, 0x0e, 0xf7, 0xf4, 0x00, 0x03, 0x00, 0xed, 0x07, + 0x0a, 0xff, 0x00, 0x00, 0xe5, 0xed, 0x0a, 0x1c, 0x0e, 0xf0, 0xf0, 0x0e, + 0x00, 0xf0, 0x00, 0x00, 0x03, 0x07, 0xf4, 0xe2, 0x07, 0x20, 0xf4, 0xdb, + 0x19, 0x0a, 0xde, 0xf7, 0x07, 0xfb, 0x00, 0x07, 0xed, 0xe2, 0x07, 0x12, + 0xf7, 0xfb, 0x00, 0xf7, 0x07, 0x03, 0xfb, 0xf0, 0x00, 0x1c, 0x00, 0xf0, + 0xf4, 0xf7, 0xf7, 0x15, 0x19, 0xde, 0xf7, 0x15, 0x00, 0xff, 0xf7, 0x00, + 0x07, 0xed, 0x03, 0x24, 0xff, 0xde, 0xfb, 0x15, 0x0a, 0xe9, 0xf4, 0x07, + 0xed, 0x0e, 0x1c, 0xdb, 0xdb, 0x20, 0x19, 0xd7, 0xde, 0x07, 0x07, 0xfb, + 0xf7, 0xf7, 0xff, 0x12, 0x15, 0x00, 0x00, 0xf0, 0xde, 0x0a, 0x20, 0xde, + 0xdb, 0x27, 0x24, 0xed, 0xf0, 0x1c, 0xf4, 0xcc, 0x07, 0x2b, 0x0e, 0xe5, + 0xff, 0x12, 0xf0, 0xff, 0x12, 0x00, 0xff, 0xe9, 0xdb, 0x12, 0x19, 0xe9, + 0xed, 0x24, 0x03, 0xe9, 0xf4, 0x03, 0x00, 0xe5, 0xf4, 0x0a, 0xed, 0xf7, + 0x24, 0x15, 0xf0, 0xe5, 0xe5, 0x12, 0x15, 0xed, 0xfb, 0x12, 0x07, 0xf0, + 0x07, 0x0e, 0xed, 0xe9, 0x07, 0x0e, 0xed, 0x00, 0x03, 0xf0, 0x0e, 0x19, + 0xff, 0xe9, 0xe9, 0xfb, 0x12, 0x0e, 0xe2, 0xd3, 0x07, 0x27, 0x19, 0xf4, + 0xe5, 0xf7, 0x00, 0x00, 0xff, 0xf4, 0x00, 0x0e, 0x00, 0xfb, 0xfb, 0x07, + 0x00, 0xe2, 0xf4, 0x03, 0x00, 0x0e, 0x07, 0xed, 0xed, 0x15, 0x12, 0x00, + 0x07, 0xe2, 0xde, 0xfb, 0x12, 0x0e, 0x00, 0x0e, 0x03, 0xeb, 0xe7, 0x0e, + 0x1c, 0xf9, 0xee, 0xf2, 0xfd, 0x1c, 0x20, 0xf6, 0xd9, 0xe7, 0x15, 0x1c, + 0xf6, 0xee, 0x00, 0xfd, 0xe4, 0x03, 0x1c, 0x03, 0xfd, 0x00, 0xe7, 0xe7, + 0xfd, 0x0e, 0x20, 0x0a, 0xe4, 0xd9, 0x19, 0x24, 0xf2, 0x00, 0x12, 0xee, + 0xd9, 0x1c, 0x2e, 0x00, 0xe0, 0xfd, 0x19, 0xf2, 0xf9, 0x15, 0x03, 0xe0, + 0xf6, 0x12, 0x07, 0xf9, 0xf2, 0xf6, 0x19, 0x03, 0xca, 0xf2, 0x24, 0x20, + 0xeb, 0xd2, 0x00, 0x0e, 0x07, 0x00, 0xee, 0xf6, 0x07, 0x12, 0x03, 0xfd, + 0xe7, 0xfd, 0x15, 0x03, 0xf6, 0xf6, 0x00, 0x07, 0x0e, 0x00, 0x00, 0xf9, + 0xf6, 0x00, 0x00, 0x03, 0xfd, 0xf9, 0x00, 0x0a, 0x03, 0xeb, 0x00, 0x24, + 0xeb, 0xe0, 0xf2, 0x00, 0x00, 0x15, 0x24, 0xe7, 0xd2, 0xeb, 0x1c, 0x19, + 0x00, 0xf2, 0xe0, 0x00, 0x0e, 0x12, 0x07, 0xeb, 0x00, 0x00, 0xf6, 0x03, + 0x0a, 0xeb, 0xee, 0x12, 0x03, 0xfd, 0x0e, 0x15, 0x00, 0xe7, 0xe4, 0xf9, + 0x12, 0x29, 0x07, 0xf2, 0x00, 0x03, 0x00, 0xee, 0xf9, 0x03, 0x00, 0x07, + 0x03, 0x0a, 0xf9, 0xfd, 0xfd, 0xf9, 0xf6, 0x0e, 0x19, 0xe7, 0xdc, 0xee, + 0x03, 0x29, 0x12, 0xe4, 0xe7, 0x07, 0x0a, 0xf2, 0xf2, 0x03, 0x00, 0xe7, + 0x15, 0x22, 0x00, 0x00, 0x00, 0xe0, 0xdc, 0x0e, 0x2d, 0x0a, 0xdc, 0xf2, + 0x07, 0x00, 0x07, 0x0e, 0x00, 0xeb, 0xee, 0x00, 0x1b, 0x00, 0xf6, 0x03, + 0xf9, 0xfd, 0x1b, 0x12, 0xe0, 0xe0, 0xfd, 0x00, 0x00, 0x0a, 0x00, 0x07, + 0x0a, 0xee, 0xe0, 0xf6, 0xfd, 0x0e, 0x12, 0x00, 0x00, 0xf9, 0x00, 0x0a, + 0xdc, 0xee, 0x1b, 0x1b, 0xf6, 0xd7, 0x0a, 0x25, 0xeb, 0xee, 0x30, 0x00, + 0xdc, 0x00, 0x03, 0xf2, 0x0a, 0x17, 0xf6, 0xeb, 0x07, 0x13, 0x00, 0x00, + 0xf2, 0xdb, 0xf9, 0x17, 0x0e, 0x0a, 0x0a, 0xe0, 0xdb, 0xf6, 0x1e, 0x17, + 0xf6, 0x00, 0x00, 0xdc, 0xee, 0x17, 0x29, 0x00, 0xdb, 0xee, 0x07, 0xf9, + 0x0a, 0x25, 0x00, 0xd7, 0xe4, 0x1b, 0x22, 0xf9, 0x00, 0x03, 0xe4, 0xe7, + 0x03, 0x25, 0x22, 0xf9, 0xe0, 0xe4, 0x00, 0x1b, 0x0e, 0x03, 0xf2, 0xdb, + 0x00, 0x1e, 0x10, 0xe7, 0xee, 0x03, 0x07, 0xeb, 0x00, 0x1b, 0xf9, 0xd7, + 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0xe4, 0xf6, 0x0a, 0x0e, 0x00, 0xf9, + 0x0a, 0xfd, 0x0c, 0x0c, 0xeb, 0xe2, 0x10, 0x0a, 0xeb, 0x0c, 0x0a, 0xeb, + 0xf9, 0x17, 0x13, 0xf9, 0xf6, 0x00, 0xf6, 0xf6, 0x07, 0x0a, 0x0a, 0x00, + 0xf9, 0xe2, 0xf6, 0x13, 0x0a, 0xe7, 0xf9, 0x0c, 0xeb, 0x00, 0x2b, 0xf9, + 0xd3, 0x00, 0x13, 0x00, 0xf6, 0x07, 0x00, 0x03, 0xfd, 0xfd, 0x07, 0x13, + 0x03, 0xee, 0xf6, 0x10, 0xf9, 0xee, 0x1b, 0x1e, 0xeb, 0xde, 0x0a, 0x17, + 0xeb, 0xe2, 0xfd, 0x1e, 0x10, 0x00, 0xf6, 0xf9, 0xfd, 0x00, 0x07, 0xfd, + 0xee, 0xf9, 0x00, 0xf6, 0x03, 0x00, 0x00, 0x0c, 0x00, 0xe2, 0xf9, 0x13, + 0x00, 0xe9, 0xfd, 0xfd, 0x10, 0x17, 0xfd, 0x00, 0xeb, 0xe5, 0x07, 0x10, + 0x09, 0x07, 0x03, 0x07, 0xf6, 0xee, 0x0c, 0x07, 0xe5, 0x07, 0x1b, 0xe9, + 0xf2, 0x13, 0x0c, 0xed, 0xed, 0x07, 0x00, 0x09, 0x00, 0xf9, 0xfd, 0xf9, + 0xf9, 0xfd, 0x07, 0x13, 0xfd, 0xed, 0xf9, 0xf2, 0xfd, 0x09, 0x0c, 0x09, + 0x00, 0xfd, 0x00, 0xee, 0xe2, 0x10, 0x10, 0xed, 0xf9, 0x09, 0x0c, 0x0c, + 0x07, 0xe9, 0xf2, 0x00, 0x10, 0x1b, 0xf6, 0xf2, 0x00, 0x00, 0xf6, 0x00, + 0x1b, 0x07, 0xf9, 0xed, 0xed, 0xf9, 0x17, 0x13, 0xf2, 0xf9, 0x17, 0x00, + 0xdc, 0xe9, 0xee, 0x00, 0x10, 0x03, 0x00, 0x07, 0x00, 0xee, 0xfd, 0xed, + 0x00, 0x24, 0x13, 0xf6, 0xe9, 0xfd, 0x00, 0x07, 0x0c, 0x07, 0xee, 0x00, + 0x17, 0xed, 0xe9, 0x17, 0x20, 0xf0, 0xf9, 0x17, 0x00, 0xf2, 0xf2, 0xfd, + 0xf9, 0x00, 0x03, 0x20, 0x13, 0xf2, 0xdc, 0xe5, 0x0c, 0x13, 0x00, 0x00, + 0x00, 0xf0, 0xe2, 0x00, 0x24, 0x00, 0xd2, 0xfd, 0x0c, 0xed, 0x03, 0x09, + 0x00, 0x00, 0xfd, 0xf6, 0x0c, 0x1c, 0x00, 0xe5, 0xdc, 0xf6, 0x10, 0x15, + 0x1c, 0x03, 0xe5, 0xd5, 0x00, 0x25, 0x20, 0x07, 0xed, 0xf9, 0x03, 0xf9, + 0x0c, 0x10, 0xf9, 0xf2, 0xfd, 0xfd, 0x00, 0x15, 0x00, 0xd5, 0xe9, 0x10, + 0x15, 0xf6, 0x00, 0x09, 0xd9, 0xd5, 0x03, 0x19, 0x13, 0x03, 0x00, 0xf0, + 0xe5, 0x00, 0x1c, 0x1c, 0xf9, 0xed, 0xed, 0x05, 0x00, 0xf2, 0x00, 0x09, + 0x10, 0xfd, 0xf9, 0xf2, 0x03, 0x03, 0x00, 0x00, 0xf9, 0x05, 0x10, 0x05, + 0xe5, 0xf9, 0x0c, 0x00, 0xf9, 0x00, 0x13, 0xe4, 0xe5, 0x15, 0x09, 0xe0, + 0xf4, 0x19, 0x0c, 0xf4, 0xfd, 0x00, 0xed, 0xf6, 0x09, 0x15, 0x00, 0xf9, + 0x00, 0xf9, 0xf9, 0xfd, 0x0c, 0x15, 0x00, 0xe9, 0xf6, 0x09, 0xe9, 0x00, + 0x19, 0x10, 0xed, 0xe9, 0x0c, 0x15, 0x05, 0xe7, 0xe7, 0x05, 0x0c, 0x03, + 0x00, 0x09, 0xe4, 0xe0, 0x10, 0x09, 0xf0, 0x09, 0x15, 0xf0, 0xe4, 0x00, + 0x10, 0x00, 0x05, 0xfd, 0xed, 0x00, 0x15, 0x03, 0xe7, 0xf9, 0x00, 0xf9, + 0x15, 0x15, 0xf4, 0xf4, 0x0c, 0xf6, 0xe0, 0x09, 0x22, 0x0c, 0xf4, 0xfd, + 0x03, 0xf0, 0xfd, 0x09, 0xf6, 0xf9, 0x15, 0x0c, 0xf9, 0xf9, 0xf6, 0xf6, + 0x00, 0x19, 0x05, 0xed, 0xe7, 0xed, 0x00, 0x1c, 0x10, 0xf0, 0xf9, 0x05, + 0x00, 0xf4, 0xf4, 0xf9, 0x00, 0x0c, 0x00, 0xfd, 0x00, 0x09, 0x15, 0x00, + 0xdb, 0xed, 0x12, 0x10, 0x05, 0xf6, 0xf6, 0x10, 0x03, 0xe7, 0x00, 0x22, + 0xfd, 0xde, 0x00, 0x15, 0xf0, 0xeb, 0x19, 0x1e, 0xf9, 0xeb, 0xf6, 0x09, + 0x00, 0xeb, 0xfd, 0x05, 0x03, 0x09, 0x15, 0xf4, 0xde, 0xf9, 0x03, 0xf9, + 0x00, 0x12, 0x03, 0xfd, 0x00, 0xfd, 0xfd, 0xf9, 0x05, 0x00, 0xed, 0xfd, + 0x00, 0x00, 0x19, 0x09, 0xe4, 0x05, 0x19, 0x00, 0xeb, 0xed, 0x03, 0x15, + 0x00, 0xfd, 0x00, 0x05, 0x00, 0xf4, 0x00, 0x12, 0xf9, 0xed, 0x0e, 0x03, + 0xeb, 0xf4, 0x0c, 0x03, 0xf0, 0xfd, 0xfd, 0x03, 0x03, 0xf6, 0xf0, 0xed, + 0x00, 0x05, 0x15, 0x12, 0xe7, 0xe2, 0x0c, 0x0c, 0xf0, 0x05, 0x24, 0x00, + 0xed, 0xfd, 0xeb, 0xf4, 0x15, 0x20, 0x00, 0xeb, 0xf4, 0x00, 0x00, 0x09, + 0x0c, 0xed, 0xed, 0x09, 0x05, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x00, 0xe4, 0xf4, 0x09, 0x00, 0x00, 0x1b, 0xf4, 0xd5, 0xf4, + 0x1b, 0x09, 0xf7, 0x00, 0x12, 0xf9, 0xf4, 0x0c, 0x09, 0xf7, 0xeb, 0x09, + 0x0e, 0xf4, 0x00, 0x00, 0xf9, 0xee, 0xfd, 0x0e, 0x09, 0x00, 0x09, 0xf0, + 0xdc, 0x00, 0x0e, 0x0c, 0x0e, 0x00, 0xeb, 0xf9, 0x00, 0xf0, 0x05, 0x1b, + 0x00, 0xe7, 0x00, 0x20, 0xf7, 0xe5, 0xee, 0x00, 0x03, 0x03, 0x0e, 0x03, + 0xee, 0xe7, 0x03, 0x09, 0x15, 0x00, 0xe2, 0xf4, 0x0c, 0xf4, 0xf0, 0x1c, + 0x17, 0xf4, 0xee, 0x09, 0x05, 0xf0, 0xfd, 0xf7, 0xf9, 0x0c, 0x13, 0x09, + 0x00, 0xeb, 0xf7, 0xfd, 0x00, 0x13, 0x0a, 0xfd, 0xe2, 0xee, 0x0a, 0x13, + 0x00, 0xee, 0xfd, 0x0a, 0x00, 0xf0, 0x00, 0x05, 0xf4, 0x00, 0x05, 0x05, + 0x0a, 0xfd, 0xf4, 0x00, 0x00, 0xf0, 0x00, 0x20, 0x12, 0xf0, 0xee, 0x09, + 0x00, 0xf4, 0x12, 0x00, 0xf4, 0x03, 0xf9, 0xf0, 0x13, 0x13, 0xe9, 0xeb, + 0x12, 0x0e, 0xf4, 0xf9, 0xf9, 0xf0, 0x09, 0x09, 0x00, 0x09, 0x00, 0xeb, + 0xeb, 0xf9, 0x03, 0x00, 0x12, 0x1b, 0xf9, 0xeb, 0xf7, 0x0a, 0x0e, 0xf9, + 0xf0, 0x00, 0x05, 0xfd, 0x05, 0x00, 0xf4, 0x00, 0x03, 0x09, 0x0e, 0xeb, + 0xe9, 0x00, 0x00, 0x00, 0x13, 0x05, 0xee, 0xf9, 0x0a, 0xf4, 0xee, 0x17, + 0x12, 0xe9, 0xf4, 0x05, 0x00, 0x00, 0x00, 0xee, 0xf7, 0x0e, 0x03, 0xfd, + 0x12, 0xf2, 0xe4, 0x00, 0x0e, 0x00, 0x0a, 0xfd, 0xee, 0x05, 0xf9, 0xfd, + 0x17, 0x12, 0xf7, 0xe9, 0x05, 0x00, 0xeb, 0x17, 0x13, 0xee, 0xeb, 0x05, + 0x01, 0x01, 0x01, 0xf2, 0xf2, 0x00, 0x01, 0x00, 0xf7, 0x05, 0x01, 0xeb, + 0x00, 0x00, 0x00, 0x0a, 0x13, 0xf2, 0xe0, 0x0a, 0x19, 0xf2, 0xf7, 0x05, + 0xf7, 0xf7, 0x17, 0x09, 0xf9, 0xf4, 0xfd, 0x01, 0x00, 0x01, 0xf9, 0xf7, + 0x05, 0x00, 0xf2, 0x00, 0x01, 0x05, 0x09, 0xfd, 0xf2, 0xfd, 0xf9, 0x00, + 0x0a, 0x10, 0xfd, 0xe9, 0xfd, 0x09, 0x00, 0xf9, 0x00, 0x01, 0x01, 0x00, + 0xee, 0xf9, 0x05, 0x05, 0x00, 0x01, 0x09, 0xed, 0xe4, 0x09, 0x0e, 0xf9, + 0x00, 0x09, 0xf7, 0xe5, 0x09, 0x19, 0xfd, 0xf9, 0x09, 0xe9, 0xee, 0x19, + 0x15, 0xfd, 0xf4, 0x00, 0xf7, 0xf7, 0x19, 0x10, 0xf4, 0xf9, 0x00, 0xee, + 0x05, 0x19, 0x01, 0xe7, 0xed, 0x0a, 0x00, 0xfd, 0x10, 0x01, 0xe7, 0xed, + 0x00, 0x09, 0x0a, 0xf7, 0x00, 0x00, 0xe4, 0xf4, 0x09, 0x1b, 0x10, 0xf2, + 0xde, 0xfd, 0x13, 0x00, 0xfb, 0x00, 0x0a, 0x00, 0xed, 0x0e, 0x1b, 0xf7, + 0xf2, 0x01, 0x00, 0xf2, 0x10, 0x13, 0xed, 0xf4, 0x0a, 0x00, 0x00, 0x0e, + 0x00, 0xee, 0xf7, 0x00, 0x00, 0x01, 0x09, 0x05, 0xf7, 0x00, 0xf7, 0xed, + 0x15, 0x0a, 0xe9, 0xf4, 0x05, 0x09, 0x00, 0xee, 0xf7, 0x00, 0x00, 0x00, + 0x05, 0x00, 0xf7, 0xf7, 0x00, 0x20, 0x13, 0xed, 0xe7, 0xf7, 0x00, 0x05, + 0x15, 0x0e, 0xf2, 0xe7, 0xfd, 0x00, 0x13, 0x15, 0xf6, 0xe2, 0xf7, 0x07, + 0x01, 0x00, 0x13, 0x01, 0xed, 0xe9, 0x07, 0x1b, 0x0a, 0xf7, 0xe9, 0xf7, + 0xfb, 0x13, 0x20, 0xee, 0xdc, 0xee, 0x05, 0x0a, 0x00, 0x00, 0x00, 0xf6, + 0xf7, 0x05, 0x00, 0x00, 0x15, 0xfd, 0xe9, 0xf7, 0x00, 0x07, 0x1b, 0xfd, + 0xe7, 0xf6, 0x0c, 0x17, 0x01, 0xf6, 0xfb, 0x01, 0xf6, 0xfd, 0x17, 0x0c, + 0xe5, 0xeb, 0x15, 0x12, 0xf0, 0xf2, 0xf7, 0x01, 0x10, 0x0a, 0x00, 0xf6, + 0xed, 0xed, 0x00, 0x01, 0x07, 0x05, 0x00, 0xf7, 0xed, 0xf2, 0x0c, 0x1c, + 0x05, 0xeb, 0xf0, 0xfd, 0x07, 0x1b, 0xf7, 0xdc, 0xfd, 0x12, 0x0c, 0x01, + 0xfd, 0xf6, 0x00, 0xfb, 0x00, 0x12, 0x12, 0x00, 0xed, 0xed, 0xfd, 0x01, + 0x0c, 0x12, 0x07, 0xfb, 0xe2, 0xed, 0x0c, 0x22, 0x01, 0xe2, 0xf6, 0x00, + 0xfb, 0x0a, 0x0c, 0xf6, 0xe7, 0xf0, 0xfd, 0x12, 0x0a, 0xf2, 0xf0, 0x00, + 0x0a, 0x00, 0xf7, 0x07, 0x12, 0xf0, 0xdc, 0x00, 0x15, 0x07, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x0a, 0x00, 0xed, 0xf7, 0x10, 0x07, 0xfd, 0x05, 0x00, + 0xf7, 0xfd, 0x01, 0xf6, 0xf6, 0x12, 0x10, 0xe7, 0xeb, 0x12, 0x01, 0xed, + 0xfd, 0x00, 0xf7, 0x05, 0x07, 0xeb, 0xf0, 0x0a, 0x15, 0x01, 0xf7, 0xfd, + 0x00, 0xf0, 0x00, 0x15, 0x00, 0xf6, 0xfd, 0x0a, 0x07, 0xfd, 0xf6, 0x0c, + 0x0a, 0xe4, 0x00, 0x17, 0x0c, 0xf6, 0xf0, 0x07, 0x05, 0xfd, 0x00, 0x00, + 0xfb, 0xfb, 0xfb, 0xfb, 0x0c, 0x01, 0xf2, 0x07, 0x05, 0xf2, 0x00, 0x00, + 0x00, 0xfd, 0xf2, 0x07, 0x01, 0xf7, 0x00, 0x00, 0x05, 0x01, 0xf6, 0xeb, + 0x01, 0x07, 0x00, 0x00, 0x05, 0xf2, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0xf6, 0x00, 0x10, 0x00, 0xf0, 0x07, 0x0c, 0x00, 0x01, 0xf6, 0xeb, + 0x01, 0x12, 0x00, 0xee, 0x00, 0x0c, 0x00, 0xfb, 0x00, 0xf6, 0x00, 0x19, + 0x01, 0xeb, 0xf0, 0xfd, 0x12, 0x0e, 0xeb, 0xee, 0x0c, 0x00, 0xf7, 0x00, + 0xf7, 0xfd, 0x0c, 0x13, 0xfb, 0xe4, 0xfd, 0x0c, 0x07, 0xfb, 0xfb, 0xfd, + 0x00, 0x07, 0xfb, 0xfd, 0x0a, 0x07, 0xfb, 0xfd, 0xfd, 0xf7, 0x00, 0x0a, + 0x05, 0x00, 0xfb, 0x00, 0x05, 0xf6, 0x05, 0x05, 0xe9, 0x00, 0x0e, 0xf4, + 0x00, 0x12, 0xee, 0xeb, 0x0c, 0x13, 0xf6, 0xee, 0x00, 0x00, 0xf7, 0x05, + 0x09, 0xfd, 0x05, 0x05, 0xf4, 0xf7, 0xf6, 0xfb, 0x12, 0x0e, 0xee, 0xeb, + 0x07, 0x0c, 0x00, 0x05, 0xf4, 0xf4, 0x05, 0x05, 0x00, 0x05, 0x0c, 0xf0, + 0xee, 0x00, 0x0c, 0x0c, 0xfd, 0xfb, 0xf0, 0x00, 0x09, 0x00, 0x00, 0x07, + 0x05, 0xfb, 0xf4, 0xf7, 0x05, 0x0c, 0xfd, 0xf0, 0x00, 0x07, 0x07, 0x05, + 0xf6, 0xe7, 0xf6, 0x12, 0x1b, 0x01, 0xee, 0xf4, 0x00, 0xf6, 0xfd, 0x00, + 0x0e, 0x0c, 0xfb, 0xed, 0xf4, 0x12, 0x01, 0xf4, 0x07, 0x09, 0x00, 0x00, + 0x00, 0xee, 0xf0, 0x00, 0x05, 0x15, 0x0c, 0xf0, 0xf9, 0x01, 0xfb, 0xf9, + 0x07, 0x13, 0x00, 0xf6, 0xf4, 0xf4, 0x05, 0x0e, 0x00, 0xe9, 0x09, 0x1b, + 0xfb, 0xed, 0x00, 0x09, 0xf0, 0x00, 0x19, 0x05, 0xe9, 0xfd, 0x15, 0xf9, + 0xe2, 0x05, 0x15, 0x01, 0x00, 0x01, 0xf4, 0xe9, 0xfb, 0x19, 0x0c, 0xf6, + 0xfb, 0xfd, 0xee, 0xfb, 0x15, 0x0c, 0xee, 0xf0, 0x0e, 0x10, 0xfd, 0xf0, + 0xf9, 0x00, 0x07, 0x0c, 0xfb, 0xfd, 0x09, 0x00, 0xf2, 0xed, 0x00, 0x0e, + 0x01, 0x05, 0x01, 0xee, 0xe7, 0x0e, 0x15, 0xe9, 0xee, 0x15, 0x09, 0xed, + 0x00, 0x05, 0xe2, 0xfb, 0x10, 0x09, 0xfd, 0x07, 0xf9, 0xe2, 0x05, 0x17, + 0xfd, 0xf2, 0x01, 0x09, 0x05, 0xfd, 0xed, 0xf9, 0x10, 0x0e, 0x00, 0xfd, + 0xf2, 0xf4, 0x05, 0x13, 0xf9, 0xee, 0x07, 0x0e, 0x00, 0xf4, 0xf2, 0xf6, + 0x09, 0x0e, 0x00, 0xfb, 0xfd, 0xfd, 0x00, 0x01, 0x00, 0x00, 0x09, 0xfb, + 0xee, 0x01, 0x03, 0xf9, 0x00, 0x10, 0x01, 0xe7, 0xf6, 0x10, 0x07, 0xeb, + 0x00, 0x01, 0xf9, 0x00, 0x0e, 0x00, 0xf2, 0x00, 0xfb, 0x00, 0x0a, 0x07, + 0xf2, 0xf4, 0x03, 0x00, 0x03, 0x09, 0xf4, 0xfd, 0x01, 0x00, 0x01, 0x03, + 0x00, 0xfd, 0x09, 0x01, 0xee, 0xfb, 0x10, 0x01, 0xf2, 0x00, 0x00, 0x00, + 0x10, 0x01, 0xf2, 0xfd, 0x00, 0xf2, 0xfb, 0x0a, 0x01, 0xf4, 0xfb, 0x00, + 0xfb, 0x00, 0x00, 0xf4, 0x00, 0x12, 0x01, 0xeb, 0xf0, 0x01, 0x03, 0x01, + 0x09, 0x01, 0xf9, 0xfd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0xf2, + 0xf4, 0x12, 0x01, 0xe9, 0xfd, 0x19, 0x00, 0xf9, 0x07, 0xf9, 0xed, 0xfd, + 0x03, 0x07, 0x0a, 0x01, 0xf2, 0xe5, 0xf6, 0x0a, 0x0a, 0x00, 0x01, 0xf9, + 0xeb, 0xf9, 0x07, 0x07, 0xf9, 0xed, 0x00, 0x17, 0x00, 0xf2, 0xf9, 0x00, + 0xfd, 0x00, 0x0e, 0x07, 0x00, 0x00, 0xf2, 0xf2, 0x00, 0x0a, 0x03, 0x0a, + 0x01, 0xf2, 0xf0, 0x01, 0x07, 0x00, 0x00, 0x00, 0xf7, 0x03, 0x17, 0xf7, + 0xe7, 0xfb, 0x03, 0x00, 0x00, 0x0a, 0x0c, 0xf2, 0xe7, 0x00, 0x0c, 0xfd, + 0xf7, 0x01, 0x10, 0x00, 0xe7, 0xf7, 0x07, 0x09, 0x03, 0xfd, 0xfd, 0x00, + 0xf7, 0x03, 0x07, 0xeb, 0xf7, 0x0a, 0x0a, 0x03, 0x01, 0xf7, 0xe4, 0xfb, + 0x15, 0x10, 0xf9, 0x00, 0x07, 0xf0, 0xf2, 0x10, 0x03, 0xfb, 0x03, 0xfb, + 0x00, 0x03, 0x00, 0xf0, 0x00, 0x10, 0xf9, 0xfd, 0x0a, 0x00, 0xfd, 0xfb, + 0xf4, 0xfb, 0x09, 0x0a, 0x00, 0xfd, 0x00, 0xee, 0xf4, 0x15, 0x03, 0xf2, + 0x09, 0x03, 0xf0, 0x03, 0x01, 0xeb, 0x01, 0x12, 0x00, 0xeb, 0xf4, 0x09, + 0x10, 0x01, 0x00, 0x00, 0xf2, 0x00, 0x10, 0xfd, 0xf7, 0x00, 0xf7, 0xfb, + 0x0a, 0x09, 0xf9, 0xfd, 0x0a, 0x00, 0xee, 0xfb, 0x09, 0x00, 0xf7, 0x00, + 0x07, 0xfb, 0xf4, 0x03, 0x0a, 0x00, 0xe7, 0x00, 0x12, 0xfb, 0x00, 0x12, + 0xf7, 0xed, 0x03, 0x0c, 0xfd, 0xf9, 0x00, 0x00, 0xfb, 0x00, 0x09, 0x07, + 0x00, 0x03, 0x00, 0xf7, 0xf9, 0x00, 0x09, 0x09, 0xfb, 0xf7, 0xfd, 0xf9, + 0x00, 0x13, 0x0a, 0xee, 0xe9, 0xfd, 0x05, 0x00, 0x00, 0x09, 0xf7, 0xed, + 0x00, 0x03, 0x00, 0x00, 0xfb, 0xfd, 0x09, 0x03, 0xfb, 0x01, 0x03, 0xf9, + 0xf7, 0x00, 0x0a, 0x00, 0x00, 0x01, 0xf2, 0xee, 0x0c, 0x17, 0x00, 0xf6, + 0x03, 0xfb, 0xed, 0x09, 0x0a, 0x01, 0xf7, 0xf9, 0x0a, 0x05, 0xed, 0xf7, + 0x0e, 0x00, 0xf2, 0x00, 0x05, 0xfd, 0xfd, 0x00, 0xf9, 0xf9, 0x0a, 0x09, + 0xf9, 0xfd, 0xfd, 0xf7, 0x00, 0x00, 0x01, 0x05, 0x00, 0xfd, 0x01, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0xf9, 0x00, 0x00, 0x00, + 0x01, 0x10, 0x00, 0xed, 0xf6, 0x0a, 0x03, 0x00, 0xff, 0x00, 0x00, 0xf4, + 0xff, 0x09, 0xff, 0xf6, 0x01, 0x00, 0xfb, 0x00, 0x00, 0x01, 0xfb, 0xf6, + 0xfb, 0x00, 0x05, 0x09, 0xfb, 0x00, 0x00, 0xed, 0x01, 0x1c, 0x03, 0xee, + 0x00, 0x05, 0xf6, 0xf9, 0x10, 0x05, 0xf4, 0x01, 0x05, 0xf9, 0xf9, 0x00, + 0x03, 0xff, 0xfb, 0x07, 0x03, 0xf6, 0xfb, 0x01, 0x00, 0x00, 0x01, 0x05, + 0xf2, 0xf2, 0x0e, 0x05, 0xf2, 0xfb, 0x03, 0x00, 0x01, 0x0e, 0x00, 0xee, + 0xf6, 0x03, 0x00, 0x00, 0x13, 0x00, 0xeb, 0xf6, 0x05, 0x03, 0x03, 0x05, + 0x00, 0xf6, 0xf6, 0x05, 0x0c, 0x00, 0xfb, 0x03, 0x00, 0xeb, 0xfb, 0x0e, + 0x0a, 0xf7, 0xf6, 0xfb, 0x07, 0x0c, 0xff, 0x00, 0xf9, 0xf7, 0x00, 0x07, + 0x00, 0xf7, 0xf7, 0x00, 0x00, 0xff, 0x01, 0x03, 0x00, 0xf6, 0xfb, 0x05, + 0x00, 0x00, 0x0c, 0x00, 0xed, 0xfb, 0x0c, 0x05, 0x00, 0xff, 0xf9, 0x01, + 0x00, 0x00, 0x07, 0x01, 0xf7, 0xf4, 0x07, 0x00, 0xf6, 0x0c, 0xff, 0xeb, + 0x05, 0x12, 0x00, 0xf6, 0x00, 0x00, 0xff, 0x00, 0xff, 0xf9, 0x00, 0x00, + 0xf6, 0x00, 0x09, 0x00, 0x00, 0x00, 0xf0, 0xf4, 0x07, 0x17, 0x03, 0xe7, + 0xf9, 0x0e, 0x00, 0x00, 0x0c, 0xfb, 0xf2, 0x01, 0x03, 0xfb, 0x00, 0x05, + 0x00, 0xf7, 0xff, 0x05, 0x03, 0x00, 0xf9, 0xf7, 0x00, 0xf9, 0xff, 0x09, + 0x0c, 0x00, 0xf0, 0xfb, 0xff, 0x00, 0x12, 0x0e, 0xf2, 0xf7, 0x03, 0xf6, + 0xfb, 0x09, 0x00, 0xf4, 0x03, 0x01, 0xf6, 0x00, 0x09, 0xff, 0xf7, 0x00, + 0x00, 0x00, 0x09, 0x00, 0xf0, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, 0xff, + 0x05, 0xff, 0xeb, 0x00, 0x13, 0x01, 0xf4, 0xfd, 0x05, 0x05, 0x00, 0xf2, + 0xf4, 0x03, 0x0a, 0x00, 0xf9, 0xff, 0xfd, 0x03, 0x0c, 0x00, 0xeb, 0xff, + 0x15, 0x07, 0xf4, 0xf4, 0xf9, 0xf9, 0x01, 0x13, 0x01, 0xf4, 0x00, 0x03, + 0x00, 0xf4, 0xf9, 0x07, 0x12, 0xff, 0xf4, 0xf6, 0xfd, 0x01, 0x0c, 0x09, + 0xfd, 0xf4, 0x00, 0x00, 0x00, 0x03, 0x09, 0xff, 0xee, 0x00, 0x13, 0x00, + 0xf0, 0xfd, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xf0, 0xfd, + 0x0a, 0x0c, 0x00, 0xf2, 0xed, 0xff, 0x09, 0x01, 0xf6, 0x00, 0x00, 0xfd, + 0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0xfb, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x07, 0x01, 0x00, 0x00, 0x03, 0xfb, 0xf4, 0xff, 0x07, 0x07, + 0xfb, 0xf7, 0xfb, 0x03, 0x00, 0xfb, 0x03, 0x00, 0xfd, 0x00, 0x01, 0xfd, + 0xf7, 0x01, 0x07, 0xfb, 0xf2, 0xff, 0x09, 0x01, 0xff, 0x00, 0x00, 0x05, + 0x00, 0x00, 0xff, 0x03, 0x00, 0xff, 0x01, 0xfb, 0x00, 0x0c, 0x03, 0xfb, + 0xfd, 0xf6, 0xf9, 0x09, 0x0a, 0x00, 0xff, 0xfd, 0xf9, 0xf6, 0x01, 0x09, + 0x00, 0xfd, 0x00, 0xf6, 0xfd, 0x0e, 0x03, 0xf6, 0xff, 0x05, 0x03, 0xff, + 0xf7, 0x01, 0x01, 0xf7, 0xfd, 0x0a, 0x09, 0xfb, 0x00, 0xff, 0xff, 0xfd, + 0x05, 0x0a, 0xfb, 0xf7, 0x01, 0x0a, 0xf7, 0xf7, 0x00, 0x00, 0x00, 0x05, + 0xff, 0xf6, 0x00, 0x05, 0xfb, 0xff, 0x0c, 0x01, 0xf6, 0xf9, 0x00, 0x00, + 0x0c, 0x07, 0xf0, 0xf4, 0x03, 0x0a, 0x00, 0xff, 0x00, 0xff, 0xfd, 0xff, + 0x09, 0x0a, 0xfd, 0xf6, 0xfd, 0x00, 0xfd, 0x00, 0x12, 0x00, 0xed, 0xfb, + 0x05, 0x00, 0x00, 0x0a, 0x00, 0xf4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x09, 0x07, 0xfb, 0xf6, 0x00, 0x01, 0xfd, 0x00, 0x0c, + 0xfb, 0xf2, 0xff, 0x03, 0xfd, 0x05, 0x0a, 0x00, 0xf0, 0xf0, 0x07, 0x10, + 0x00, 0xf4, 0x00, 0x00, 0xfb, 0x00, 0x09, 0x09, 0x03, 0xfb, 0xf4, 0xf7, + 0x03, 0x0e, 0x09, 0xfb, 0xee, 0xfb, 0x09, 0x05, 0x00, 0x01, 0xff, 0xf9, + 0xfb, 0x00, 0x07, 0xff, 0xfd, 0x0a, 0xff, 0xee, 0xfb, 0x0e, 0x05, 0xee, + 0xf7, 0x09, 0x09, 0xf9, 0xff, 0x09, 0xfb, 0xf2, 0x00, 0x0a, 0xfd, 0x00, + 0x0a, 0xff, 0xf0, 0xff, 0x0a, 0x03, 0x01, 0xff, 0xf2, 0x00, 0x0e, 0x00, + 0xee, 0x00, 0x0c, 0x00, 0xfd, 0x05, 0x01, 0xf2, 0xfd, 0x0c, 0x03, 0xfb, + 0xff, 0x07, 0x01, 0xf4, 0xf6, 0x00, 0x0a, 0x00, 0x00, 0xfd, 0xf7, 0x00, + 0x05, 0x09, 0x00, 0xf0, 0xf7, 0x05, 0x0e, 0x01, 0xfb, 0xf4, 0xff, 0x09, + 0x07, 0x00, 0x00, 0xf6, 0xf4, 0x05, 0x07, 0xf6, 0x00, 0x0e, 0x00, 0xf0, + 0xfb, 0x05, 0x07, 0x07, 0x00, 0xf2, 0xf4, 0x01, 0x0c, 0x05, 0x00, 0xf4, + 0xf2, 0x09, 0x0a, 0xfd, 0xf7, 0x03, 0x03, 0xf9, 0xee, 0x00, 0x10, 0x05, + 0xf9, 0xfb, 0xfd, 0x01, 0x07, 0x05, 0xff, 0xf9, 0x05, 0x00, 0xf7, 0x00, + 0x09, 0x05, 0xfd, 0xff, 0xfd, 0xfb, 0xff, 0x09, 0x07, 0xfd, 0xfb, 0xfd, + 0x00, 0xff, 0x00, 0x03, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x03, 0x00, 0x00, + 0xff, 0xf7, 0x01, 0x0e, 0xff, 0xf4, 0xff, 0x03, 0x00, 0x00, 0x0e, 0x05, + 0xed, 0xf4, 0x03, 0x00, 0x01, 0x12, 0x05, 0xf7, 0xee, 0xf7, 0x05, 0x0a, + 0x03, 0xff, 0x00, 0xfd, 0xf4, 0xff, 0x0c, 0x03, 0xfb, 0xf6, 0xff, 0x09, + 0x07, 0xff, 0xf7, 0x00, 0xf7, 0xfd, 0x0a, 0x0e, 0xf7, 0xee, 0x00, 0x00, + 0xf9, 0x00, 0x12, 0x07, 0xf2, 0xee, 0x00, 0x0c, 0x00, 0xfd, 0x00, 0x00, + 0x00, 0xfb, 0xfd, 0x01, 0xf9, 0xff, 0x03, 0x00, 0x00, 0x0a, 0x05, 0xf7, + 0xee, 0xfd, 0x0a, 0x09, 0x00, 0xf9, 0xf9, 0x00, 0x03, 0x01, 0x01, 0x00, + 0x00, 0x07, 0xff, 0xf9, 0x00, 0x01, 0xfd, 0xfb, 0x01, 0x01, 0x01, 0x01, + 0xff, 0xf0, 0xf7, 0x03, 0x0a, 0x05, 0xfd, 0xfd, 0x00, 0xf4, 0xf2, 0x03, + 0x0c, 0xff, 0xf4, 0x00, 0x07, 0xfd, 0xfd, 0x03, 0x03, 0xff, 0xfb, 0x0a, + 0x07, 0xf9, 0xf7, 0x00, 0x00, 0x00, 0x05, 0x03, 0x00, 0xfd, 0xf9, 0xf7, + 0xff, 0x0c, 0x0c, 0x00, 0xf9, 0xfd, 0xfb, 0x00, 0x07, 0xff, 0xf6, 0x00, + 0x09, 0x00, 0xf6, 0xff, 0x0a, 0x03, 0xf4, 0xf6, 0x05, 0x03, 0xf9, 0xf9, + 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xfd, 0x01, 0x00, 0xfb, 0x00, + 0x0a, 0x00, 0xf6, 0x00, 0x0c, 0xff, 0xf0, 0x00, 0x01, 0x05, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xff, 0x01, 0x07, 0x00, 0xf7, 0x00, + 0x00, 0x00, 0xfb, 0x01, 0x09, 0x03, 0xf6, 0xf0, 0x03, 0x0c, 0xf7, 0xf7, + 0x0c, 0xff, 0xee, 0x00, 0x05, 0xf7, 0x00, 0x0e, 0x00, 0xf2, 0xf9, 0x0e, + 0x03, 0xf4, 0xf9, 0x00, 0x00, 0x05, 0x03, 0xf9, 0xf7, 0x00, 0x05, 0x09, + 0xff, 0xf9, 0x01, 0x03, 0x00, 0xf7, 0xf9, 0x01, 0x05, 0x03, 0xfb, 0xf7, + 0x00, 0x05, 0x01, 0x00, 0xf9, 0xff, 0x05, 0x07, 0xf9, 0xf6, 0x00, 0x01, + 0xf9, 0x00, 0x09, 0xfd, 0xfb, 0x05, 0xfb, 0xf4, 0x01, 0x0c, 0x00, 0xf2, + 0x01, 0x09, 0xfd, 0xf9, 0xff, 0xff, 0x00, 0x01, 0xfd, 0x00, 0x01, 0xf9, + 0xfb, 0x00, 0x05, 0x07, 0x01, 0xff, 0xf2, 0xf9, 0x07, 0x10, 0x01, 0xf4, + 0xf7, 0x01, 0x09, 0xfb, 0x00, 0x0c, 0xff, 0xf2, 0xfb, 0x0a, 0x07, 0xf9, + 0xfd, 0xff, 0xf4, 0xff, 0x0c, 0x0a, 0xf6, 0xee, 0x00, 0x07, 0x03, 0x00, + 0x00, 0x00, 0xfd, 0xf7, 0xff, 0x09, 0x01, 0xfd, 0x03, 0x00, 0xf9, 0xfd, + 0x03, 0x01, 0x01, 0x01, 0xfd, 0xf9, 0xff, 0x01, 0x00, 0xfb, 0x00, 0x07, + 0x00, 0xf9, 0x00, 0x01, 0xff, 0xfb, 0x09, 0x09, 0xf7, 0xf7, 0x01, 0x00, + 0x00, 0xfd, 0x01, 0x01, 0x00, 0x01, 0xfb, 0xf6, 0xfb, 0x09, 0x0c, 0x00, + 0xfb, 0xfb, 0x00, 0x00, 0xfb, 0x00, 0x01, 0x09, 0x00, 0xfb, 0xfd, 0xfd, + 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0xf7, 0x00, 0x09, 0x00, + 0xfb, 0xfd, 0x03, 0x01, 0xfd, 0xfb, 0x01, 0x05, 0x00, 0xfb, 0x00, 0x07, + 0xfb, 0xf4, 0xff, 0x01, 0x01, 0x07, 0x07, 0xf9, 0xf0, 0xfb, 0x07, 0x07, + 0x00, 0x00, 0x03, 0x00, 0xf0, 0xfd, 0x09, 0x01, 0xfb, 0xff, 0x00, 0xfb, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xf7, 0xfb, 0xff, + 0x00, 0xff, 0x07, 0x07, 0xff, 0xf9, 0xf6, 0xfd, 0x03, 0x07, 0x07, 0xff, + 0xf4, 0xfd, 0x00, 0x00, 0x00, 0x01, 0x01, 0xfb, 0xf9, 0x00, 0x07, 0x03, + 0xff, 0x00, 0x00, 0xfb, 0xfb, 0x03, 0x01, 0xf9, 0xfb, 0x03, 0x05, 0xff, + 0x00, 0x00, 0xf9, 0xfd, 0x00, 0x00, 0x00, 0x07, 0xfd, 0xf6, 0x00, 0x01, + 0x00, 0xfb, 0x00, 0x03, 0x00, 0xfb, 0xf6, 0x00, 0x0a, 0x00, 0xfb, 0x01, + 0x01, 0xf6, 0xfb, 0x07, 0xfd, 0x00, 0x05, 0x00, 0xfb, 0xfd, 0xfd, 0x05, + 0x05, 0x01, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x03, + 0x00, 0x00, 0x01, 0xff, 0xf6, 0xff, 0x0a, 0x0a, 0x00, 0xf7, 0xf7, 0xfb, + 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xf9, 0xfb, 0x00, 0x0a, 0x05, + 0xfd, 0xf6, 0xfd, 0x05, 0x00, 0xf7, 0xf9, 0x00, 0x05, 0x05, 0x00, 0xff, + 0x00, 0xf9, 0xfd, 0x05, 0x01, 0xfd, 0x01, 0x00, 0xf7, 0xf9, 0x00, 0x01, + 0x00, 0x00, 0x03, 0xfd, 0xf9, 0xfd, 0x00, 0x03, 0x05, 0x00, 0xf9, 0xf9, + 0x00, 0xfd, 0xff, 0x00, 0x05, 0x05, 0x00, 0xfd, 0xf7, 0x03, 0x07, 0xfd, + 0xf6, 0x00, 0x05, 0xff, 0x00, 0x00, 0xf9, 0xfd, 0x00, 0xff, 0x00, 0x03, + 0x00, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x05, 0x05, 0xfb, 0xf4, 0x00, 0x05, + 0xfd, 0xfd, 0x01, 0x03, 0xfd, 0xfd, 0x03, 0x05, 0x00, 0xfb, 0xfd, 0x00, + 0xfb, 0x03, 0x0e, 0x00, 0xf4, 0xf4, 0x00, 0x09, 0x01, 0x00, 0x00, 0xfd, + 0xfd, 0x00, 0x00, 0xfb, 0x00, 0x07, 0x00, 0xf6, 0xfb, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x03, 0xfd, 0xfd, 0x05, 0xfd, 0xf9, 0x03, 0x00, 0xf6, 0xfd, + 0x07, 0x05, 0xf6, 0xf7, 0x05, 0x09, 0x00, 0xf9, 0xf7, 0x01, 0x09, 0x00, + 0xf9, 0xf9, 0x03, 0x09, 0x00, 0xfd, 0xff, 0xfd, 0x00, 0x03, 0xfd, 0xff, + 0x07, 0x00, 0xf7, 0xfb, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf9, 0xfd, 0x07, + 0x0c, 0x00, 0xf6, 0xfd, 0x00, 0xff, 0x00, 0x09, 0x00, 0xf4, 0xf6, 0x05, + 0x0c, 0x01, 0xf6, 0xf7, 0x01, 0x09, 0xfd, 0xf9, 0x03, 0x01, 0xfb, 0xfd, + 0xfd, 0x00, 0x03, 0x05, 0xfb, 0xf4, 0xf9, 0x07, 0x0a, 0x00, 0xfb, 0x00, + 0xf6, 0xfd, 0x0c, 0x09, 0xf6, 0xf4, 0x07, 0x05, 0xf7, 0x03, 0x07, 0xfd, + 0xfd, 0x00, 0x00, 0xfd, 0x01, 0x03, 0x00, 0xff, 0x00, 0xff, 0x00, 0x01, + 0x00, 0xff, 0x00, 0x00, 0xff, 0xfb, 0x00, 0x09, 0x00, 0xf9, 0x00, 0x00, + 0xfd, 0xfb, 0x00, 0x05, 0x00, 0x00, 0xff, 0xf6, 0xff, 0x07, 0x07, 0xff, + 0xfd, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, + 0x05, 0xff, 0xf6, 0xff, 0x07, 0x05, 0x03, 0xff, 0xf7, 0xff, 0x00, 0xff, + 0x00, 0x09, 0x05, 0xf6, 0xf7, 0x00, 0x03, 0x00, 0x00, 0xff, 0xf7, 0xff, + 0x03, 0x01, 0x00, 0xfb, 0xfb, 0x00, 0x00, 0x00, 0x05, 0x03, 0xfd, 0xf7, + 0xff, 0x00, 0x05, 0x03, 0x00, 0xff, 0xf7, 0xff, 0x03, 0x03, 0x00, 0xff, + 0xfd, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0xff, 0xfd, 0xff, 0x01, 0x03, 0x00, 0xfd, 0xf9, 0x01, 0x03, 0xfb, 0xf9, + 0x00, 0x03, 0x00, 0x00, 0x00, 0xff, 0xfb, 0xfd, 0x03, 0x07, 0x00, 0xfb, + 0xfd, 0xf9, 0xfd, 0x07, 0x09, 0x00, 0xf7, 0xff, 0x03, 0x00, 0xfd, 0x01, + 0x05, 0xff, 0xfb, 0xff, 0x00, 0x03, 0x05, 0x00, 0xf9, 0xf9, 0x01, 0x0a, + 0xff, 0xf2, 0xff, 0x0a, 0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0xf7, 0xfd, + 0x05, 0x05, 0x00, 0xfb, 0xf9, 0xfd, 0x03, 0x05, 0x00, 0xfd, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x01, 0x01, 0xfd, 0xf6, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x01, 0x00, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0xfb, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, 0x00, 0x00, 0xff, 0xfb, + 0x00, 0x01, 0x05, 0x05, 0xf7, 0xf6, 0x00, 0x01, 0xfd, 0x01, 0x07, 0x00, + 0xf6, 0xf9, 0x01, 0x05, 0x01, 0xff, 0xff, 0xfd, 0xfd, 0x00, 0x07, 0x01, + 0xf7, 0xf7, 0x00, 0x07, 0x01, 0xfd, 0x00, 0x01, 0xf9, 0xfb, 0x00, 0x09, + 0x09, 0xff, 0xf6, 0xf6, 0x01, 0x0a, 0x01, 0xff, 0xff, 0xfd, 0x00, 0x00, + 0xfd, 0x00, 0x07, 0x00, 0xfb, 0xfd, 0xff, 0x03, 0x07, 0x00, 0xfd, 0xfd, + 0x01, 0x07, 0x00, 0xfd, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x05, 0x00, 0xf9, + 0xf9, 0xff, 0x01, 0x01, 0x01, 0x00, 0xfd, 0x00, 0x00, 0xfd, 0xfb, 0x03, + 0x03, 0xff, 0xfb, 0x00, 0x07, 0x00, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x03, + 0x00, 0xf7, 0xfb, 0x03, 0x03, 0xfb, 0xf9, 0x00, 0x0a, 0x00, 0xf6, 0xf6, + 0x01, 0x09, 0x00, 0xff, 0x00, 0xff, 0xf7, 0xfd, 0x03, 0x01, 0xff, 0x03, + 0x05, 0xfb, 0xf4, 0x00, 0x0a, 0x05, 0xfd, 0xf9, 0xff, 0x01, 0x00, 0x00, + 0xff, 0xfb, 0x00, 0x01, 0xff, 0x00, 0x03, 0x00, 0xfb, 0xf9, 0xfd, 0x07, + 0x09, 0xff, 0xf9, 0xff, 0xff, 0xfd, 0xff, 0x05, 0x05, 0xfd, 0xfb, 0x01, + 0x03, 0xfd, 0x00, 0x03, 0x01, 0xf9, 0xfd, 0x07, 0x00, 0xf7, 0x01, 0x09, + 0xff, 0xf7, 0xff, 0x05, 0x00, 0xfd, 0x00, 0xff, 0x00, 0x03, 0x01, 0xf7, + 0xfd, 0x03, 0xff, 0xfd, 0x00, 0x00, 0x03, 0x00, 0xfd, 0xfd, 0xff, 0x00, + 0x03, 0x01, 0xfd, 0xfd, 0x00, 0xff, 0xff, 0x00, 0x03, 0x03, 0x00, 0xfd, + 0xff, 0xff, 0xff, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xfd, 0x00, 0x01, 0x00, 0x01, 0x05, 0xfd, 0xf7, 0xfd, 0x00, 0x05, 0x07, + 0xfd, 0xf7, 0xfd, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0xfd, 0xf9, + 0x03, 0x09, 0x00, 0xf7, 0xfd, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, + 0x01, 0xff, 0xf9, 0xfd, 0x01, 0x01, 0xfd, 0xfd, 0x01, 0x03, 0x00, 0xf9, + 0xff, 0x01, 0x00, 0x00, 0x03, 0x03, 0x00, 0xf9, 0xfd, 0x03, 0x03, 0xff, + 0x00, 0x00, 0xff, 0xfd, 0x00, 0x01, 0x01, 0xff, 0x00, 0xff, 0xf9, 0x00, + 0x05, 0x00, 0xfb, 0xff, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xff, 0x01, 0x03, 0x00, 0xfb, 0xff, 0x03, 0x01, 0xfb, 0xfd, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x01, 0xff, 0xfd, 0x01, + 0x00, 0xff, 0xfd, 0xfb, 0x03, 0x07, 0x00, 0xf9, 0xff, 0x00, 0x00, 0x01, + 0x00, 0xfd, 0xff, 0x01, 0x00, 0xfb, 0xff, 0x01, 0x01, 0x01, 0xfd, 0xfb, + 0x00, 0x01, 0x01, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, + 0xfd, 0xfd, 0x01, 0x01, 0x00, 0x00, 0xff, 0xfd, 0x01, 0x00, 0xfd, 0x00, + 0x01, 0xff, 0xfb, 0x01, 0x03, 0xff, 0x01, 0x01, 0xfb, 0xfd, 0x01, 0x01, + 0xff, 0x00, 0x01, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xff, 0x00, 0x01, 0xff, + 0xff, 0x03, 0x00, 0xfd, 0xff, 0x00, 0x01, 0xff, 0xfd, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xfd, 0xff, 0x03, 0x03, 0xfd, + 0xfb, 0x01, 0x05, 0xfb, 0xf9, 0x00, 0x05, 0x00, 0x00, 0x00, 0xf9, 0xff, + 0x03, 0x05, 0x00, 0xfb, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x01, 0x00, + 0x00, 0xff, 0x01, 0x00, 0xff, 0xfd, 0xff, 0x01, 0x01, 0x00, 0xff, 0xfd, + 0xfb, 0x00, 0x05, 0x05, 0x00, 0xff, 0xfb, 0xf9, 0x00, 0x07, 0x01, 0xfb, + 0xfd, 0x05, 0x00, 0xfb, 0xfb, 0x00, 0x01, 0x01, 0x00, 0x00, 0xff, 0x00, + 0x00, 0xff, 0xfb, 0xff, 0x05, 0x03, 0xfd, 0xf9, 0xfd, 0x00, 0x00, 0x03, + 0x01, 0xfb, 0xfd, 0x00, 0x00, 0xfd, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0xff, 0x00, 0x05, 0x00, 0xff, 0x00, 0xff, 0xfd, 0x01, + 0x03, 0x00, 0xff, 0x00, 0xff, 0xfd, 0x00, 0x03, 0x05, 0x00, 0xfb, 0xfd, + 0x01, 0x03, 0x00, 0xfd, 0xf9, 0x00, 0x03, 0x03, 0x00, 0xfb, 0xfd, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x01, 0xff, 0xfd, + 0xfd, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x00, + 0xfd, 0xff, 0x00, 0x01, 0xff, 0xfd, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, + 0xfd, 0x00, 0x01, 0x03, 0x00, 0xfd, 0xfb, 0xff, 0x00, 0x01, 0x01, 0x00, + 0xff, 0xfd, 0xff, 0x00, 0x00, 0x01, 0x03, 0x00, 0xfd, 0xfb, 0xff, 0x01, + 0x03, 0x00, 0xfb, 0x00, 0x03, 0x01, 0x00, 0xff, 0xfb, 0xfd, 0x05, 0x05, + 0xff, 0xff, 0x00, 0xff, 0xfb, 0x00, 0x03, 0x01, 0x00, 0x00, 0xfb, 0xfd, + 0x01, 0x03, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0x03, 0x00, 0xfd, 0x00, 0x00, 0xfd, 0x00, 0x05, 0x00, 0xfd, 0xfd, + 0x00, 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfd, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xff, 0x03, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x03, 0xff, 0xfb, 0x00, 0x05, 0x00, 0xfd, + 0x00, 0x00, 0xff, 0x01, 0x03, 0xff, 0xfd, 0x00, 0x01, 0xff, 0xff, 0x01, + 0x01, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, + 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfd, 0x01, + 0x01, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0xff, + 0xff, 0x01, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x03, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xfd, 0x00, 0x03, 0x00, 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0xfd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfd, 0x01, 0x03, 0x00, + 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xfd, 0x00, 0x03, 0x00, + 0xff, 0x00, 0x00, 0xfd, 0xfd, 0x03, 0x01, 0x00, 0x00, 0x00, 0xfd, 0xfd, + 0x00, 0x03, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x03, 0x00, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x03, 0x00, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0x00, 0x01, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0xff, + 0xff, 0x01, 0x01, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x00, 0x00, + 0xff, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, 0xff, 0x00, 0x00, + 0x00, 0x01, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, + 0x01, 0xff, 0xfd, 0xff, 0x00, 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x01, 0x00, 0xfd, 0x00, 0x01, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xfd, 0x00, 0x03, 0x01, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x01, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, + 0x00, 0x00, 0x01, 0x00, 0xfd, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x01, 0x00, 0xff, 0x00, 0x01, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, + 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x01, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x01, 0x00, 0xff, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xfe, 0xfc, 0xf9, 0xf8, 0xf8, + 0xf7, 0xf5, 0xf2, 0xf1, 0xef, 0xed, 0xec, 0xea, 0xe8, 0xe4, 0xe1, 0xe0, + 0xdf, 0xdf, 0xdf, 0xdf, 0xe0, 0xe1, 0xe1, 0xe1, 0xe1, 0xe3, 0xe5, 0xe5, + 0xe3, 0xe2, 0xe3, 0xe8, 0xea, 0xec, 0xee, 0xec, 0xed, 0xf4, 0xf7, 0xf7, + 0xf7, 0xf8, 0xfa, 0xf8, 0xfa, 0xff, 0x02, 0x02, 0x05, 0x04, 0x02, 0x0c, + 0x0e, 0x02, 0xfb, 0x04, 0x10, 0x1f, 0x22, 0x20, 0x1e, 0x14, 0x14, 0x14, + 0x0e, 0x0e, 0x14, 0x0f, 0x0d, 0x12, 0x11, 0x11, 0x14, 0x12, 0x10, 0x0a, + 0x00, 0xfa, 0xf4, 0xee, 0xef, 0xed, 0xe2, 0xdb, 0xd7, 0xd5, 0xd7, 0xd4, + 0xcb, 0xbf, 0xb3, 0xa8, 0xa2, 0xa0, 0x9a, 0x99, 0x99, 0x9d, 0x9f, 0xa3, + 0xaa, 0xae, 0xb1, 0xb1, 0xb6, 0xb8, 0xb8, 0xbd, 0xbe, 0xb9, 0xbf, 0xc8, + 0xcc, 0xcf, 0xd3, 0xd7, 0xd4, 0xcf, 0xde, 0xed, 0xe3, 0xe9, 0xf8, 0xf3, + 0xeb, 0xf4, 0x04, 0x0d, 0x15, 0x16, 0x0c, 0x03, 0x0c, 0x24, 0x34, 0x44, + 0x4f, 0x45, 0x37, 0x37, 0x3c, 0x45, 0x54, 0x5c, 0x5b, 0x52, 0x4a, 0x4c, + 0x57, 0x5d, 0x5d, 0x5d, 0x61, 0x61, 0x5b, 0x5e, 0x6b, 0x74, 0x72, 0x70, + 0x6d, 0x67, 0x66, 0x6e, 0x78, 0x76, 0x70, 0x68, 0x5f, 0x5b, 0x55, 0x55, + 0x5f, 0x65, 0x61, 0x59, 0x56, 0x56, 0x51, 0x4a, 0x4c, 0x58, 0x5b, 0x55, + 0x4c, 0x3c, 0x40, 0x4e, 0x47, 0x3a, 0x3b, 0x3d, 0x36, 0x2f, 0x2e, 0x32, + 0x34, 0x31, 0x2d, 0x23, 0x1c, 0x29, 0x37, 0x2f, 0x21, 0x25, 0x2e, 0x2d, + 0x20, 0x16, 0x22, 0x37, 0x41, 0x37, 0x22, 0x1e, 0x2c, 0x38, 0x3a, 0x3a, + 0x3b, 0x38, 0x34, 0x30, 0x34, 0x3f, 0x40, 0x3b, 0x3a, 0x3b, 0x40, 0x4b, + 0x51, 0x4a, 0x44, 0x48, 0x4e, 0x4e, 0x4b, 0x4b, 0x51, 0x56, 0x56, 0x53, + 0x4c, 0x46, 0x46, 0x4c, 0x54, 0x54, 0x4b, 0x42, 0x44, 0x4a, 0x4c, 0x48, + 0x44, 0x46, 0x49, 0x4b, 0x4a, 0x4a, 0x4b, 0x45, 0x3c, 0x35, 0x38, 0x40, + 0x44, 0x3f, 0x36, 0x31, 0x2f, 0x2e, 0x2f, 0x31, 0x38, 0x3d, 0x37, 0x28, + 0x1a, 0x1d, 0x2a, 0x34, 0x33, 0x2c, 0x2a, 0x2a, 0x2a, 0x28, 0x26, 0x2c, + 0x38, 0x38, 0x2a, 0x24, 0x2b, 0x31, 0x32, 0x33, 0x31, 0x2a, 0x26, 0x2a, + 0x2d, 0x30, 0x3c, 0x44, 0x3b, 0x2a, 0x28, 0x30, 0x35, 0x3d, 0x43, 0x3b, + 0x32, 0x33, 0x33, 0x2f, 0x2b, 0x31, 0x38, 0x37, 0x30, 0x29, 0x24, 0x20, + 0x1f, 0x1c, 0x11, 0x06, 0x00, 0xfb, 0xfa, 0xfb, 0xfa, 0xf8, 0xee, 0xe3, + 0xdf, 0xde, 0xde, 0xdb, 0xd7, 0xd3, 0xc9, 0xc3, 0xc5, 0xc7, 0xc6, 0xcc, + 0xd4, 0xd3, 0xd0, 0xd2, 0xd9, 0xe4, 0xed, 0xef, 0xea, 0xe4, 0xe0, 0xe2, + 0xeb, 0xf4, 0xf1, 0xef, 0xf1, 0xeb, 0xe7, 0xea, 0xf1, 0xf9, 0xfa, 0xf5, + 0xef, 0xea, 0xee, 0xf7, 0xfb, 0xff, 0x0b, 0x0b, 0xfd, 0xf9, 0x02, 0x11, + 0x17, 0x0f, 0x09, 0x0c, 0x15, 0x1b, 0x18, 0x14, 0x1a, 0x24, 0x20, 0x0f, + 0x07, 0x13, 0x25, 0x25, 0x16, 0x13, 0x1e, 0x21, 0x1c, 0x19, 0x1d, 0x2a, + 0x33, 0x27, 0x15, 0x17, 0x25, 0x29, 0x1c, 0x0d, 0x0e, 0x19, 0x20, 0x1a, + 0x0e, 0x06, 0x08, 0x0d, 0x07, 0xff, 0x00, 0x05, 0x09, 0x05, 0xfd, 0xfa, + 0xfa, 0xf5, 0xf2, 0xf6, 0xf8, 0xf4, 0xec, 0xdf, 0xd7, 0xd8, 0xde, 0xe3, + 0xe2, 0xda, 0xd4, 0xd4, 0xd7, 0xdb, 0xdb, 0xd2, 0xcd, 0xd1, 0xd7, 0xd9, + 0xdb, 0xde, 0xe4, 0xe7, 0xdf, 0xda, 0xe3, 0xf1, 0xfc, 0xff, 0xfe, 0xfd, + 0xf9, 0xf6, 0xf7, 0xfc, 0x0b, 0x20, 0x1a, 0x08, 0x0e, 0x18, 0x1c, 0x1e, + 0x28, 0x32, 0x37, 0x37, 0x39, 0x3a, 0x3a, 0x48, 0x4d, 0x3a, 0x2d, 0x35, + 0x3e, 0x49, 0x50, 0x48, 0x39, 0x33, 0x33, 0x38, 0x3d, 0x45, 0x4b, 0x48, + 0x40, 0x3d, 0x41, 0x41, 0x46, 0x4e, 0x50, 0x4e, 0x42, 0x33, 0x2e, 0x31, + 0x31, 0x36, 0x3d, 0x37, 0x2b, 0x23, 0x26, 0x2e, 0x33, 0x2f, 0x23, 0x18, + 0x1a, 0x25, 0x29, 0x26, 0x28, 0x22, 0x1b, 0x1d, 0x1e, 0x20, 0x24, 0x2c, + 0x31, 0x27, 0x1d, 0x1e, 0x1c, 0x1a, 0x28, 0x32, 0x29, 0x1f, 0x22, 0x28, + 0x2c, 0x35, 0x3a, 0x33, 0x2b, 0x28, 0x2b, 0x38, 0x48, 0x45, 0x38, 0x30, + 0x2e, 0x32, 0x3d, 0x47, 0x49, 0x42, 0x38, 0x2f, 0x26, 0x24, 0x2b, 0x33, + 0x37, 0x30, 0x1e, 0x10, 0x0b, 0x0d, 0x11, 0x15, 0x14, 0x05, 0xf0, 0xe2, + 0xe4, 0xed, 0xf0, 0xea, 0xe0, 0xdc, 0xd6, 0xc9, 0xc4, 0xce, 0xd8, 0xd7, + 0xd3, 0xcc, 0xc4, 0xca, 0xd9, 0xe5, 0xe8, 0xea, 0xf0, 0xe8, 0xdd, 0xde, + 0xe7, 0xf2, 0xfb, 0xf6, 0xe6, 0xe3, 0xee, 0xf2, 0xed, 0xed, 0xef, 0xf4, + 0xf4, 0xf0, 0xee, 0xf2, 0xfb, 0x01, 0x01, 0xfc, 0xf8, 0xfb, 0x06, 0x0d, + 0x0b, 0x05, 0x06, 0x0e, 0x13, 0x14, 0x14, 0x12, 0x11, 0x0d, 0x0a, 0x0f, + 0x19, 0x1b, 0x16, 0x0e, 0x08, 0x0c, 0x19, 0x23, 0x22, 0x1b, 0x1a, 0x1f, + 0x21, 0x1a, 0x16, 0x1a, 0x25, 0x2c, 0x1f, 0x0e, 0x0d, 0x10, 0x0c, 0x0e, + 0x14, 0x10, 0x04, 0xfc, 0xfe, 0x07, 0x0d, 0x0b, 0x03, 0xfa, 0xfb, 0x02, + 0x03, 0xff, 0xfe, 0xfc, 0xf5, 0xeb, 0xe6, 0xe9, 0xef, 0xf2, 0xec, 0xe2, + 0xdd, 0xdc, 0xdb, 0xd8, 0xd8, 0xe0, 0xe9, 0xe5, 0xd5, 0xc9, 0xcd, 0xdc, + 0xe8, 0xe9, 0xe3, 0xda, 0xd8, 0xe1, 0xed, 0xf8, 0xfd, 0xf5, 0xec, 0xea, + 0xf0, 0xfa, 0x01, 0x06, 0x06, 0x02, 0xff, 0xff, 0x01, 0x0a, 0x1a, 0x23, + 0x26, 0x25, 0x1f, 0x16, 0x18, 0x28, 0x37, 0x40, 0x41, 0x35, 0x25, 0x21, + 0x2e, 0x3d, 0x41, 0x3a, 0x2f, 0x28, 0x29, 0x2d, 0x2f, 0x2f, 0x30, 0x35, + 0x38, 0x37, 0x33, 0x30, 0x32, 0x36, 0x37, 0x31, 0x28, 0x24, 0x20, 0x21, + 0x25, 0x26, 0x25, 0x21, 0x18, 0x0f, 0x11, 0x1a, 0x1a, 0x11, 0x0b, 0x0b, + 0x10, 0x16, 0x13, 0x08, 0x03, 0x06, 0x0b, 0x11, 0x18, 0x17, 0x10, 0x08, + 0x04, 0x06, 0x07, 0x0a, 0x10, 0x12, 0x13, 0x13, 0x09, 0xff, 0x02, 0x0d, + 0x1e, 0x27, 0x1c, 0x0d, 0x0b, 0x14, 0x1e, 0x20, 0x1e, 0x24, 0x2a, 0x26, + 0x20, 0x20, 0x2a, 0x37, 0x33, 0x21, 0x17, 0x1b, 0x25, 0x28, 0x20, 0x1a, + 0x23, 0x2c, 0x23, 0x12, 0x09, 0x12, 0x20, 0x1e, 0x07, 0xf3, 0xf4, 0xfd, + 0xfc, 0xee, 0xe5, 0xec, 0xf4, 0xec, 0xd8, 0xcb, 0xce, 0xda, 0xda, 0xcf, + 0xc8, 0xcf, 0xd6, 0xd5, 0xd2, 0xd5, 0xe0, 0xe6, 0xe8, 0xe6, 0xe4, 0xef, + 0xfa, 0xf6, 0xe6, 0xe0, 0xec, 0xfa, 0xfc, 0xf5, 0xed, 0xe8, 0xe9, 0xf0, + 0xf6, 0xf6, 0xf4, 0xf1, 0xf0, 0xf1, 0xf6, 0xfb, 0xf7, 0xf6, 0x03, 0x0b, + 0x05, 0xfd, 0xfc, 0x03, 0x0f, 0x17, 0x13, 0x0a, 0x03, 0x01, 0x07, 0x10, + 0x13, 0x13, 0x0e, 0x05, 0x00, 0x0b, 0x1d, 0x22, 0x19, 0x13, 0x18, 0x22, + 0x28, 0x2a, 0x27, 0x22, 0x23, 0x26, 0x22, 0x1b, 0x1b, 0x1e, 0x1a, 0x15, + 0x18, 0x14, 0x0a, 0x05, 0x08, 0x11, 0x17, 0x16, 0x0e, 0x07, 0x07, 0x11, + 0x18, 0x11, 0x07, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xf1, 0xe9, + 0xea, 0xef, 0xf1, 0xeb, 0xe4, 0xe2, 0xe3, 0xe5, 0xdf, 0xd5, 0xd4, 0xe0, + 0xeb, 0xed, 0xe7, 0xe2, 0xdc, 0xe2, 0xf1, 0xf9, 0xf5, 0xed, 0xed, 0xef, + 0xf0, 0xf5, 0xfa, 0xfb, 0xfb, 0xfe, 0x02, 0x06, 0x08, 0x0b, 0x0d, 0x0f, + 0x11, 0x18, 0x1e, 0x1b, 0x19, 0x1d, 0x26, 0x2e, 0x2d, 0x2a, 0x28, 0x26, + 0x2d, 0x34, 0x2a, 0x1d, 0x1a, 0x1f, 0x25, 0x28, 0x2d, 0x2d, 0x25, 0x21, + 0x2e, 0x39, 0x3a, 0x36, 0x29, 0x1e, 0x22, 0x2a, 0x28, 0x28, 0x2d, 0x30, + 0x2a, 0x1b, 0x12, 0x16, 0x1d, 0x21, 0x20, 0x19, 0x12, 0x0e, 0x08, 0x03, + 0x06, 0x14, 0x21, 0x1a, 0x03, 0xf6, 0x02, 0x13, 0x15, 0x0a, 0x03, 0x09, + 0x11, 0x0a, 0xff, 0xfe, 0x09, 0x16, 0x12, 0x04, 0xff, 0x08, 0x11, 0x11, + 0x0f, 0x0d, 0x11, 0x16, 0x14, 0x12, 0x16, 0x20, 0x2c, 0x2c, 0x22, 0x21, + 0x27, 0x2b, 0x2b, 0x28, 0x28, 0x2c, 0x29, 0x23, 0x21, 0x20, 0x22, 0x2a, + 0x2c, 0x2a, 0x28, 0x23, 0x21, 0x20, 0x1a, 0x11, 0x09, 0x08, 0x0e, 0x0d, + 0x01, 0xf5, 0xeb, 0xe3, 0xe6, 0xec, 0xea, 0xe0, 0xd6, 0xd3, 0xd2, 0xcc, + 0xca, 0xd0, 0xd3, 0xcf, 0xca, 0xc8, 0xcc, 0xd4, 0xd7, 0xd5, 0xda, 0xe4, + 0xea, 0xe6, 0xdf, 0xde, 0xe7, 0xf0, 0xf0, 0xe6, 0xdd, 0xdf, 0xe7, 0xef, + 0xf2, 0xef, 0xec, 0xea, 0xea, 0xec, 0xf6, 0x01, 0x02, 0xf9, 0xf4, 0xff, + 0x0f, 0x14, 0x0b, 0x06, 0x0d, 0x17, 0x17, 0x10, 0x0e, 0x12, 0x1b, 0x1d, + 0x11, 0x06, 0x0b, 0x15, 0x17, 0x17, 0x1d, 0x23, 0x20, 0x18, 0x15, 0x1b, + 0x28, 0x34, 0x2f, 0x1e, 0x14, 0x1a, 0x24, 0x20, 0x18, 0x15, 0x12, 0x0f, + 0x0d, 0x09, 0x04, 0x05, 0x08, 0x09, 0x07, 0x03, 0xfe, 0xf9, 0xfa, 0x00, + 0x01, 0xff, 0xfc, 0xf6, 0xf0, 0xee, 0xef, 0xf0, 0xef, 0xea, 0xe4, 0xe2, + 0xe3, 0xe5, 0xe3, 0xdb, 0xd4, 0xd3, 0xd8, 0xdb, 0xd7, 0xd0, 0xcd, 0xd2, + 0xd8, 0xd9, 0xd6, 0xd4, 0xd7, 0xdc, 0xde, 0xe0, 0xe1, 0xde, 0xdd, 0xe0, + 0xe4, 0xe6, 0xe4, 0xe3, 0xe7, 0xee, 0xf5, 0xf8, 0xf5, 0xf2, 0xf4, 0xf6, + 0xfa, 0x03, 0x0b, 0x0d, 0x0b, 0x09, 0x0a, 0x11, 0x17, 0x1a, 0x1b, 0x1a, + 0x1a, 0x18, 0x10, 0x08, 0x09, 0x14, 0x22, 0x27, 0x1f, 0x17, 0x15, 0x1a, + 0x21, 0x22, 0x23, 0x28, 0x26, 0x1e, 0x18, 0x18, 0x1f, 0x24, 0x1f, 0x18, + 0x15, 0x18, 0x1a, 0x14, 0x0e, 0x0f, 0x13, 0x12, 0x0c, 0x07, 0x06, 0x07, + 0x09, 0x05, 0xff, 0x00, 0x05, 0x04, 0xfd, 0xfc, 0x00, 0x04, 0x03, 0xfc, + 0xf7, 0xf9, 0xff, 0x02, 0x01, 0x00, 0x01, 0x00, 0xfd, 0xfc, 0xfd, 0x00, + 0x00, 0xff, 0x04, 0x09, 0x09, 0x07, 0x05, 0x06, 0x0d, 0x16, 0x1c, 0x1c, + 0x16, 0x10, 0x0c, 0x0c, 0x10, 0x14, 0x16, 0x15, 0x14, 0x14, 0x15, 0x14, + 0x13, 0x13, 0x14, 0x18, 0x1a, 0x16, 0x11, 0x0f, 0x0c, 0x09, 0x04, 0xfb, + 0xf5, 0xef, 0xe9, 0xe8, 0xeb, 0xea, 0xe2, 0xd8, 0xd0, 0xd1, 0xd7, 0xdc, + 0xdc, 0xd4, 0xcb, 0xcb, 0xcd, 0xce, 0xcf, 0xd2, 0xd7, 0xd9, 0xd9, 0xdb, + 0xe2, 0xea, 0xec, 0xe9, 0xe7, 0xe9, 0xeb, 0xec, 0xed, 0xee, 0xf4, 0xf8, + 0xf4, 0xed, 0xeb, 0xf2, 0xfc, 0x05, 0x09, 0x04, 0xff, 0xff, 0x02, 0x06, + 0x0b, 0x12, 0x14, 0x10, 0x0b, 0x09, 0x0b, 0x0d, 0x0d, 0x0d, 0x0e, 0x0b, + 0x06, 0x02, 0x00, 0x01, 0x05, 0x08, 0x06, 0x04, 0x05, 0x07, 0x0a, 0x0f, + 0x11, 0x0d, 0x09, 0x06, 0x04, 0x05, 0x07, 0x07, 0x03, 0xfe, 0xfd, 0xff, + 0xff, 0xfc, 0xfa, 0xfc, 0xff, 0xff, 0xfc, 0xf8, 0xf4, 0xf5, 0xf8, 0xf8, + 0xf8, 0xf7, 0xf6, 0xf6, 0xf4, 0xef, 0xed, 0xef, 0xee, 0xec, 0xeb, 0xec, + 0xed, 0xeb, 0xe7, 0xe3, 0xe4, 0xe8, 0xeb, 0xe6, 0xe0, 0xde, 0xde, 0xe0, + 0xe2, 0xe0, 0xdf, 0xe0, 0xe4, 0xe6, 0xe1, 0xde, 0xe2, 0xe6, 0xe6, 0xe4, + 0xe3, 0xe7, 0xea, 0xe8, 0xe3, 0xe4, 0xee, 0xf6, 0xf2, 0xea, 0xea, 0xf2, + 0xfa, 0xfd, 0xfb, 0xfc, 0x01, 0x06, 0x04, 0x00, 0x00, 0x04, 0x07, 0x02, + 0xfe, 0x00, 0x04, 0x03, 0xfe, 0xfd, 0x00, 0x07, 0x0d, 0x0b, 0x05, 0x04, + 0x0a, 0x0e, 0x0d, 0x0b, 0x0a, 0x0a, 0x0a, 0x0c, 0x10, 0x11, 0x0d, 0x09, + 0x08, 0x09, 0x0a, 0x0c, 0x0c, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, + 0x06, 0x08, 0x0d, 0x0d, 0x05, 0xff, 0xff, 0x00, 0x01, 0x01, 0x00, 0xff, + 0xfe, 0xff, 0x01, 0xfd, 0xf9, 0xfb, 0xfd, 0xfb, 0xfb, 0xfc, 0xf9, 0xf5, + 0xf3, 0xf4, 0xf9, 0xfe, 0xff, 0xfe, 0xfe, 0x01, 0x05, 0x05, 0x02, 0x00, + 0x00, 0x03, 0x06, 0x05, 0x06, 0x08, 0x05, 0x02, 0x04, 0x07, 0x08, 0x0a, + 0x0d, 0x0b, 0x09, 0x0b, 0x10, 0x11, 0x0c, 0x09, 0x09, 0x08, 0x03, 0xfd, + 0xf6, 0xf2, 0xef, 0xe9, 0xe1, 0xda, 0xd6, 0xd8, 0xd9, 0xd9, 0xda, 0xdb, + 0xd6, 0xcf, 0xca, 0xca, 0xce, 0xd1, 0xd1, 0xce, 0xcc, 0xcf, 0xd5, 0xd7, + 0xd7, 0xdd, 0xe4, 0xe6, 0xe6, 0xe5, 0xe5, 0xe6, 0xe9, 0xec, 0xee, 0xf1, + 0xf2, 0xf2, 0xf1, 0xf3, 0xf9, 0xfe, 0x01, 0x00, 0xff, 0x03, 0x08, 0x0a, + 0x09, 0x09, 0x0c, 0x11, 0x14, 0x10, 0x0f, 0x11, 0x13, 0x11, 0x0f, 0x0d, + 0x0b, 0x08, 0x08, 0x08, 0x0c, 0x11, 0x12, 0x0f, 0x0b, 0x0c, 0x12, 0x18, + 0x1a, 0x15, 0x10, 0x0d, 0x0b, 0x09, 0x09, 0x0b, 0x0f, 0x11, 0x0d, 0x09, + 0x09, 0x09, 0x0b, 0x0b, 0x09, 0x0b, 0x0d, 0x0a, 0x07, 0x07, 0x0b, 0x0d, + 0x0b, 0x07, 0x04, 0x02, 0x04, 0x06, 0x04, 0x01, 0xff, 0xff, 0xff, 0xff, + 0x01, 0x01, 0xff, 0xfb, 0xf8, 0xf9, 0xfc, 0xfe, 0xfd, 0xf9, 0xf6, 0xf6, + 0xf7, 0xf7, 0xf7, 0xfa, 0xfb, 0xf9, 0xf7, 0xf7, 0xf7, 0xf4, 0xf5, 0xf9, + 0xfd, 0xfd, 0xf9, 0xf6, 0xf6, 0xf7, 0xfb, 0xff, 0xfd, 0xfa, 0xf9, 0xfc, + 0x00, 0x01, 0x02, 0x01, 0xff, 0x01, 0x07, 0x0c, 0x0e, 0x0d, 0x0a, 0x07, + 0x07, 0x0b, 0x0b, 0x09, 0x09, 0x0e, 0x12, 0x11, 0x0d, 0x09, 0x0b, 0x10, + 0x16, 0x19, 0x17, 0x11, 0x0c, 0x0e, 0x14, 0x17, 0x19, 0x16, 0x10, 0x0f, + 0x13, 0x17, 0x17, 0x12, 0x10, 0x11, 0x12, 0x12, 0x12, 0x12, 0x13, 0x14, + 0x12, 0x10, 0x0e, 0x0f, 0x10, 0x0f, 0x0e, 0x0f, 0x0e, 0x09, 0x04, 0x05, + 0x0b, 0x10, 0x10, 0x0b, 0x08, 0x08, 0x0b, 0x0b, 0x09, 0x08, 0x06, 0x02, + 0x00, 0x00, 0x02, 0x05, 0x06, 0x05, 0x03, 0x02, 0x03, 0x05, 0x07, 0x09, + 0x09, 0x08, 0x08, 0x07, 0x06, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x07, + 0x07, 0x09, 0x0a, 0x09, 0x08, 0x08, 0x08, 0x08, 0x07, 0x03, 0xfe, 0xfa, + 0xf5, 0xee, 0xe6, 0xe1, 0xe0, 0xdc, 0xd8, 0xd4, 0xd1, 0xcf, 0xcd, 0xcd, + 0xcd, 0xcc, 0xca, 0xc8, 0xc6, 0xc4, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7, 0xcb, + 0xd0, 0xd3, 0xd7, 0xdc, 0xe2, 0xe8, 0xea, 0xea, 0xea, 0xed, 0xf1, 0xf4, + 0xf4, 0xf3, 0xf3, 0xf5, 0xf9, 0xfd, 0xff, 0xff, 0xff, 0x00, 0x02, 0x05, + 0x07, 0x08, 0x08, 0x07, 0x07, 0x0a, 0x0e, 0x0f, 0x0d, 0x0b, 0x09, 0x09, + 0x0a, 0x09, 0x07, 0x07, 0x0a, 0x0b, 0x08, 0x07, 0x05, 0x04, 0x06, 0x09, + 0x08, 0x05, 0x06, 0x08, 0x07, 0x07, 0x08, 0x08, 0x07, 0x07, 0x08, 0x08, + 0x08, 0x08, 0x07, 0x04, 0x02, 0x04, 0x07, 0x07, 0x06, 0x06, 0x07, 0x08, + 0x08, 0x06, 0x03, 0x03, 0x05, 0x06, 0x04, 0x00, 0xff, 0xff, 0xff, 0x01, + 0x02, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x01, 0xff, 0xff, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x06, 0x05, 0x04, + 0x04, 0x02, 0x01, 0x01, 0x04, 0x07, 0x07, 0x05, 0x02, 0xff, 0x00, 0x02, + 0x04, 0x04, 0x03, 0x01, 0x01, 0x01, 0x02, 0x04, 0x06, 0x05, 0x04, 0x05, + 0x07, 0x08, 0x09, 0x08, 0x09, 0x0c, 0x0d, 0x0b, 0x09, 0x0c, 0x12, 0x15, + 0x15, 0x13, 0x12, 0x13, 0x17, 0x17, 0x16, 0x18, 0x1a, 0x19, 0x19, 0x19, + 0x1a, 0x1b, 0x1b, 0x1a, 0x18, 0x16, 0x17, 0x17, 0x15, 0x15, 0x15, 0x16, + 0x14, 0x11, 0x0e, 0x0d, 0x0f, 0x10, 0x0f, 0x0c, 0x09, 0x08, 0x08, 0x09, + 0x08, 0x08, 0x07, 0x06, 0x06, 0x06, 0x06, 0x05, 0x02, 0x00, 0xff, 0xfe, + 0xfe, 0xff, 0xff, 0xfd, 0xfb, 0xfa, 0xfa, 0xfb, 0xfd, 0xfd, 0xfc, 0xfb, + 0xfa, 0xf9, 0xf7, 0xf7, 0xf9, 0xfc, 0xfe, 0xfc, 0xf8, 0xf7, 0xf7, 0xfa, + 0xfd, 0xfc, 0xf8, 0xf7, 0xfb, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, 0xf4, + 0xf0, 0xed, 0xec, 0xe8, 0xe2, 0xdb, 0xd7, 0xd6, 0xd3, 0xce, 0xcd, 0xd0, + 0xd3, 0xd2, 0xce, 0xca, 0xc8, 0xcb, 0xcb, 0xc6, 0xc2, 0xc3, 0xc9, 0xcc, + 0xcd, 0xcd, 0xce, 0xd2, 0xd8, 0xdd, 0xe0, 0xe3, 0xe6, 0xe8, 0xea, 0xec, + 0xf0, 0xf4, 0xf4, 0xf3, 0xf4, 0xf6, 0xf8, 0xfb, 0xfb, 0xfb, 0xfe, 0x01, + 0x03, 0x03, 0x03, 0x06, 0x09, 0x09, 0x08, 0x07, 0x06, 0x07, 0x09, 0x0a, + 0x0a, 0x09, 0x08, 0x07, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0a, 0x0a, + 0x09, 0x07, 0x06, 0x07, 0x09, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x09, 0x0a, + 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, + 0x0b, 0x0d, 0x0d, 0x0b, 0x0a, 0x0b, 0x0b, 0x09, 0x09, 0x09, 0x0a, 0x0a, + 0x09, 0x09, 0x08, 0x08, 0x09, 0x0a, 0x09, 0x09, 0x08, 0x07, 0x06, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x0c, + 0x0f, 0x0f, 0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x11, 0x14, 0x15, 0x15, + 0x13, 0x12, 0x14, 0x15, 0x16, 0x16, 0x17, 0x19, 0x1a, 0x19, 0x17, 0x18, + 0x1a, 0x1b, 0x1a, 0x17, 0x15, 0x18, 0x19, 0x16, 0x11, 0x11, 0x12, 0x13, + 0x12, 0x12, 0x12, 0x14, 0x15, 0x14, 0x11, 0x11, 0x13, 0x15, 0x14, 0x11, + 0x11, 0x13, 0x15, 0x14, 0x13, 0x13, 0x14, 0x14, 0x12, 0x11, 0x10, 0x11, + 0x14, 0x12, 0x0f, 0x0f, 0x11, 0x10, 0x0c, 0x0a, 0x0c, 0x10, 0x10, 0x0c, + 0x09, 0x08, 0x09, 0x0a, 0x09, 0x07, 0x07, 0x08, 0x08, 0x06, 0x04, 0x04, + 0x04, 0x03, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x00, 0x01, 0x03, 0x05, 0x05, 0x04, 0x00, 0x00, 0x0f, 0x11, 0x11, 0x0f, + 0x0d, 0x0b, 0x0c, 0x0d, 0x0d, 0x0c, 0x0b, 0x0b, 0x0b, 0x09, 0x0a, 0x09, + 0x09, 0x09, 0x09, 0x08, 0x07, 0x07, 0x07, 0x07, 0x05, 0x05, 0x05, 0x04, + 0x05, 0x05, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x01, 0x01, + 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, 0x05, 0x07, 0x08, 0x07, 0x06, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x07, 0x05, 0x05, 0x07, 0x07, + 0x09, 0x09, 0x09, 0x08, 0x07, 0x08, 0x07, 0x07, 0x08, 0x08, 0x07, 0x06, + 0x07, 0x07, 0x08, 0x08, 0x07, 0x05, 0x07, 0x07, 0x07, 0x05, 0x05, 0x05, + 0x05, 0x03, 0x03, 0x03, 0x01, 0x01, 0x02, 0x01, 0x01, 0x00, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x02, 0x01, 0xf5, 0xe5, 0xdd, 0xd9, 0xd7, 0xd5, 0xd3, 0xd1, 0xcf, + 0xcb, 0xc9, 0xc9, 0xc9, 0xc6, 0xc3, 0xc1, 0xc0, 0xc0, 0xbd, 0xbb, 0xb9, + 0xb9, 0xb8, 0xb8, 0xc3, 0xd3, 0xd7, 0xd9, 0xdc, 0xde, 0xe1, 0xe1, 0xe2, + 0xe5, 0xe7, 0xe8, 0xeb, 0xed, 0xef, 0xef, 0xf2, 0xf5, 0xf7, 0xf8, 0xf9, + 0xfb, 0xfd, 0xff, 0x01, 0x01, 0x01, 0x03, 0x03, 0x05, 0x07, 0x08, 0x08, + 0x07, 0x07, 0x07, 0x05, 0x05, 0x03, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x05, 0x05, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0b, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x0d, 0x0d, + 0x0d, 0x0f, 0x0f, 0x11, 0x11, 0x12, 0x11, 0x12, 0x13, 0x11, 0x11, 0x11, + 0x11, 0x0f, 0x0d, 0x0d, 0x0d, 0x0d, 0x0f, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x09, 0x0b, 0x0b, 0x09, + 0x0b, 0x0b, 0x0b, 0x0a, 0x09, 0x09, 0x07, 0x07, 0x07, 0x08, 0x09, 0x08, + 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x04, + 0x03, 0x05, 0x05, 0x04, 0x03, 0x03, 0x05, 0x06, 0x06, 0x06, 0x05, 0x05, + 0x05, 0x05, 0x07, 0x08, 0x09, 0x07, 0x07, 0x08, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x09, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, + 0x03, 0x02, 0x02, 0x03, 0x03, 0x03, 0x01, 0x01, 0x03, 0x03, 0x01, 0x00, + 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, + 0x01, 0x01, 0x01, 0x01, 0x01, 0xef, 0xe0, 0xdd, 0xd9, 0xd7, 0xd5, 0xd1, + 0xcf, 0xcf, 0xcd, 0xcb, 0xc7, 0xc6, 0xc5, 0xc3, 0xc1, 0xc0, 0xbd, 0xbc, + 0xbb, 0xb9, 0xb8, 0xb7, 0xb9, 0xcb, 0xd6, 0xd7, 0xd8, 0xdb, 0xde, 0xe1, + 0xe3, 0xe4, 0xe5, 0xe8, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf3, 0xf5, 0xf7, + 0xf9, 0xfb, 0xfb, 0xfd, 0xff, 0x01, 0x01, 0x02, 0x03, 0x05, 0x05, 0x05, + 0x07, 0x06, 0x07, 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0b, 0x0b, 0x0b, 0x09, 0x09, 0x09, 0x09, 0x0b, 0x0b, 0x0a, 0x09, + 0x0b, 0x0d, 0x0d, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0b, 0x0a, + 0x0b, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0b, 0x0b, 0x0b, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x11, 0x0f, 0x0d, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0e, 0x0d, 0x0b, 0x0b, 0x0b, 0x0d, 0x0c, + 0x0b, 0x0b, 0x0b, 0x0b, 0x09, 0x09, 0x08, 0x09, 0x09, 0x09, 0x09, 0x08, + 0x08, 0x09, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x05, 0x04, 0x04, 0x03, 0x03, + 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x00, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x01, 0x01, 0x01, + 0x00, 0x01, 0x01, 0x01, 0x01, 0xfc, 0xe9, 0xdf, 0xdb, 0xd8, 0xd5, 0xd3, + 0xd1, 0xcf, 0xcd, 0xc9, 0xc9, 0xc8, 0xc7, 0xc5, 0xc2, 0xbf, 0xbd, 0xbd, + 0xbc, 0xbb, 0xb9, 0xb7, 0xb7, 0xbb, 0xd1, 0xd5, 0xd9, 0xdb, 0xdb, 0xdf, + 0xe2, 0xe5, 0xe7, 0xe8, 0xe9, 0xeb, 0xef, 0xef, 0xf3, 0xf5, 0xf7, 0xf8, + 0xfa, 0xfb, 0xfd, 0xff, 0x01, 0x01, 0x03, 0x05, 0x05, 0x05, 0x07, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0e, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x0e, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0b, 0x0c, 0x0d, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x11, 0x0f, 0x11, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0d, 0x0f, 0x0f, 0x0f, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0b, 0x0b, 0x0c, + 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0b, 0x0b, 0x09, 0x09, 0x0b, 0x09, 0x09, + 0x09, 0x09, 0x0b, 0x09, 0x09, 0x08, 0x07, 0x08, 0x09, 0x09, 0x08, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, + 0x05, 0x03, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x03, 0x02, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x00, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0xff, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, + 0x00, 0xff, 0xff, 0x01, 0x00, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, 0xe8, 0xdd, 0xdb, 0xd9, 0xd5, + 0xd3, 0xd1, 0xcf, 0xcb, 0xc9, 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xc1, 0xc0, + 0xbd, 0xbd, 0xbd, 0xbc, 0xbb, 0xb9, 0xbb, 0xd3, 0xd9, 0xda, 0xdd, 0xdf, + 0xe1, 0xe4, 0xe5, 0xe8, 0xeb, 0xeb, 0xed, 0xef, 0xf1, 0xf3, 0xf5, 0xf7, + 0xf9, 0xfb, 0xfb, 0xfd, 0xff, 0x01, 0x01, 0x03, 0x05, 0x05, 0x05, 0x07, + 0x09, 0x09, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, + 0x0b, 0x0b, 0x0b, 0x0c, 0x0d, 0x0d, 0x0c, 0x0b, 0x0b, 0x0c, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0b, 0x0c, + 0x0d, 0x0d, 0x0b, 0x0b, 0x0b, 0x0c, 0x0d, 0x0f, 0x0e, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x11, 0x11, 0x11, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0f, 0x0f, 0x0d, 0x0d, 0x0b, 0x0b, + 0x0b, 0x0c, 0x0b, 0x0b, 0x0b, 0x0d, 0x0b, 0x0b, 0x0b, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x06, 0x05, 0x04, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x03, 0x05, 0x04, 0x04, 0x03, 0x03, 0x03, 0x05, 0x05, 0x03, 0x03, 0x03, + 0x04, 0x05, 0x03, 0x03, 0x02, 0x03, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, + 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0xfe, 0xff, 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x00, 0x01, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x02, 0xf7, 0xdf, 0xe1, 0xdd, + 0xd9, 0xd7, 0xd3, 0xd1, 0xcf, 0xcd, 0xcb, 0xc9, 0xc9, 0xc7, 0xc7, 0xc5, + 0xc3, 0xc1, 0xbd, 0xbf, 0xbd, 0xbd, 0xbb, 0xb9, 0xc3, 0xd9, 0xd9, 0xdb, + 0xdf, 0xdf, 0xe1, 0xe5, 0xe7, 0xe9, 0xe9, 0xed, 0xef, 0xf1, 0xf3, 0xf5, + 0xf5, 0xf8, 0xfb, 0xfb, 0xfd, 0xff, 0x01, 0x01, 0x03, 0x05, 0x05, 0x06, + 0x07, 0x09, 0x09, 0x09, 0x0b, 0x0b, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0d, 0x0c, 0x0b, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, + 0x0d, 0x0b, 0x0c, 0x0c, 0x0b, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0d, 0x0f, 0x0f, + 0x0d, 0x0e, 0x0d, 0x0d, 0x0c, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0e, 0x0d, 0x0e, 0x0f, 0x0e, 0x0d, 0x0d, + 0x0f, 0x0d, 0x0d, 0x0d, 0x0f, 0x0e, 0x0d, 0x0e, 0x0f, 0x0e, 0x0d, 0x0d, + 0x0b, 0x0b, 0x0c, 0x0b, 0x0d, 0x0b, 0x0d, 0x0d, 0x0b, 0x0b, 0x0b, 0x0a, + 0x09, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x0b, 0x09, 0x08, 0x08, 0x07, 0x07, + 0x09, 0x09, 0x07, 0x07, 0x07, 0x08, 0x07, 0x05, 0x07, 0x07, 0x06, 0x07, + 0x07, 0x06, 0x07, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05, 0x05, 0x07, 0x05, + 0x05, 0x05, 0x04, 0x05, 0x05, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, + 0x03, 0x03, 0x03, 0x02, 0x01, 0x02, 0x01, 0x01, 0x03, 0x02, 0x01, 0x01, + 0x01, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x03, + 0x01, 0x01, 0x01, 0x01, 0x02, 0x03, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x01, 0xff, 0xff, 0xff, + 0x00, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0xf5, 0xde, + 0xe0, 0xdd, 0xd9, 0xd7, 0xd5, 0xd3, 0xd1, 0xcf, 0xcd, 0xcc, 0xca, 0xc9, + 0xc8, 0xc6, 0xc5, 0xc3, 0xc1, 0xc0, 0xc0, 0xbd, 0xbd, 0xbb, 0xc5, 0xdb, + 0xda, 0xdd, 0xdf, 0xe1, 0xe3, 0xe6, 0xe8, 0xe9, 0xeb, 0xed, 0xef, 0xf2, + 0xf3, 0xf5, 0xf7, 0xf8, 0xfb, 0xfd, 0xfe, 0x00, 0x01, 0x03, 0x05, 0x05, + 0x07, 0x07, 0x09, 0x0a, 0x0b, 0x0b, 0x0b, 0x0d, 0x0d, 0x0b, 0x0b, 0x0c, + 0x0d, 0x0d, 0x0c, 0x0d, 0x0b, 0x0b, 0x0b, 0x0d, 0x0c, 0x0d, 0x0c, 0x0d, + 0x0b, 0x0c, 0x0b, 0x0b, 0x0c, 0x0d, 0x0b, 0x0c, 0x0d, 0x0c, 0x0d, 0x0d, + 0x0c, 0x0b, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, + 0x0f, 0x0d, 0x0d, 0x0d, 0x0d, 0x0b, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0d, 0x0f, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0f, 0x0d, 0x0e, 0x0d, 0x0d, 0x0d, 0x0d, 0x0f, 0x0e, 0x0d, + 0x0d, 0x0d, 0x0b, 0x0b, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0c, 0x0b, 0x0c, + 0x0b, 0x0b, 0x09, 0x0b, 0x0b, 0x0b, 0x09, 0x0b, 0x0b, 0x09, 0x09, 0x09, + 0x07, 0x08, 0x09, 0x09, 0x08, 0x09, 0x07, 0x06, 0x05, 0x05, 0x05, 0x06, + 0x05, 0x05, 0x05, 0x05, 0x07, 0x07, 0x07, 0x06, 0x05, 0x05, 0x05, 0x06, + 0x07, 0x05, 0x07, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x05, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, + 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0xfe, 0xe0, 0xe3, 0xdf, 0xdb, 0xd9, 0xd7, 0xd5, 0xd3, 0xd1, 0xd1, 0xcd, + 0xcb, 0xca, 0xca, 0xc7, 0xc6, 0xc4, 0xc3, 0xc1, 0xc1, 0xc0, 0xbe, 0xbd, + 0xc0, 0xdd, 0xdb, 0xdd, 0xe0, 0xe1, 0xe3, 0xe7, 0xe9, 0xea, 0xed, 0xef, + 0xf1, 0xf3, 0xf3, 0xf5, 0xf7, 0xf9, 0xfb, 0xfd, 0xff, 0x00, 0x01, 0x03, + 0x05, 0x05, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0b, 0x0d, 0x0b, 0x0c, 0x0c, 0x0d, 0x0b, 0x0d, + 0x0d, 0x0d, 0x0b, 0x0c, 0x0d, 0x0d, 0x0c, 0x0b, 0x0c, 0x0d, 0x0d, 0x0c, + 0x0b, 0x0c, 0x0c, 0x0b, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, + 0x0c, 0x0d, 0x0e, 0x0c, 0x0d, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0d, + 0x0d, 0x00, 0x00, 0x00, 0x03, 0x03, 0x02, 0xf2, 0xe9, 0xeb, 0xe1, 0xd7, + 0xd2, 0xc9, 0xba, 0xb3, 0xb4, 0xb4, 0xb7, 0xb7, 0xbe, 0xbb, 0xb9, 0xc8, + 0xd4, 0xcc, 0xec, 0xe0, 0xe6, 0xe5, 0xfe, 0x03, 0x03, 0x32, 0xe1, 0x14, + 0x55, 0x31, 0x1b, 0x32, 0x23, 0x20, 0x3a, 0x26, 0x27, 0x29, 0x33, 0x20, + 0x35, 0x18, 0x2e, 0x3b, 0x17, 0x07, 0x12, 0x0a, 0x15, 0x0e, 0x05, 0x06, + 0x13, 0x13, 0xd7, 0x1a, 0xfd, 0xfd, 0xd0, 0x21, 0xf5, 0xd1, 0xef, 0x07, + 0x0a, 0xc3, 0x0b, 0x28, 0xe3, 0xe8, 0x1b, 0x2f, 0xf1, 0x07, 0x1c, 0x17, + 0x12, 0x1a, 0x3e, 0x2d, 0x01, 0x25, 0x35, 0x20, 0x0d, 0x1e, 0x33, 0x0a, + 0x1d, 0x00, 0x46, 0x0f, 0xf6, 0x3b, 0xf5, 0x1c, 0x08, 0x06, 0x07, 0xf6, + 0x3a, 0xdf, 0x0f, 0x1a, 0xdb, 0x39, 0xfc, 0x0c, 0x21, 0x02, 0x13, 0x00, + 0x27, 0xfc, 0x12, 0x39, 0xe5, 0x1a, 0x22, 0x0b, 0x16, 0x10, 0x0a, 0x1b, + 0x01, 0xf6, 0x1f, 0x0d, 0xf4, 0x14, 0x1e, 0xe4, 0xf5, 0x1a, 0x02, 0xea, + 0xfb, 0x19, 0xfd, 0xdc, 0xf5, 0x1d, 0x01, 0xd8, 0xfc, 0x15, 0xf0, 0xf5, + 0x0e, 0x09, 0xd7, 0x09, 0x0b, 0x0e, 0xea, 0x05, 0x26, 0xf2, 0x05, 0xed, + 0x1b, 0xf2, 0xf7, 0xfc, 0xf6, 0xfd, 0x02, 0x00, 0xfd, 0xfc, 0xfd, 0xe7, + 0xe9, 0xf3, 0xef, 0xf7, 0xd7, 0xf7, 0x03, 0xd7, 0xd8, 0xf9, 0xec, 0xd9, + 0xd6, 0xde, 0xe9, 0xd2, 0xd7, 0xe8, 0xf9, 0xd0, 0xe4, 0x15, 0xbe, 0x0c, + 0x0d, 0x01, 0x08, 0xce, 0x42, 0xf1, 0x25, 0x10, 0x0b, 0x50, 0xec, 0x39, + 0x1d, 0xfc, 0x4b, 0xff, 0x0b, 0x1b, 0x0d, 0x24, 0xff, 0x2a, 0x09, 0x13, + 0x13, 0xe9, 0x16, 0x08, 0xed, 0x0d, 0x09, 0xe1, 0x05, 0x0d, 0xf7, 0x07, + 0x0c, 0x17, 0x15, 0xf7, 0x04, 0x27, 0x16, 0xfd, 0x19, 0x2e, 0xed, 0x17, + 0x26, 0x21, 0xfc, 0x1e, 0x28, 0x00, 0xfb, 0x0e, 0x26, 0x08, 0xf4, 0x17, + 0x26, 0xea, 0xf6, 0x0d, 0x13, 0xf6, 0xf8, 0x0d, 0xf0, 0xf0, 0x02, 0x07, + 0xf1, 0xe1, 0x00, 0x14, 0xe7, 0xf4, 0x03, 0xfd, 0xf3, 0xfc, 0xfe, 0x01, + 0x0d, 0x10, 0xf6, 0x05, 0x0e, 0x01, 0x02, 0xeb, 0x00, 0xff, 0xe5, 0xfa, + 0x10, 0x00, 0xf0, 0xfd, 0x02, 0xdd, 0xfb, 0xd1, 0x03, 0xf0, 0xd7, 0x00, + 0xd4, 0xff, 0xcf, 0xf2, 0xed, 0xb6, 0x02, 0xc3, 0xd9, 0xe1, 0xbf, 0x17, + 0xc6, 0xce, 0xf3, 0xdc, 0x02, 0xea, 0x08, 0xe3, 0xfd, 0x21, 0xdc, 0x06, + 0x1a, 0x12, 0x22, 0x0e, 0x0f, 0x3a, 0x0e, 0x15, 0x1a, 0x29, 0xf6, 0x24, + 0x11, 0x11, 0x18, 0x1c, 0x1b, 0x05, 0x09, 0xfe, 0x17, 0xf5, 0xec, 0x0f, + 0x09, 0xdf, 0xf1, 0x0a, 0x03, 0xe8, 0x1f, 0x05, 0xfb, 0x02, 0x00, 0x29, + 0xec, 0xfc, 0x24, 0x14, 0xf5, 0xfd, 0x2b, 0x25, 0xf7, 0x1a, 0x1a, 0x0f, + 0x0a, 0x12, 0x1e, 0x19, 0x0a, 0x19, 0x12, 0x07, 0x0b, 0x1a, 0x18, 0xf2, + 0x10, 0x06, 0x0d, 0x06, 0x00, 0xf7, 0xfb, 0x05, 0xf7, 0xf9, 0x00, 0x04, + 0x02, 0xe2, 0xf8, 0x1f, 0xe0, 0x0b, 0x05, 0x0c, 0xff, 0xf7, 0x1c, 0xf7, + 0x02, 0xf2, 0xeb, 0x0b, 0xe0, 0xfb, 0x0d, 0xeb, 0x0b, 0xec, 0xfd, 0xec, + 0xe0, 0xf9, 0xe6, 0xeb, 0xe1, 0xf7, 0xee, 0xe3, 0xe3, 0xfd, 0xe1, 0xf1, + 0xd9, 0xd1, 0xf1, 0xeb, 0xeb, 0xe6, 0xdd, 0xce, 0xf9, 0xd0, 0xd0, 0xef, + 0xee, 0xbe, 0xce, 0xdd, 0xc0, 0xd9, 0xe6, 0xd9, 0xe2, 0xd2, 0xf0, 0xec, + 0xe6, 0xe2, 0xf9, 0x06, 0xc0, 0xf7, 0x19, 0xee, 0x04, 0x26, 0x04, 0x10, + 0x2a, 0x3e, 0x00, 0x17, 0x1a, 0x17, 0x28, 0xfd, 0x0a, 0x3b, 0x45, 0x03, + 0x43, 0x2d, 0x34, 0x1c, 0x32, 0x34, 0x1d, 0x1a, 0x27, 0x36, 0x13, 0x19, + 0x4d, 0x2a, 0xf6, 0x2e, 0x16, 0x05, 0xe5, 0x32, 0x0a, 0x00, 0xf4, 0x08, + 0x1b, 0xe2, 0x10, 0x15, 0xee, 0x01, 0x13, 0x1f, 0xf1, 0x0a, 0x22, 0xdf, + 0x29, 0x09, 0x1c, 0x20, 0xfa, 0x3d, 0x07, 0x14, 0x11, 0x16, 0x2e, 0x01, + 0x2e, 0x11, 0x1c, 0x31, 0x17, 0x2f, 0xf8, 0x14, 0x19, 0xed, 0x05, 0xfa, + 0x2f, 0x02, 0xf0, 0x1a, 0xdf, 0x20, 0xf5, 0xe7, 0x18, 0xef, 0xff, 0xf3, + 0x05, 0xe8, 0x06, 0x24, 0xdc, 0xe3, 0x0a, 0x01, 0xe1, 0xf9, 0xf7, 0xeb, + 0x01, 0xcf, 0xfc, 0x0e, 0xd2, 0x1b, 0x03, 0xe6, 0xf9, 0x06, 0x1e, 0xd5, + 0x19, 0x1b, 0x00, 0x14, 0x00, 0x1f, 0x27, 0x05, 0x0d, 0x12, 0x07, 0x09, + 0x24, 0x09, 0xf9, 0x22, 0x1c, 0x02, 0xfb, 0x1b, 0x17, 0x10, 0xf3, 0x05, + 0xfc, 0xf8, 0xf4, 0x10, 0xfe, 0xe9, 0x22, 0x06, 0xf8, 0x0d, 0x09, 0x13, + 0xf3, 0xef, 0x19, 0xfb, 0x09, 0xf2, 0x1f, 0x1c, 0xdd, 0x08, 0xf7, 0xed, + 0x03, 0xe9, 0xfc, 0xe3, 0xf3, 0xf6, 0xe1, 0xfe, 0xdb, 0x04, 0xda, 0xe6, + 0x19, 0xe5, 0x06, 0xde, 0xfe, 0x05, 0xde, 0x1e, 0xe9, 0x23, 0x09, 0x01, + 0x26, 0xd2, 0x38, 0x0e, 0xfc, 0x12, 0x08, 0x31, 0xff, 0x23, 0x16, 0x17, + 0x19, 0xec, 0x04, 0x03, 0xf4, 0x03, 0x10, 0xed, 0xf1, 0x1e, 0xeb, 0xec, + 0x06, 0x01, 0x07, 0xe0, 0xec, 0x06, 0x03, 0xef, 0xf3, 0x16, 0xe7, 0xed, + 0x1b, 0xf3, 0xe0, 0x0d, 0x03, 0xe3, 0xdf, 0xfc, 0x01, 0xf9, 0xea, 0xff, + 0x13, 0xe5, 0xf7, 0x13, 0x03, 0xf9, 0x1a, 0x16, 0xf0, 0x0d, 0x2c, 0x18, + 0x00, 0x0f, 0x1c, 0x26, 0xf1, 0x07, 0x2f, 0xff, 0x0c, 0x17, 0x10, 0x02, + 0x03, 0x2b, 0x00, 0xfb, 0x13, 0x00, 0x05, 0xdd, 0x08, 0x12, 0xe5, 0x01, + 0x09, 0x05, 0xff, 0x00, 0x06, 0xf1, 0x05, 0xee, 0xf8, 0xff, 0xf2, 0x13, + 0xf8, 0xfb, 0xf4, 0xfb, 0x00, 0xd2, 0x09, 0xe4, 0xe8, 0xf5, 0xdd, 0x11, + 0xda, 0xe1, 0xfa, 0xdc, 0x01, 0xe7, 0xfc, 0xe4, 0xf8, 0x0e, 0xe1, 0xf5, + 0x04, 0x07, 0x08, 0x00, 0x08, 0x1b, 0xfe, 0x0e, 0x0c, 0x16, 0xf3, 0x29, + 0x10, 0x0e, 0x15, 0x21, 0x30, 0xf4, 0x10, 0x0f, 0x0f, 0xfe, 0xf2, 0x18, + 0x0f, 0xeb, 0x02, 0x0e, 0x04, 0xf1, 0x1a, 0x03, 0xe5, 0x00, 0x0b, 0x0d, + 0xe6, 0xfe, 0x14, 0x03, 0xec, 0xfb, 0x1e, 0xfe, 0xea, 0x0f, 0xfe, 0xe5, + 0x00, 0x04, 0xfc, 0xf6, 0xfe, 0x13, 0xf6, 0xea, 0x17, 0x14, 0x07, 0xf5, + 0x17, 0x18, 0x03, 0x1b, 0x03, 0x13, 0x18, 0x0c, 0x11, 0x0a, 0x09, 0x16, + 0x11, 0xfd, 0x15, 0x11, 0x00, 0x0a, 0x07, 0x0e, 0x01, 0x0b, 0x0a, 0xef, + 0xfc, 0xf6, 0x06, 0xf1, 0xf3, 0x0e, 0xfd, 0xf5, 0xfe, 0xf6, 0x06, 0xe8, + 0xef, 0xfe, 0xec, 0xf9, 0xf4, 0x09, 0xee, 0xf3, 0x03, 0xee, 0xf3, 0xee, + 0xe8, 0xf0, 0xf1, 0xf6, 0xeb, 0xef, 0xe7, 0xf4, 0xfa, 0xe2, 0x02, 0xfe, + 0xe8, 0x06, 0xf5, 0x0b, 0xee, 0xfe, 0x04, 0xfe, 0xf8, 0xfc, 0x11, 0xf7, + 0xea, 0xf9, 0x08, 0xe5, 0xf0, 0x05, 0x03, 0xf9, 0xfd, 0x0e, 0x0a, 0xee, + 0x11, 0x0b, 0xfc, 0xf3, 0x18, 0x09, 0xf8, 0x0a, 0x09, 0x24, 0x0b, 0x19, + 0x1f, 0x11, 0x0c, 0x12, 0x20, 0x1f, 0x05, 0x1a, 0x24, 0x11, 0x1a, 0x26, + 0x27, 0x20, 0x12, 0x1c, 0x10, 0x0d, 0x19, 0x12, 0x24, 0x06, 0x06, 0x1c, + 0xf9, 0x13, 0x00, 0xfe, 0xff, 0x01, 0xff, 0xee, 0x02, 0xf8, 0xf1, 0xf8, + 0xf1, 0x02, 0xf3, 0xe9, 0x04, 0xfd, 0xf3, 0xf5, 0x07, 0xfc, 0xfb, 0x07, + 0x11, 0x0f, 0x08, 0x09, 0x18, 0x09, 0xff, 0x06, 0x06, 0x0c, 0x10, 0x03, + 0x0f, 0x12, 0xff, 0x0a, 0xf8, 0xfd, 0xf8, 0xfe, 0x00, 0xe4, 0x02, 0xf1, + 0xe9, 0x0b, 0xd6, 0xf8, 0xf5, 0xdc, 0xfb, 0xe6, 0xfa, 0xeb, 0xed, 0xef, + 0xe3, 0x14, 0xe6, 0xf3, 0x16, 0xee, 0xff, 0x03, 0x05, 0xff, 0x05, 0x11, + 0xfd, 0x1a, 0x0b, 0x17, 0x22, 0x0e, 0x13, 0x15, 0x10, 0x07, 0x18, 0x21, + 0x10, 0x11, 0x16, 0x0e, 0x11, 0x0c, 0x07, 0x0e, 0x12, 0xf8, 0x0e, 0x06, + 0xff, 0x03, 0x06, 0x0e, 0x01, 0x0f, 0x01, 0x14, 0x13, 0x02, 0x11, 0x11, + 0x04, 0x05, 0x0a, 0x0f, 0x0b, 0x1c, 0x12, 0x1a, 0x08, 0x04, 0x23, 0x07, + 0x10, 0x0f, 0x19, 0x08, 0x06, 0x17, 0x04, 0x07, 0x00, 0x01, 0x08, 0xf6, + 0xfb, 0x05, 0xf2, 0xf0, 0xf8, 0xfc, 0xec, 0xf9, 0xf2, 0xf5, 0xf7, 0xf5, + 0x0c, 0xf3, 0xf0, 0x07, 0x01, 0xfc, 0xf6, 0x1a, 0x0c, 0xf9, 0x0a, 0xee, + 0x09, 0x00, 0xf5, 0x07, 0xfc, 0x02, 0x01, 0x03, 0xf4, 0xf0, 0x0b, 0xec, + 0xef, 0xef, 0xe7, 0xfd, 0xe8, 0xed, 0xef, 0xef, 0xea, 0xe3, 0xee, 0xeb, + 0xf5, 0xf8, 0xe1, 0xea, 0xfd, 0xed, 0xf1, 0xf8, 0x01, 0xf3, 0xfb, 0x02, + 0xfc, 0x00, 0x03, 0xfe, 0x09, 0x04, 0xfe, 0x18, 0x07, 0x0e, 0x14, 0x11, + 0x02, 0x0c, 0x0c, 0x0f, 0x11, 0x16, 0x17, 0x10, 0x11, 0x0a, 0x1a, 0x0d, + 0x08, 0x18, 0x13, 0xff, 0x0a, 0x0e, 0x0c, 0x0b, 0x08, 0x0d, 0x0d, 0x08, + 0x0b, 0x15, 0x09, 0x09, 0x15, 0x0c, 0xf4, 0x09, 0x07, 0x11, 0x0a, 0x0b, + 0x0e, 0x0d, 0x08, 0x06, 0x13, 0x04, 0x08, 0x0e, 0x0b, 0x0b, 0x06, 0x0e, + 0x05, 0xfb, 0x09, 0xf7, 0x0a, 0xf8, 0xfe, 0xff, 0xeb, 0x0a, 0xf6, 0xf9, + 0xf2, 0xf5, 0xfc, 0xf6, 0xf9, 0xf7, 0xfa, 0x07, 0xec, 0xfd, 0xfb, 0xfd, + 0x0e, 0xff, 0x00, 0xfd, 0x07, 0xf6, 0xfb, 0x05, 0xf6, 0x05, 0x04, 0xf7, + 0xfa, 0x00, 0x04, 0xfc, 0xf7, 0xf8, 0xf5, 0xfd, 0xea, 0xf4, 0xfd, 0xf1, + 0xe9, 0xf0, 0xf4, 0xe9, 0xf2, 0xf8, 0xf5, 0xf3, 0xeb, 0xf9, 0xfd, 0xec, + 0x01, 0xff, 0x01, 0xf7, 0x00, 0x10, 0xfc, 0x09, 0x09, 0x02, 0x08, 0x02, + 0x0f, 0x0f, 0x03, 0x16, 0x0d, 0x08, 0xfd, 0x10, 0x0e, 0x06, 0x13, 0x0f, + 0x0f, 0x0f, 0x05, 0x0e, 0x0f, 0x0a, 0x0d, 0x0d, 0x08, 0x01, 0x14, 0x07, + 0x04, 0x0d, 0x06, 0x09, 0x09, 0x07, 0x0c, 0x10, 0x11, 0x02, 0x05, 0x05, + 0xfe, 0x0b, 0xfd, 0x06, 0x07, 0x04, 0x03, 0x03, 0x03, 0x00, 0x01, 0x03, + 0x01, 0x01, 0x01, 0x0b, 0x04, 0xfb, 0x00, 0x01, 0x02, 0x01, 0xfe, 0xfb, + 0xfb, 0x00, 0xff, 0xfd, 0xfb, 0xf6, 0x08, 0xf1, 0xf5, 0x09, 0x02, 0x00, + 0xfa, 0x08, 0x01, 0xfc, 0x0d, 0x0b, 0x09, 0x04, 0x07, 0x0f, 0xfe, 0xfc, + 0x09, 0x09, 0xfa, 0x02, 0x06, 0xff, 0xfa, 0xfb, 0x03, 0x00, 0xf0, 0xfd, + 0xfb, 0xf1, 0xf8, 0xf7, 0xfe, 0xec, 0xf1, 0xfb, 0xf2, 0xf5, 0xfa, 0xfe, + 0x00, 0xf5, 0x03, 0x06, 0x02, 0x03, 0x05, 0x11, 0xfe, 0x08, 0x13, 0x05, + 0x0e, 0x0f, 0x0a, 0x0b, 0x09, 0x0b, 0x0c, 0x12, 0x05, 0x06, 0x0e, 0x01, + 0x03, 0x09, 0x07, 0x0c, 0x06, 0x07, 0x07, 0x0d, 0x04, 0x00, 0x12, 0x04, + 0x03, 0x08, 0x09, 0x07, 0x04, 0x05, 0x0c, 0x0b, 0x04, 0x07, 0x09, 0x08, + 0x0e, 0x0f, 0x0c, 0x09, 0x09, 0x0c, 0x06, 0x02, 0x09, 0x07, 0x07, 0x00, + 0x02, 0x03, 0x00, 0x01, 0xf5, 0x01, 0xff, 0xfa, 0x01, 0xfa, 0xf5, 0xfe, + 0xfd, 0xf8, 0xf6, 0xf7, 0xfe, 0xf3, 0xf3, 0xf5, 0xfd, 0xf9, 0xf2, 0xfa, + 0xfe, 0xf1, 0xff, 0xff, 0xfc, 0xfb, 0xfd, 0x02, 0x01, 0x03, 0x01, 0x0b, + 0x03, 0x05, 0x05, 0x07, 0x05, 0x00, 0x08, 0x02, 0x05, 0x08, 0x00, 0x03, + 0x04, 0x03, 0x00, 0xfe, 0x04, 0xf9, 0x02, 0x00, 0xf8, 0x00, 0xfe, 0xf8, + 0xf7, 0xf9, 0xfe, 0xfb, 0x00, 0xf5, 0x03, 0x06, 0xf9, 0x0a, 0x05, 0x03, + 0x0a, 0x09, 0x0a, 0x05, 0x11, 0x0f, 0x0a, 0x0d, 0x08, 0x13, 0x0c, 0x08, + 0x0c, 0x12, 0x0a, 0x01, 0x0e, 0x06, 0x05, 0x05, 0x05, 0x0c, 0x03, 0x06, + 0x08, 0x05, 0x07, 0xff, 0x07, 0x04, 0x02, 0x05, 0x00, 0x03, 0x03, 0x08, + 0x07, 0x00, 0x08, 0x01, 0x05, 0x08, 0x05, 0x06, 0x07, 0x09, 0xff, 0x03, + 0x05, 0x03, 0x08, 0x00, 0xff, 0x09, 0xfd, 0xfd, 0xff, 0x01, 0xf7, 0x03, + 0x01, 0xf7, 0x01, 0xfe, 0x01, 0xfc, 0xfe, 0xf8, 0x00, 0xfa, 0xf4, 0xff, + 0xfd, 0xfa, 0xfb, 0xfb, 0xf9, 0xfa, 0x01, 0xfd, 0xfe, 0x00, 0xfe, 0x04, + 0x00, 0x00, 0x05, 0x0b, 0x05, 0x01, 0x0e, 0x07, 0x08, 0x08, 0x06, 0x08, + 0x08, 0x08, 0x02, 0x06, 0x09, 0x02, 0x06, 0xff, 0x00, 0x05, 0xff, 0xfb, + 0x01, 0x00, 0xfb, 0xfe, 0x00, 0xfa, 0xfe, 0xfe, 0xfc, 0xfa, 0xff, 0x00, + 0x00, 0x00, 0xff, 0x09, 0x07, 0xfd, 0x07, 0x06, 0x07, 0x06, 0x05, 0x0a, + 0x04, 0x05, 0x0a, 0x06, 0x09, 0x04, 0x06, 0x05, 0x04, 0x06, 0xff, 0x06, + 0xff, 0x05, 0x02, 0x02, 0x02, 0x05, 0xff, 0xff, 0x04, 0x02, 0xfd, 0x03, + 0x00, 0xfe, 0x00, 0xfe, 0x04, 0x00, 0xfe, 0x00, 0x03, 0xfc, 0xfe, 0x06, + 0xff, 0xfd, 0x02, 0x02, 0xfd, 0x03, 0x00, 0x00, 0x02, 0x00, 0x01, 0x02, + 0xfc, 0x00, 0x02, 0x03, 0x00, 0x02, 0x03, 0x00, 0x02, 0x03, 0x02, 0x01, + 0x00, 0x01, 0x00, 0xfd, 0x00, 0x01, 0x00, 0xfb, 0xff, 0x04, 0xfb, 0xff, + 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x03, 0x01, 0x04, + 0x04, 0xff, 0x02, 0x05, 0x02, 0x01, 0x03, 0x04, 0x04, 0x01, 0x07, 0x04, + 0x02, 0x02, 0x04, 0x04, 0xff, 0x02, 0x03, 0x00, 0xff, 0x02, 0x03, 0x00, + 0xfe, 0x04, 0x00, 0xff, 0x00, 0x02, 0x01, 0x00, 0x02, 0x02, 0x02, 0x00, + 0x03, 0x03, 0x02, 0x02, 0x03, 0x03, 0x02, 0x05, 0x04, 0x02, 0x03, 0x04, + 0x03, 0x03, 0x03, 0x04, 0x03, 0x01, 0x01, 0x04, 0x02, 0x00, 0x03, 0x02, + 0x00, 0x01, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x01, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xfe, 0xf9, 0xf3, 0xed, 0xe9, 0xe5, 0xe3, 0xe1, 0xdf, + 0xdd, 0xdb, 0xd9, 0xd7, 0xd5, 0xd3, 0xd1, 0xcf, 0xcd, 0xcb, 0xc9, 0xc8, + 0xc7, 0xc5, 0xc3, 0xc2, 0xc1, 0xbf, 0xbd, 0xbc, 0xbb, 0xb9, 0xb7, 0xb6, + 0xb5, 0xb3, 0xb2, 0xb1, 0xb0, 0xaf, 0xaf, 0xae, 0xad, 0xad, 0xad, 0xad, + 0xaf, 0xb3, 0xb9, 0xc1, 0xc9, 0xd0, 0xd7, 0xdd, 0xe2, 0xe6, 0xe9, 0xec, + 0xef, 0xf2, 0xf5, 0xf7, 0xf9, 0xfc, 0xfd, 0xff, 0x01, 0x03, 0x05, 0x07, + 0x09, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x11, 0x13, 0x15, 0x17, 0x18, 0x19, + 0x1a, 0x1b, 0x1b, 0x1c, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x22, 0x23, 0x24, + 0x25, 0x27, 0x29, 0x2a, 0x2b, 0x2b, 0x2d, 0x2f, 0x31, 0x30, 0x2f, 0x30, + 0x33, 0x36, 0x37, 0x37, 0x36, 0x35, 0x33, 0x33, 0x33, 0x35, 0x38, 0x3b, + 0x3e, 0x41, 0x44, 0x44, 0x44, 0x46, 0x49, 0x49, 0x47, 0x46, 0x46, 0x47, + 0x48, 0x48, 0x47, 0x46, 0x46, 0x46, 0x48, 0x49, 0x48, 0x47, 0x46, 0x46, + 0x46, 0x47, 0x48, 0x47, 0x47, 0x47, 0x48, 0x49, 0x48, 0x47, 0x47, 0x47, + 0x48, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x48, 0x48, 0x47, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, + 0x47, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40, 0x40, 0x40, + 0x3f, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3a, + 0x3a, 0x3a, 0x3a, 0x39, 0x38, 0x38, 0x37, 0x36, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x34, 0x33, 0x31, 0x2f, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2e, 0x2f, 0x2f, 0x2e, 0x2d, 0x2d, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, + 0x27, 0x25, 0x26, 0x28, 0x2b, 0x2c, 0x2a, 0x27, 0x26, 0x26, 0x27, 0x28, + 0x27, 0x25, 0x22, 0x1f, 0x1f, 0x21, 0x22, 0x23, 0x24, 0x25, 0x25, 0x25, + 0x25, 0x26, 0x26, 0x25, 0x22, 0x20, 0x1e, 0x1e, 0x20, 0x21, 0x22, 0x22, + 0x23, 0x26, 0x29, 0x29, 0x28, 0x27, 0x25, 0x23, 0x21, 0x21, 0x21, 0x22, + 0x23, 0x25, 0x27, 0x29, 0x2a, 0x2b, 0x2c, 0x2c, 0x2b, 0x2a, 0x28, 0x26, + 0x25, 0x25, 0x26, 0x27, 0x28, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2a, + 0x2a, 0x29, 0x28, 0x27, 0x27, 0x29, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x2f, + 0x2f, 0x2f, 0x30, 0x30, 0x2f, 0x2d, 0x2c, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x31, 0x31, 0x31, 0x30, 0x2f, 0x2d, 0x2d, 0x2c, 0x2b, 0x2a, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2e, 0x2d, 0x2c, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x26, 0x26, 0x28, 0x2a, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2a, 0x29, 0x27, 0x25, 0x25, 0x27, 0x28, 0x29, 0x29, 0x27, + 0x25, 0x23, 0x23, 0x24, 0x25, 0x24, 0x24, 0x24, 0x23, 0x22, 0x21, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x20, 0x1f, 0x1d, 0x1c, 0x1b, 0x1b, 0x1b, + 0x1d, 0x1f, 0x21, 0x21, 0x20, 0x1d, 0x1a, 0x18, 0x18, 0x19, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1e, 0x1b, 0x19, 0x17, 0x17, 0x19, 0x1b, 0x1d, 0x1e, 0x1f, + 0x1f, 0x1e, 0x1c, 0x1a, 0x19, 0x19, 0x1b, 0x1d, 0x1e, 0x1f, 0x1e, 0x1d, + 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1d, 0x1c, 0x1b, 0x1b, 0x1b, + 0x1c, 0x1d, 0x1e, 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1d, 0x1e, + 0x20, 0x21, 0x22, 0x22, 0x20, 0x1e, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, + 0x1d, 0x1e, 0x1f, 0x1e, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1d, + 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1c, 0x1b, 0x1a, 0x19, + 0x18, 0x15, 0x12, 0x0e, 0x0a, 0x06, 0x02, 0xfe, 0xfb, 0xf8, 0xf4, 0xf1, + 0xee, 0xe9, 0xe4, 0xdf, 0xd9, 0xd5, 0xd1, 0xcd, 0xcb, 0xc9, 0xc8, 0xc7, + 0xc5, 0xc4, 0xc3, 0xc1, 0xbf, 0xbc, 0xba, 0xb8, 0xb6, 0xb4, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb2, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb1, 0xb3, 0xb5, 0xb9, 0xbd, 0xc1, 0xc5, 0xc9, 0xce, 0xd1, 0xd4, 0xd7, + 0xd9, 0xdc, 0xdf, 0xe1, 0xe5, 0xe8, 0xeb, 0xef, 0xf3, 0xf7, 0xfb, 0xfe, + 0x01, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x07, 0x09, + 0x0b, 0x0d, 0x0e, 0x0f, 0x10, 0x10, 0x0f, 0x0e, 0x0d, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x15, 0x14, 0x13, 0x11, 0x11, + 0x12, 0x13, 0x14, 0x15, 0x15, 0x15, 0x17, 0x18, 0x19, 0x1a, 0x19, 0x18, + 0x17, 0x16, 0x16, 0x16, 0x16, 0x17, 0x18, 0x18, 0x19, 0x1b, 0x1c, 0x1d, + 0x1d, 0x1c, 0x1b, 0x19, 0x19, 0x19, 0x1a, 0x19, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1b, 0x1a, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x18, 0x19, 0x19, 0x19, 0x19, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x18, 0x17, 0x16, 0x15, 0x15, 0x15, + 0x15, 0x14, 0x13, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x12, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x10, 0x0f, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0e, 0x0f, 0x0f, 0x10, 0x10, 0x0f, 0x0e, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0d, 0x0e, 0x0f, 0x0f, 0x0d, 0x0b, 0x0b, 0x0a, 0x09, + 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, + 0x05, 0x05, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x05, 0x05, + 0x05, 0x05, 0x06, 0x07, 0x08, 0x07, 0x06, 0x05, 0x03, 0x03, 0x05, 0x07, + 0x09, 0x0b, 0x0c, 0x0c, 0x0b, 0x09, 0x07, 0x07, 0x07, 0x07, 0x09, 0x0b, + 0x0d, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x11, 0x13, 0x14, 0x13, 0x12, + 0x11, 0x0f, 0x0d, 0x0c, 0x0d, 0x11, 0x14, 0x17, 0x19, 0x19, 0x17, 0x15, + 0x14, 0x15, 0x17, 0x18, 0x19, 0x1a, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1b, + 0x1d, 0x1f, 0x21, 0x23, 0x24, 0x22, 0x20, 0x1e, 0x1d, 0x1e, 0x20, 0x22, + 0x25, 0x27, 0x26, 0x24, 0x22, 0x20, 0x1f, 0x1f, 0x21, 0x23, 0x25, 0x26, + 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x20, 0x20, 0x21, 0x22, 0x22, 0x21, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x22, 0x23, 0x23, 0x22, 0x21, 0x20, 0x1f, + 0x1f, 0x20, 0x21, 0x22, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1b, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, + 0x1b, 0x1c, 0x1b, 0x1a, 0x18, 0x16, 0x15, 0x15, 0x15, 0x15, 0x15, 0x16, + 0x17, 0x17, 0x17, 0x16, 0x15, 0x13, 0x00, 0x00, 0xfd, 0xff, 0x01, 0x07, + 0x10, 0x16, 0x18, 0x16, 0x0f, 0x04, 0xfd, 0xf9, 0xfa, 0xfe, 0x02, 0x07, + 0x0a, 0x0a, 0x08, 0x05, 0x03, 0x02, 0x01, 0x01, 0xfd, 0xfa, 0xf8, 0xf5, + 0xf3, 0xf1, 0xee, 0xed, 0xec, 0xef, 0xf5, 0x00, 0x0b, 0x18, 0x1f, 0x21, + 0x1e, 0x19, 0x15, 0x12, 0x12, 0x15, 0x15, 0x12, 0x0d, 0x05, 0xfd, 0xf5, + 0xf2, 0xf9, 0xec, 0xe0, 0xda, 0xdb, 0xdd, 0xe0, 0xeb, 0xfd, 0x0e, 0x11, + 0x07, 0x02, 0x0d, 0x22, 0x2d, 0x21, 0x0d, 0xff, 0x01, 0x0a, 0x07, 0xf9, + 0xf0, 0xf0, 0xf9, 0xff, 0x01, 0x04, 0x0d, 0x17, 0x19, 0x10, 0x07, 0x07, + 0x0c, 0x09, 0xf5, 0xdc, 0xdb, 0xd8, 0xe4, 0xf0, 0xec, 0xe6, 0xea, 0xfa, + 0x0f, 0x1e, 0x29, 0x31, 0x33, 0x2d, 0x26, 0x19, 0x19, 0x25, 0x28, 0x1b, + 0x00, 0xe6, 0xe0, 0xeb, 0xf3, 0xf0, 0xe5, 0xdd, 0xdc, 0xde, 0xdf, 0xe5, + 0xf3, 0x02, 0x0a, 0x07, 0x00, 0x03, 0x15, 0x26, 0x2a, 0x1c, 0x0b, 0x01, + 0x02, 0x06, 0x00, 0xf8, 0xf5, 0xfa, 0x00, 0x03, 0x04, 0x06, 0x0c, 0x14, + 0x11, 0x08, 0x04, 0x05, 0x06, 0xfe, 0xea, 0xdb, 0xd9, 0xdd, 0xea, 0xee, + 0xeb, 0xed, 0xf8, 0x0b, 0x1d, 0x27, 0x2c, 0x30, 0x2e, 0x27, 0x1b, 0x16, + 0x1b, 0x24, 0x23, 0x0d, 0xf4, 0xe4, 0xe3, 0xec, 0xef, 0xe9, 0xe2, 0xde, + 0xde, 0xe1, 0xe4, 0xeb, 0xf7, 0x03, 0x06, 0x01, 0xff, 0x0a, 0x1c, 0x2a, + 0x26, 0x17, 0x08, 0x03, 0x02, 0x00, 0xfc, 0xf9, 0xfb, 0x01, 0x07, 0x05, + 0x04, 0x07, 0x0d, 0x0f, 0x0a, 0x05, 0x02, 0x03, 0x01, 0xf6, 0xe4, 0xdb, + 0xd9, 0xe2, 0xeb, 0xed, 0xee, 0xf6, 0x07, 0x19, 0x26, 0x2b, 0x2d, 0x2c, + 0x26, 0x1d, 0x15, 0x16, 0x1f, 0x22, 0x18, 0x03, 0xed, 0xe3, 0xe6, 0xec, + 0xeb, 0xe5, 0xe0, 0xe0, 0xe1, 0xe4, 0xe8, 0xf0, 0xfa, 0x01, 0x00, 0x00, + 0x05, 0x11, 0x25, 0x2d, 0x24, 0x13, 0x07, 0x01, 0x00, 0xfe, 0xfc, 0xfc, + 0x02, 0x09, 0x0a, 0x07, 0x05, 0x07, 0x0a, 0x09, 0x05, 0x00, 0xff, 0xff, + 0xfc, 0xef, 0xe1, 0xdc, 0xe0, 0xea, 0xef, 0xf2, 0xf8, 0x06, 0x1a, 0x29, + 0x30, 0x30, 0x2c, 0x29, 0x24, 0x1c, 0x1a, 0x1e, 0x24, 0x22, 0x11, 0xfa, + 0xe9, 0xe3, 0xe5, 0xe7, 0xe3, 0xdd, 0xda, 0xdb, 0xde, 0xe1, 0xe6, 0xef, + 0xf7, 0xfb, 0xfc, 0xfc, 0x07, 0x17, 0x26, 0x26, 0x1a, 0x0c, 0x00, 0xfc, + 0xfc, 0xfd, 0xfe, 0x04, 0x0b, 0x0e, 0x0c, 0x08, 0x06, 0x07, 0x0a, 0x07, + 0x02, 0xfd, 0xfc, 0xfc, 0xf6, 0xea, 0xe1, 0xe0, 0xe5, 0xed, 0xf2, 0xf8, + 0x03, 0x16, 0x26, 0x30, 0x31, 0x2d, 0x27, 0x22, 0x1d, 0x1a, 0x1c, 0x20, + 0x21, 0x17, 0x04, 0xf0, 0xe5, 0xe3, 0xe5, 0xe2, 0xde, 0xdc, 0xdb, 0xde, + 0xe0, 0xe5, 0xea, 0xf2, 0xf7, 0xfa, 0xfb, 0x02, 0x12, 0x21, 0x27, 0x23, + 0x14, 0x06, 0xfe, 0xfb, 0xfc, 0xff, 0x04, 0x0a, 0x0e, 0x0d, 0x09, 0x05, + 0x05, 0x08, 0x07, 0x04, 0xfe, 0xfc, 0xfb, 0xf9, 0xf1, 0xe8, 0xe3, 0xe3, + 0xe9, 0xef, 0xf6, 0xff, 0x11, 0x21, 0x2e, 0x32, 0x2e, 0x28, 0x21, 0x1d, + 0x1a, 0x1a, 0x1d, 0x20, 0x1a, 0x0d, 0xf9, 0xe9, 0xe1, 0xe0, 0xe2, 0xdf, + 0xdd, 0xdb, 0xdc, 0xdf, 0xe3, 0xe8, 0xed, 0xf3, 0xf8, 0xfb, 0xfe, 0x0b, + 0x1a, 0x26, 0x28, 0x1d, 0x0c, 0x00, 0xfb, 0xfb, 0x00, 0x04, 0x0a, 0x0e, + 0x0e, 0x0b, 0x07, 0x04, 0x05, 0x07, 0x04, 0x00, 0xfb, 0xf9, 0xf8, 0xf5, + 0xed, 0xe7, 0xe4, 0xe6, 0xec, 0xf3, 0xfc, 0x0b, 0x1d, 0x2b, 0x32, 0x30, + 0x28, 0x22, 0x1d, 0x1a, 0x1a, 0x1b, 0x1d, 0x1a, 0x12, 0x02, 0xef, 0xe3, + 0xdf, 0xe0, 0xe0, 0xde, 0xdb, 0xdc, 0xde, 0xe2, 0xe6, 0xeb, 0xef, 0xf3, + 0xf7, 0xfc, 0x06, 0x14, 0x22, 0x29, 0x22, 0x14, 0x03, 0xfb, 0xf9, 0xfc, + 0x01, 0x07, 0x0c, 0x0e, 0x0b, 0x07, 0x01, 0x01, 0x02, 0x01, 0xff, 0xf9, + 0xf4, 0xf3, 0xf2, 0xee, 0xe8, 0xe5, 0xe5, 0xea, 0xf1, 0xfb, 0x08, 0x1a, + 0x29, 0x32, 0x33, 0x2b, 0x23, 0x1c, 0x18, 0x19, 0x1c, 0x1d, 0x1e, 0x16, + 0x0a, 0xfa, 0xed, 0xe5, 0xe2, 0xe2, 0xe1, 0xdf, 0xdd, 0xde, 0xe2, 0xe6, + 0xea, 0xef, 0xf3, 0xf7, 0xfc, 0x04, 0x10, 0x1e, 0x27, 0x27, 0x1b, 0x0b, + 0xfe, 0xf9, 0xfa, 0xff, 0x07, 0x0c, 0x0f, 0x0e, 0x09, 0x04, 0x01, 0x01, + 0x01, 0x00, 0xfb, 0xf7, 0xf4, 0xf3, 0xf1, 0xed, 0xe9, 0xe7, 0xe8, 0xee, + 0xf9, 0x04, 0x15, 0x25, 0x31, 0x34, 0x2e, 0x24, 0x1d, 0x18, 0x17, 0x1a, + 0x1c, 0x1c, 0x18, 0x0d, 0xfe, 0xf0, 0xe7, 0xe3, 0xe1, 0xe0, 0xdf, 0xde, + 0xdf, 0xe0, 0xe4, 0xe8, 0xec, 0xf0, 0xf3, 0xf9, 0xff, 0x0c, 0x19, 0x26, + 0x28, 0x20, 0x12, 0x04, 0xfd, 0xfc, 0xfe, 0x04, 0x0b, 0x0f, 0x0f, 0x0b, + 0x05, 0x01, 0x01, 0x01, 0x00, 0xff, 0xfa, 0xf6, 0xf4, 0xf3, 0xef, 0xeb, + 0xe8, 0xe8, 0xeb, 0xf3, 0xff, 0x0f, 0x21, 0x2f, 0x33, 0x30, 0x29, 0x1e, + 0x19, 0x17, 0x19, 0x1b, 0x1c, 0x18, 0x10, 0x03, 0xf5, 0xe9, 0xe3, 0xe1, + 0xe0, 0xde, 0xdd, 0xde, 0xe0, 0xe1, 0xe6, 0xea, 0xed, 0xf0, 0xf5, 0xfb, + 0x07, 0x15, 0x21, 0x28, 0x26, 0x19, 0x0a, 0xff, 0xfc, 0xfe, 0x04, 0x0b, + 0x0f, 0x10, 0x0d, 0x07, 0x03, 0x00, 0x00, 0x01, 0xff, 0xfb, 0xf7, 0xf4, + 0xf2, 0xf1, 0xed, 0xeb, 0xe9, 0xea, 0xef, 0xfb, 0x09, 0x1a, 0x2b, 0x34, + 0x33, 0x2b, 0x21, 0x19, 0x16, 0x17, 0x1b, 0x1c, 0x1a, 0x11, 0x05, 0xf6, + 0xea, 0xe4, 0xe0, 0xdf, 0xde, 0xdd, 0xdd, 0xdf, 0xe2, 0xe5, 0xe8, 0xeb, + 0xed, 0xf1, 0xf8, 0x02, 0x10, 0x1d, 0x27, 0x28, 0x20, 0x11, 0x04, 0xfd, + 0xfd, 0x02, 0x0a, 0x0f, 0x11, 0x0e, 0x09, 0x04, 0xff, 0xfe, 0x00, 0x00, + 0xfd, 0xf9, 0xf5, 0xf4, 0xf3, 0xf0, 0xed, 0xea, 0xea, 0xee, 0xf7, 0x04, + 0x14, 0x26, 0x33, 0x35, 0x30, 0x25, 0x1a, 0x16, 0x16, 0x18, 0x1a, 0x19, + 0x12, 0x08, 0xfb, 0xee, 0xe5, 0xe0, 0xe0, 0xdf, 0xdd, 0xdd, 0xde, 0xe0, + 0xe3, 0xe7, 0xe9, 0xec, 0xee, 0xf4, 0xfd, 0x0b, 0x19, 0x26, 0x2b, 0x25, + 0x19, 0x09, 0x01, 0xfe, 0x02, 0x08, 0x0e, 0x11, 0x0f, 0x0b, 0x06, 0x00, + 0xff, 0xff, 0x00, 0xfe, 0xfc, 0xf8, 0xf5, 0xf3, 0xf2, 0xef, 0xec, 0xe9, + 0xec, 0xf3, 0xff, 0x0f, 0x21, 0x2e, 0x35, 0x32, 0x28, 0x1d, 0x17, 0x15, + 0x16, 0x19, 0x18, 0x15, 0x0c, 0xff, 0xf1, 0xe7, 0xe0, 0xdf, 0xdf, 0xdd, + 0xdd, 0xdd, 0xde, 0xe2, 0xe6, 0xe8, 0xe9, 0xec, 0xf1, 0xfa, 0x05, 0x15, + 0x21, 0x2a, 0x29, 0x20, 0x10, 0x05, 0x00, 0x02, 0x08, 0x0f, 0x11, 0x10, + 0x0c, 0x07, 0x01, 0xff, 0xfe, 0xff, 0xfe, 0xfc, 0xf9, 0xf5, 0xf5, 0xf3, + 0xf1, 0xed, 0xea, 0xea, 0xef, 0xfb, 0x09, 0x1b, 0x2b, 0x33, 0x33, 0x2c, + 0x21, 0x18, 0x15, 0x16, 0x18, 0x19, 0x14, 0x0d, 0x01, 0xf4, 0xe8, 0xe1, + 0xde, 0xdd, 0xde, 0xdd, 0xdd, 0xdf, 0xe2, 0xe4, 0xe7, 0xe9, 0xea, 0xee, + 0xf6, 0x01, 0x10, 0x1e, 0x28, 0x2a, 0x24, 0x16, 0x09, 0x02, 0x01, 0x05, + 0x0d, 0x11, 0x11, 0x0e, 0x08, 0x02, 0xfe, 0xfe, 0xfe, 0x00, 0xff, 0xfc, + 0xf8, 0xf5, 0xf5, 0xf3, 0xf0, 0xeb, 0xea, 0xed, 0xf7, 0x04, 0x16, 0x26, + 0x32, 0x35, 0x2f, 0x25, 0x1b, 0x15, 0x15, 0x17, 0x19, 0x16, 0x0e, 0x04, + 0xf7, 0xeb, 0xe2, 0xde, 0xdc, 0xdd, 0xdd, 0xdd, 0xdd, 0xdf, 0xe4, 0xe6, + 0xe7, 0xe9, 0xeb, 0xf0, 0xfb, 0x0a, 0x18, 0x25, 0x2b, 0x27, 0x1c, 0x10, + 0x06, 0x02, 0x05, 0x0d, 0x12, 0x12, 0x0f, 0x09, 0x04, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xfd, 0xfa, 0xf5, 0xf5, 0xf4, 0xf2, 0xee, 0xec, 0xec, 0xf1, + 0x00, 0x10, 0x21, 0x2f, 0x35, 0x31, 0x28, 0x1e, 0x17, 0x13, 0x16, 0x18, + 0x17, 0x0f, 0x06, 0xfa, 0xee, 0xe4, 0xdf, 0xdd, 0xdd, 0xde, 0xdd, 0xdd, + 0xdf, 0xe1, 0xe4, 0xe7, 0xe7, 0xe9, 0xec, 0xf7, 0x04, 0x14, 0x22, 0x29, + 0x2b, 0x22, 0x16, 0x09, 0x05, 0x05, 0x0b, 0x11, 0x14, 0x11, 0x0c, 0x05, + 0x01, 0xfe, 0xfe, 0xfe, 0x00, 0xff, 0xfc, 0xf8, 0xf6, 0xf4, 0xf4, 0xf1, + 0xed, 0xec, 0xf1, 0xfd, 0x0a, 0x1c, 0x2c, 0x33, 0x34, 0x2b, 0x20, 0x17, + 0x14, 0x15, 0x17, 0x18, 0x12, 0x08, 0xfb, 0xef, 0xe6, 0xdf, 0xdd, 0xdd, + 0xdc, 0xdd, 0xdd, 0xde, 0xe1, 0xe2, 0xe5, 0xe5, 0xe6, 0xe8, 0xf1, 0xff, + 0x0d, 0x1d, 0x28, 0x2a, 0x25, 0x1b, 0x10, 0x09, 0x07, 0x0b, 0x11, 0x15, + 0x12, 0x0d, 0x07, 0x01, 0xfd, 0xfc, 0xfe, 0x00, 0x00, 0xfe, 0xfa, 0xf6, + 0xf6, 0xf4, 0xf3, 0xef, 0xec, 0xee, 0xf8, 0x07, 0x16, 0x27, 0x32, 0x34, + 0x2e, 0x25, 0x19, 0x14, 0x13, 0x15, 0x18, 0x13, 0x0a, 0xfe, 0xf2, 0xe8, + 0xe1, 0xdd, 0xdc, 0xdd, 0xdc, 0xdd, 0xdf, 0xe0, 0xe1, 0xe3, 0xe5, 0xe4, + 0xe6, 0xec, 0xf9, 0x08, 0x17, 0x25, 0x2a, 0x28, 0x20, 0x15, 0x0c, 0x09, + 0x0b, 0x11, 0x16, 0x16, 0x10, 0x09, 0x02, 0xfe, 0xfc, 0xfd, 0xfe, 0xff, + 0xff, 0xfc, 0xf9, 0xf7, 0xf5, 0xf5, 0xf1, 0xee, 0xee, 0xf4, 0x00, 0x11, + 0x23, 0x30, 0x34, 0x30, 0x28, 0x1d, 0x14, 0x11, 0x14, 0x16, 0x16, 0x0d, + 0x02, 0xf5, 0xea, 0xe3, 0xdd, 0xdc, 0xdb, 0xdd, 0xdd, 0xdf, 0xdf, 0xe0, + 0xe1, 0xe4, 0xe3, 0xe3, 0xe8, 0xf3, 0x02, 0x13, 0x22, 0x2a, 0x2a, 0x25, + 0x1a, 0x0f, 0x0a, 0x0c, 0x10, 0x16, 0x17, 0x13, 0x0c, 0x05, 0xfe, 0xfd, + 0xfc, 0xfe, 0x00, 0x01, 0xfe, 0xfb, 0xf7, 0xf7, 0xf5, 0xf2, 0xef, 0xee, + 0xf2, 0xfd, 0x0c, 0x1e, 0x2d, 0x33, 0x32, 0x2a, 0x1f, 0x17, 0x12, 0x13, + 0x15, 0x15, 0x10, 0x05, 0xf8, 0xec, 0xe3, 0xdd, 0xdc, 0xdb, 0xda, 0xdd, + 0xdc, 0xde, 0xdf, 0xe1, 0xe1, 0xe2, 0xe3, 0xe6, 0xed, 0xfd, 0x0e, 0x1d, + 0x29, 0x2c, 0x27, 0x1d, 0x12, 0x0d, 0x0c, 0x10, 0x16, 0x18, 0x16, 0x0f, + 0x08, 0x01, 0xfd, 0xfc, 0xff, 0xff, 0xff, 0xfe, 0xfd, 0xfa, 0xf8, 0xf6, + 0xf4, 0xf1, 0xee, 0xf0, 0xf9, 0x08, 0x18, 0x2a, 0x34, 0x34, 0x2c, 0x22, + 0x18, 0x14, 0x11, 0x14, 0x14, 0x11, 0x08, 0xfb, 0xef, 0xe5, 0xdf, 0xdc, + 0xda, 0xda, 0xdc, 0xdc, 0xde, 0xde, 0xe0, 0xdf, 0xe0, 0xe0, 0xe2, 0xe8, + 0xf4, 0x06, 0x17, 0x26, 0x2c, 0x2a, 0x23, 0x18, 0x11, 0x0d, 0x0f, 0x16, + 0x1a, 0x18, 0x12, 0x0a, 0x02, 0xfe, 0xfd, 0xfc, 0xfe, 0xff, 0xff, 0xfe, + 0xfb, 0xf8, 0xf9, 0xf6, 0xf2, 0xf2, 0xef, 0xf4, 0x01, 0x13, 0x25, 0x31, + 0x34, 0x2f, 0x25, 0x1b, 0x12, 0x0f, 0x11, 0x14, 0x13, 0x0b, 0xff, 0xf3, + 0xe7, 0xe0, 0xdd, 0xdc, 0xda, 0xdb, 0xdd, 0xdd, 0xde, 0xde, 0xdf, 0xde, + 0xdf, 0xe0, 0xe4, 0xee, 0xfe, 0x11, 0x22, 0x2b, 0x2c, 0x26, 0x1e, 0x14, + 0x11, 0x10, 0x15, 0x1b, 0x1c, 0x17, 0x0e, 0x05, 0xff, 0xfd, 0xfd, 0xfc, + 0xff, 0xff, 0xfe, 0xfc, 0xf9, 0xf9, 0xf7, 0xf6, 0xf2, 0xf0, 0xf3, 0xfd, + 0x0d, 0x1f, 0x2d, 0x35, 0x31, 0x28, 0x1e, 0x15, 0x0f, 0x10, 0x12, 0x12, + 0x0b, 0x03, 0xf6, 0xeb, 0xe3, 0xdd, 0xda, 0xdb, 0xdb, 0xdb, 0xdb, 0xdc, + 0xdc, 0xdd, 0xdf, 0xdf, 0xde, 0xe0, 0xe8, 0xf9, 0x0a, 0x1d, 0x2a, 0x2e, + 0x2a, 0x21, 0x19, 0x12, 0x12, 0x15, 0x1a, 0x1d, 0x19, 0x11, 0x08, 0x01, + 0xfe, 0xfd, 0xfd, 0xff, 0x00, 0xff, 0xfd, 0xfb, 0xf9, 0xf9, 0xf6, 0xf3, + 0xf1, 0xf2, 0xfb, 0x0a, 0x19, 0x2a, 0x33, 0x33, 0x2b, 0x20, 0x16, 0x0f, + 0x0e, 0x10, 0x11, 0x0d, 0x07, 0xfb, 0xed, 0xe5, 0xdf, 0xdc, 0xdb, 0xdd, + 0xdd, 0xdc, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xe5, 0xf3, 0x03, + 0x15, 0x25, 0x2d, 0x2c, 0x25, 0x1c, 0x15, 0x12, 0x15, 0x19, 0x1c, 0x1c, + 0x15, 0x0c, 0x03, 0xff, 0xfe, 0xfd, 0x00, 0x01, 0x00, 0xff, 0xfc, 0xfa, + 0xfa, 0xf8, 0xf6, 0xf1, 0xf1, 0xf8, 0x04, 0x14, 0x26, 0x31, 0x35, 0x2e, + 0x23, 0x17, 0x0f, 0x0d, 0x10, 0x10, 0x0e, 0x08, 0xfe, 0xf2, 0xe8, 0xe1, + 0xdc, 0xdc, 0xdc, 0xdd, 0xdd, 0xdc, 0xdd, 0xdc, 0xdc, 0xdb, 0xda, 0xdb, + 0xe1, 0xed, 0xff, 0x0f, 0x20, 0x2b, 0x2d, 0x28, 0x1f, 0x17, 0x13, 0x15, + 0x1a, 0x1d, 0x1e, 0x18, 0x10, 0x07, 0xff, 0xfe, 0xfe, 0x00, 0x01, 0x01, + 0xff, 0xfd, 0xfa, 0xfa, 0xf9, 0xf6, 0xf3, 0xf2, 0xf6, 0xfe, 0x0e, 0x20, + 0x2e, 0x33, 0x30, 0x27, 0x1a, 0x11, 0x0c, 0x0d, 0x0f, 0x0f, 0x0a, 0x01, + 0xf3, 0xe9, 0xe2, 0xdd, 0xdc, 0xdc, 0xdd, 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, + 0xdb, 0xd9, 0xda, 0xdd, 0xe6, 0xf8, 0x09, 0x1c, 0x29, 0x2d, 0x2b, 0x22, + 0x19, 0x14, 0x15, 0x18, 0x1e, 0x20, 0x1b, 0x13, 0x0b, 0x03, 0xfe, 0xfe, + 0xfe, 0x01, 0x01, 0x01, 0xfe, 0xfb, 0xfb, 0xfb, 0xf7, 0xf4, 0xf2, 0xf4, + 0xfe, 0x0b, 0x1b, 0x2b, 0x34, 0x32, 0x2a, 0x1e, 0x12, 0x0c, 0x0b, 0x0c, + 0x0f, 0x0b, 0x05, 0xf7, 0xed, 0xe4, 0xdf, 0xdc, 0xde, 0xde, 0xdd, 0xdd, + 0xdc, 0xdb, 0xdb, 0xdb, 0xda, 0xd9, 0xda, 0xe2, 0xf0, 0x02, 0x15, 0x25, + 0x2d, 0x2c, 0x25, 0x1b, 0x15, 0x14, 0x17, 0x1c, 0x21, 0x1e, 0x17, 0x0f, + 0x06, 0x01, 0xfe, 0x00, 0x01, 0x02, 0x02, 0xff, 0xfc, 0xfb, 0xfa, 0xf8, + 0xf4, 0xf3, 0xf3, 0xfa, 0x05, 0x16, 0x28, 0x32, 0x33, 0x2e, 0x23, 0x16, + 0x0d, 0x0a, 0x0b, 0x0d, 0x0b, 0x04, 0xfc, 0xf1, 0xe6, 0xdf, 0xde, 0xde, + 0xdd, 0xdc, 0xdc, 0xdb, 0xda, 0xd9, 0xda, 0xd9, 0xd9, 0xd9, 0xde, 0xe9, + 0xfc, 0x0f, 0x1f, 0x2b, 0x2d, 0x28, 0x1f, 0x18, 0x14, 0x17, 0x1c, 0x21, + 0x20, 0x1b, 0x12, 0x0a, 0x03, 0x01, 0x00, 0x02, 0x02, 0x02, 0x01, 0xfc, + 0xfc, 0xfc, 0xf9, 0xf6, 0xf4, 0xf3, 0xf7, 0x02, 0x12, 0x22, 0x2f, 0x34, + 0x30, 0x25, 0x19, 0x10, 0x09, 0x09, 0x0b, 0x0b, 0x07, 0xff, 0xf3, 0xe9, + 0xe1, 0xde, 0xde, 0xdd, 0xdd, 0xdd, 0xdc, 0xda, 0xda, 0xda, 0xd9, 0xd9, + 0xd9, 0xdb, 0xe4, 0xf6, 0x08, 0x1a, 0x27, 0x2d, 0x29, 0x21, 0x19, 0x15, + 0x15, 0x19, 0x21, 0x23, 0x1d, 0x15, 0x0e, 0x07, 0x03, 0x02, 0x01, 0x02, + 0x02, 0x01, 0xff, 0xfc, 0xfb, 0xf9, 0xf8, 0xf5, 0xf4, 0xf6, 0xff, 0x0d, + 0x1e, 0x2c, 0x34, 0x33, 0x2a, 0x1c, 0x11, 0x09, 0x06, 0x0a, 0x0b, 0x08, + 0x01, 0xf6, 0xea, 0xe3, 0xe0, 0xde, 0xdd, 0xdd, 0xdd, 0xdb, 0xda, 0xd9, + 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xe0, 0xf0, 0x01, 0x14, 0x23, 0x2b, 0x29, + 0x22, 0x1c, 0x15, 0x14, 0x18, 0x1e, 0x22, 0x20, 0x1b, 0x11, 0x0a, 0x05, + 0x04, 0x03, 0x03, 0x04, 0x03, 0xff, 0xfd, 0xfb, 0xfa, 0xf8, 0xf7, 0xf5, + 0xf5, 0xfd, 0x09, 0x18, 0x29, 0x34, 0x33, 0x2b, 0x20, 0x13, 0x0a, 0x06, + 0x06, 0x09, 0x07, 0x03, 0xf9, 0xee, 0xe5, 0xe3, 0xdf, 0xde, 0xdf, 0xdf, + 0xdc, 0xda, 0xd9, 0xd8, 0xd8, 0xd7, 0xd7, 0xd8, 0xde, 0xea, 0xfd, 0x0e, + 0x1f, 0x29, 0x2a, 0x25, 0x1d, 0x17, 0x14, 0x16, 0x1d, 0x21, 0x23, 0x1e, + 0x16, 0x0e, 0x08, 0x05, 0x05, 0x05, 0x04, 0x03, 0x01, 0xfd, 0xfc, 0xfa, + 0xf8, 0xf7, 0xf5, 0xf5, 0xfb, 0x04, 0x14, 0x24, 0x32, 0x35, 0x2f, 0x23, + 0x17, 0x0a, 0x05, 0x05, 0x08, 0x08, 0x04, 0xfd, 0xf2, 0xe8, 0xe2, 0xe0, + 0xe0, 0xdf, 0xdf, 0xdb, 0xda, 0xd9, 0xd8, 0xd7, 0xd8, 0xd8, 0xd8, 0xdb, + 0xe5, 0xf6, 0x08, 0x1b, 0x27, 0x2a, 0x27, 0x1f, 0x17, 0x14, 0x15, 0x1a, + 0x1f, 0x22, 0x20, 0x19, 0x11, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x05, 0x02, + 0xfe, 0xfd, 0xf9, 0xf8, 0xf8, 0xf5, 0xf5, 0xfa, 0x01, 0x0f, 0x20, 0x2e, + 0x34, 0x30, 0x27, 0x19, 0x0d, 0x05, 0x03, 0x05, 0x07, 0x05, 0xff, 0xf3, + 0xe9, 0xe4, 0xe2, 0xe0, 0xe1, 0xe0, 0xdd, 0xdb, 0xd9, 0xd7, 0xd5, 0xd7, + 0xd7, 0xd7, 0xda, 0xe2, 0xf1, 0x02, 0x14, 0x23, 0x29, 0x26, 0x20, 0x18, + 0x13, 0x13, 0x18, 0x1d, 0x22, 0x22, 0x1d, 0x14, 0x0f, 0x0b, 0x08, 0x08, + 0x09, 0x07, 0x04, 0x00, 0xfe, 0xfa, 0xf8, 0xf6, 0xf5, 0xf6, 0xf9, 0xff, + 0x0c, 0x1b, 0x2b, 0x34, 0x34, 0x2a, 0x1d, 0x0f, 0x06, 0x02, 0x03, 0x06, + 0x05, 0x02, 0xf8, 0xee, 0xe6, 0xe1, 0xe0, 0xe1, 0xe0, 0xde, 0xdb, 0xda, + 0xd6, 0xd5, 0xd5, 0xd5, 0xd7, 0xd8, 0xde, 0xeb, 0xfe, 0x10, 0x20, 0x28, + 0x28, 0x21, 0x1a, 0x14, 0x12, 0x14, 0x1b, 0x21, 0x24, 0x20, 0x1a, 0x13, + 0x0e, 0x0b, 0x0a, 0x0a, 0x09, 0x06, 0x03, 0xff, 0xfa, 0xf8, 0xf7, 0xf6, + 0xf6, 0xf7, 0xfc, 0x06, 0x16, 0x27, 0x33, 0x34, 0x2d, 0x21, 0x12, 0x06, + 0x00, 0x00, 0x03, 0x06, 0x01, 0xfa, 0xf1, 0xe8, 0xe4, 0xe2, 0xe2, 0xe1, + 0xde, 0xdc, 0xd9, 0xd7, 0xd5, 0xd7, 0xd4, 0xd4, 0xd7, 0xdd, 0xe7, 0xf7, + 0x0a, 0x1a, 0x26, 0x27, 0x22, 0x1b, 0x14, 0x11, 0x12, 0x17, 0x1f, 0x23, + 0x22, 0x1d, 0x17, 0x11, 0x0e, 0x0d, 0x0c, 0x0b, 0x08, 0x03, 0xff, 0xfc, + 0xf9, 0xf6, 0xf5, 0xf5, 0xf6, 0xfa, 0x02, 0x12, 0x23, 0x31, 0x36, 0x32, + 0x24, 0x16, 0x08, 0x00, 0x00, 0x02, 0x04, 0x03, 0xfe, 0xf5, 0xeb, 0xe4, + 0xe3, 0xe3, 0xe2, 0xe0, 0xde, 0xda, 0xd8, 0xd7, 0xd5, 0xd5, 0xd5, 0xd7, + 0xda, 0xe2, 0xf1, 0x04, 0x16, 0x23, 0x29, 0x24, 0x1d, 0x14, 0x0f, 0x0f, + 0x14, 0x1b, 0x21, 0x22, 0x1f, 0x19, 0x13, 0x0f, 0x0f, 0x0e, 0x0c, 0x0a, + 0x06, 0x02, 0xfd, 0xfa, 0xf6, 0xf5, 0xf6, 0xf6, 0xfa, 0x00, 0x0c, 0x1f, + 0x2d, 0x36, 0x34, 0x29, 0x19, 0x0c, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, + 0xf8, 0xef, 0xe6, 0xe3, 0xe3, 0xe2, 0xe0, 0xdf, 0xdc, 0xd7, 0xd7, 0xd5, + 0xd4, 0xd4, 0xd7, 0xd8, 0xdf, 0xec, 0x00, 0x11, 0x21, 0x2a, 0x26, 0x1e, + 0x15, 0x0e, 0x0b, 0x0f, 0x18, 0x20, 0x23, 0x22, 0x1c, 0x16, 0x12, 0x10, + 0x10, 0x0f, 0x0c, 0x08, 0x03, 0x00, 0xfd, 0xf8, 0xf6, 0xf5, 0xf6, 0xf7, + 0xfe, 0x08, 0x1a, 0x2a, 0x35, 0x36, 0x2d, 0x1e, 0x0f, 0x03, 0xff, 0x00, + 0x00, 0x02, 0x00, 0xfb, 0xf1, 0xe9, 0xe5, 0xe4, 0xe3, 0xe2, 0xe0, 0xdd, + 0xd9, 0xd7, 0xd5, 0xd4, 0xd4, 0xd6, 0xd7, 0xdc, 0xe8, 0xfa, 0x0b, 0x1c, + 0x27, 0x27, 0x20, 0x16, 0x0d, 0x09, 0x0b, 0x14, 0x1c, 0x21, 0x22, 0x1e, + 0x18, 0x15, 0x13, 0x12, 0x10, 0x0f, 0x0b, 0x05, 0x00, 0xfd, 0xfa, 0xf6, + 0xf5, 0xf5, 0xf6, 0xfb, 0x04, 0x14, 0x25, 0x33, 0x37, 0x30, 0x24, 0x15, + 0x06, 0xff, 0xfd, 0x00, 0x01, 0x00, 0xfc, 0xf4, 0xeb, 0xe7, 0xe4, 0xe3, + 0xe3, 0xe2, 0xde, 0xda, 0xd6, 0xd5, 0xd3, 0xd3, 0xd3, 0xd6, 0xda, 0xe3, + 0xf3, 0x04, 0x17, 0x24, 0x28, 0x22, 0x1a, 0x10, 0x09, 0x0a, 0x10, 0x19, + 0x21, 0x23, 0x21, 0x1c, 0x17, 0x15, 0x15, 0x13, 0x12, 0x0f, 0x07, 0x01, + 0xfd, 0xfa, 0xf6, 0xf5, 0xf4, 0xf5, 0xf9, 0x01, 0x10, 0x22, 0x31, 0x37, + 0x34, 0x28, 0x18, 0x09, 0xff, 0xfc, 0xff, 0x00, 0x00, 0xfe, 0xf7, 0xef, + 0xe9, 0xe7, 0xe5, 0xe4, 0xe4, 0xe1, 0xdc, 0xd8, 0xd5, 0xd2, 0xd2, 0xd3, + 0xd4, 0xd7, 0xdf, 0xed, 0x00, 0x12, 0x21, 0x28, 0x25, 0x1c, 0x10, 0x08, + 0x06, 0x0b, 0x14, 0x1c, 0x22, 0x21, 0x1d, 0x18, 0x15, 0x14, 0x15, 0x14, + 0x10, 0x0a, 0x03, 0x00, 0xfb, 0xf8, 0xf6, 0xf5, 0xf4, 0xf7, 0x00, 0x0b, + 0x1b, 0x2c, 0x36, 0x35, 0x2b, 0x1b, 0x0b, 0x00, 0xfc, 0xfd, 0x00, 0x00, + 0x00, 0xfb, 0xf4, 0xef, 0xea, 0xe8, 0xe7, 0xe6, 0xe3, 0xe0, 0xdc, 0xd7, + 0xd4, 0xd3, 0xd3, 0xd3, 0xd7, 0xde, 0xe9, 0xfa, 0x0b, 0x1c, 0x26, 0x26, + 0x1e, 0x12, 0x09, 0x04, 0x07, 0x0f, 0x18, 0x20, 0x21, 0x1e, 0x1b, 0x17, + 0x15, 0x15, 0x15, 0x12, 0x0d, 0x06, 0x00, 0xfd, 0xfa, 0xf7, 0xf5, 0xf4, + 0xf5, 0xfc, 0x05, 0x15, 0x27, 0x33, 0x36, 0x2f, 0x21, 0x0f, 0x00, 0xfc, + 0xfb, 0xfe, 0x00, 0x00, 0xfe, 0xf8, 0xf0, 0xeb, 0xe9, 0xe8, 0xe7, 0xe4, + 0xe2, 0xde, 0xd9, 0xd7, 0xd4, 0xd4, 0xd5, 0xd7, 0xdc, 0xe5, 0xf5, 0x05, + 0x17, 0x23, 0x27, 0x22, 0x15, 0x0a, 0x03, 0x04, 0x0b, 0x14, 0x1d, 0x21, + 0x20, 0x1c, 0x19, 0x17, 0x17, 0x16, 0x14, 0x0f, 0x0a, 0x02, 0xfd, 0xfa, + 0xf7, 0xf5, 0xf4, 0xf5, 0xfa, 0x01, 0x10, 0x21, 0x30, 0x35, 0x32, 0x24, + 0x15, 0x04, 0xfd, 0xfa, 0xfb, 0x00, 0x00, 0xff, 0xf9, 0xf3, 0xef, 0xeb, + 0xea, 0xe9, 0xe6, 0xe3, 0xe0, 0xda, 0xd8, 0xd5, 0xd5, 0xd4, 0xd7, 0xdb, + 0xe2, 0xef, 0x00, 0x12, 0x20, 0x26, 0x22, 0x19, 0x0c, 0x04, 0x02, 0x06, + 0x10, 0x19, 0x1f, 0x1f, 0x1d, 0x1a, 0x17, 0x17, 0x17, 0x15, 0x11, 0x0b, + 0x03, 0xff, 0xfa, 0xf7, 0xf5, 0xf5, 0xf5, 0xf9, 0x00, 0x0c, 0x1c, 0x2d, + 0x34, 0x34, 0x2a, 0x19, 0x09, 0xfe, 0xf8, 0xf9, 0xfd, 0x00, 0x01, 0xfb, + 0xf6, 0xf0, 0xed, 0xec, 0xea, 0xe8, 0xe5, 0xe1, 0xdd, 0xd9, 0xd8, 0xd6, + 0xd6, 0xd5, 0xd8, 0xde, 0xea, 0xfc, 0x0c, 0x1b, 0x24, 0x24, 0x1b, 0x10, + 0x05, 0x00, 0x03, 0x0b, 0x15, 0x1d, 0x20, 0x1e, 0x1b, 0x19, 0x17, 0x17, + 0x15, 0x14, 0x0e, 0x07, 0xff, 0xfb, 0xf9, 0xf6, 0xf5, 0xf5, 0xf6, 0xfc, + 0x07, 0x17, 0x27, 0x32, 0x35, 0x2d, 0x1e, 0x0d, 0x01, 0xf8, 0xf6, 0xfb, + 0x00, 0x01, 0xfe, 0xf8, 0xf2, 0xf0, 0xee, 0xed, 0xeb, 0xe9, 0xe4, 0xdf, + 0xdb, 0xd9, 0xd7, 0xd5, 0xd7, 0xd8, 0xdd, 0xe6, 0xf6, 0x06, 0x16, 0x23, + 0x25, 0x1e, 0x12, 0x06, 0x00, 0x00, 0x07, 0x11, 0x19, 0x1f, 0x1f, 0x1c, + 0x1a, 0x19, 0x17, 0x16, 0x14, 0x10, 0x09, 0x02, 0xff, 0xfa, 0xf5, 0xf5, + 0xf5, 0xf6, 0xfa, 0x01, 0x11, 0x20, 0x2e, 0x34, 0x30, 0x23, 0x13, 0x03, + 0xf9, 0xf6, 0xf8, 0xfd, 0x01, 0xff, 0xfc, 0xf4, 0xf1, 0xf0, 0xee, 0xed, + 0xea, 0xe6, 0xe2, 0xde, 0xda, 0xd8, 0xd7, 0xd8, 0xd9, 0xdd, 0xe3, 0xf0, + 0x00, 0x11, 0x1f, 0x24, 0x20, 0x14, 0x09, 0x00, 0x00, 0x02, 0x0c, 0x16, + 0x1b, 0x1e, 0x1c, 0x1a, 0x1a, 0x19, 0x17, 0x14, 0x10, 0x0b, 0x04, 0xfe, + 0xfb, 0xf8, 0xf4, 0xf5, 0xf5, 0xf9, 0xff, 0x0d, 0x1b, 0x2a, 0x34, 0x32, + 0x27, 0x17, 0x07, 0xfc, 0xf5, 0xf7, 0xfb, 0x00, 0x02, 0xfe, 0xf8, 0xf3, + 0xf1, 0xf0, 0xee, 0xec, 0xe9, 0xe4, 0xdf, 0xdb, 0xd8, 0xd8, 0xd9, 0xda, + 0xdc, 0xe1, 0xec, 0xfd, 0x0b, 0x1b, 0x23, 0x22, 0x18, 0x0c, 0x00, 0xfe, + 0xff, 0x08, 0x11, 0x1a, 0x1e, 0x1c, 0x1b, 0x19, 0x19, 0x18, 0x17, 0x13, + 0x0c, 0x05, 0xff, 0xfc, 0xf8, 0xf5, 0xf4, 0xf5, 0xf9, 0xff, 0x0a, 0x17, + 0x27, 0x31, 0x33, 0x2b, 0x1c, 0x0b, 0xfe, 0xf6, 0xf5, 0xf8, 0xfe, 0x01, + 0xff, 0xf9, 0xf5, 0xf1, 0xf1, 0xf0, 0xee, 0xeb, 0xe6, 0xe1, 0xdf, 0xdb, + 0xda, 0xda, 0xdb, 0xdc, 0xe0, 0xea, 0xf8, 0x08, 0x16, 0x21, 0x22, 0x18, + 0x0e, 0x02, 0xfe, 0xff, 0x04, 0x0c, 0x16, 0x1d, 0x1e, 0x1c, 0x1a, 0x18, + 0x18, 0x16, 0x14, 0x0f, 0x09, 0x01, 0xfc, 0xf9, 0xf6, 0xf5, 0xf5, 0xf8, + 0xfe, 0x05, 0x11, 0x21, 0x2e, 0x34, 0x2e, 0x21, 0x10, 0x02, 0xf7, 0xf5, + 0xf7, 0xfc, 0x00, 0xff, 0xfa, 0xf7, 0xf4, 0xf1, 0xf1, 0xf0, 0xee, 0xe8, + 0xe3, 0xe0, 0xdc, 0xdc, 0xdb, 0xdb, 0xde, 0xe1, 0xe9, 0xf5, 0x03, 0x13, + 0x1e, 0x21, 0x1c, 0x11, 0x04, 0xfe, 0xfc, 0xff, 0x08, 0x12, 0x1a, 0x1b, + 0x1b, 0x1a, 0x19, 0x18, 0x18, 0x15, 0x10, 0x0a, 0x03, 0xfe, 0xf9, 0xf7, + 0xf6, 0xf6, 0xf6, 0xfc, 0x02, 0x0e, 0x1d, 0x2b, 0x31, 0x31, 0x27, 0x15, + 0x04, 0xf9, 0xf5, 0xf6, 0xfa, 0xfe, 0x00, 0xfe, 0xf9, 0xf4, 0xf1, 0xf1, + 0xf1, 0xef, 0xea, 0xe6, 0xe2, 0xde, 0xdc, 0xdd, 0xdd, 0xde, 0xe1, 0xe7, + 0xf1, 0x00, 0x0e, 0x1a, 0x21, 0x1d, 0x13, 0x05, 0xfd, 0xfa, 0xfc, 0x03, + 0x0f, 0x18, 0x1b, 0x1d, 0x1b, 0x19, 0x18, 0x18, 0x16, 0x12, 0x0d, 0x06, + 0xfe, 0xfa, 0xf8, 0xf6, 0xf6, 0xf6, 0xf9, 0xff, 0x09, 0x18, 0x26, 0x30, + 0x33, 0x2a, 0x1a, 0x08, 0xfc, 0xf3, 0xf3, 0xf8, 0xfe, 0x00, 0xff, 0xfb, + 0xf6, 0xf3, 0xf2, 0xf1, 0xef, 0xec, 0xe9, 0xe3, 0xe0, 0xdf, 0xde, 0xdf, + 0xe0, 0xe2, 0xe6, 0xee, 0xfc, 0x09, 0x17, 0x1e, 0x1f, 0x16, 0x09, 0x00, + 0xf9, 0xf9, 0xff, 0x0c, 0x15, 0x1a, 0x1d, 0x1d, 0x1a, 0x18, 0x18, 0x16, + 0x12, 0x0e, 0x07, 0x00, 0xfb, 0xf8, 0xf6, 0xf6, 0xf8, 0xf9, 0xfe, 0x06, + 0x15, 0x23, 0x2d, 0x32, 0x2d, 0x1f, 0x0d, 0xff, 0xf6, 0xf2, 0xf6, 0xfd, + 0x00, 0x00, 0xfd, 0xf9, 0xf4, 0xf3, 0xf2, 0xef, 0xec, 0xea, 0xe5, 0xe1, + 0xdf, 0xde, 0xdf, 0xe1, 0xe3, 0xe5, 0xec, 0xf8, 0x06, 0x13, 0x1d, 0x20, + 0x19, 0x0d, 0x01, 0xfa, 0xf7, 0xfd, 0x05, 0x11, 0x19, 0x1c, 0x1c, 0x1a, + 0x19, 0x19, 0x17, 0x13, 0x0f, 0x0a, 0x02, 0xfd, 0xf8, 0xf7, 0xf6, 0xf7, + 0xf9, 0xfc, 0x03, 0x10, 0x1d, 0x2a, 0x32, 0x2e, 0x23, 0x12, 0x03, 0xf7, + 0xf2, 0xf3, 0xfa, 0xff, 0x01, 0xfe, 0xfa, 0xf5, 0xf3, 0xf2, 0xf1, 0xed, + 0xec, 0xe8, 0xe4, 0xe1, 0xdf, 0xdf, 0xe1, 0xe5, 0xe6, 0xeb, 0xf4, 0x00, + 0x0e, 0x1b, 0x1f, 0x1c, 0x10, 0x02, 0xfa, 0xf6, 0xf8, 0x01, 0x0d, 0x17, + 0x1c, 0x1c, 0x1a, 0x19, 0x18, 0x18, 0x13, 0x11, 0x0b, 0x04, 0xfd, 0xfa, + 0xf7, 0xf5, 0xf6, 0xf9, 0xfb, 0xff, 0x0b, 0x19, 0x26, 0x30, 0x31, 0x27, + 0x17, 0x08, 0xfb, 0xf3, 0xf4, 0xf8, 0xfe, 0x01, 0x00, 0xfb, 0xf8, 0xf4, + 0xf2, 0xf1, 0xef, 0xee, 0xea, 0xe7, 0xe3, 0xe2, 0xe1, 0xe2, 0xe4, 0xe6, + 0xea, 0xf2, 0xfe, 0x09, 0x16, 0x1e, 0x1c, 0x13, 0x06, 0xfb, 0xf5, 0xf5, + 0xfd, 0x08, 0x13, 0x1c, 0x1c, 0x1c, 0x1a, 0x19, 0x17, 0x15, 0x11, 0x0c, + 0x05, 0xfe, 0xfa, 0xf8, 0xf6, 0xf6, 0xf9, 0xf9, 0xfe, 0x07, 0x14, 0x22, + 0x2f, 0x32, 0x2b, 0x1e, 0x0d, 0xfe, 0xf5, 0xf2, 0xf6, 0xfc, 0x01, 0x02, + 0xff, 0xf9, 0xf5, 0xf2, 0xf1, 0xf0, 0xee, 0xeb, 0xe8, 0xe5, 0xe3, 0xe3, + 0xe4, 0xe5, 0xe8, 0xea, 0xf0, 0xfb, 0x05, 0x12, 0x1c, 0x1c, 0x15, 0x08, + 0xfd, 0xf6, 0xf4, 0xf9, 0x02, 0x10, 0x1a, 0x1d, 0x1d, 0x1b, 0x19, 0x18, + 0x16, 0x13, 0x0e, 0x06, 0x00, 0xfc, 0xf7, 0xf5, 0xf6, 0xf7, 0xf9, 0xfd, + 0x03, 0x0f, 0x1e, 0x2b, 0x31, 0x2e, 0x22, 0x13, 0x03, 0xf7, 0xf2, 0xf4, + 0xf9, 0xff, 0x01, 0xff, 0xfb, 0xf8, 0xf4, 0xf2, 0xf1, 0xef, 0xec, 0xe9, + 0xe6, 0xe5, 0xe3, 0xe5, 0xe6, 0xe7, 0xeb, 0xf0, 0xf7, 0x00, 0x0d, 0x18, + 0x1c, 0x18, 0x0e, 0x00, 0xf7, 0xf2, 0xf4, 0xfd, 0x0b, 0x18, 0x1c, 0x1d, + 0x1c, 0x1b, 0x18, 0x17, 0x13, 0x10, 0x09, 0x02, 0xfd, 0xf9, 0xf5, 0xf5, + 0xf7, 0xf9, 0xfb, 0x00, 0x09, 0x18, 0x28, 0x31, 0x32, 0x28, 0x18, 0x06, + 0xf9, 0xf2, 0xf3, 0xf7, 0xfe, 0x01, 0x00, 0xfd, 0xfa, 0xf5, 0xf3, 0xf1, + 0xef, 0xee, 0xeb, 0xe9, 0xe6, 0xe5, 0xe5, 0xe6, 0xe8, 0xe9, 0xed, 0xf5, + 0x00, 0x0a, 0x15, 0x1b, 0x19, 0x0f, 0x03, 0xf7, 0xf1, 0xf3, 0xfa, 0x06, + 0x12, 0x1b, 0x1e, 0x1d, 0x1b, 0x18, 0x16, 0x16, 0x11, 0x0a, 0x03, 0xfd, + 0xf9, 0xf5, 0xf5, 0xf6, 0xf8, 0xfa, 0xfe, 0x06, 0x13, 0x22, 0x2e, 0x32, + 0x2a, 0x1e, 0x0a, 0xfe, 0xf3, 0xf2, 0xf6, 0xfd, 0x01, 0x01, 0xff, 0xfc, + 0xf6, 0xf4, 0xf2, 0xef, 0xee, 0xec, 0xe9, 0xe7, 0xe6, 0xe6, 0xe7, 0xe9, + 0xea, 0xed, 0xf2, 0xfc, 0x05, 0x12, 0x1a, 0x1a, 0x13, 0x07, 0xfa, 0xf2, + 0xf0, 0xf7, 0x00, 0x0f, 0x19, 0x1d, 0x1e, 0x1c, 0x1a, 0x17, 0x14, 0x11, + 0x0b, 0x06, 0xff, 0xf9, 0xf6, 0xf5, 0xf6, 0xf6, 0xfa, 0xfd, 0x03, 0x0f, + 0x1d, 0x29, 0x30, 0x2e, 0x23, 0x12, 0x01, 0xf5, 0xf1, 0xf4, 0xfb, 0x01, + 0x02, 0x01, 0xfc, 0xf8, 0xf5, 0xf2, 0xf0, 0xef, 0xec, 0xea, 0xe7, 0xe6, + 0xe7, 0xe8, 0xe8, 0xea, 0xec, 0xf1, 0xf7, 0x03, 0x0e, 0x18, 0x1c, 0x16, + 0x0a, 0xfe, 0xf4, 0xf0, 0xf3, 0xfc, 0x09, 0x16, 0x1b, 0x20, 0x1c, 0x1b, + 0x17, 0x15, 0x12, 0x0e, 0x07, 0x01, 0xfb, 0xf7, 0xf5, 0xf6, 0xf6, 0xf9, + 0xfc, 0x01, 0x0a, 0x18, 0x25, 0x2f, 0x31, 0x28, 0x17, 0x06, 0xf9, 0xf2, + 0xf3, 0xf8, 0xff, 0x02, 0x02, 0xfe, 0xfa, 0xf5, 0xf3, 0xf1, 0xf0, 0xee, + 0xec, 0xe8, 0xe7, 0xe7, 0xe8, 0xea, 0xec, 0xec, 0xef, 0xf5, 0x00, 0x0a, + 0x15, 0x1b, 0x18, 0x0d, 0x01, 0xf6, 0xf0, 0xf1, 0xf9, 0x06, 0x12, 0x1b, + 0x1e, 0x1e, 0x1b, 0x1a, 0x16, 0x11, 0x0d, 0x09, 0x02, 0xfd, 0xf9, 0xf5, + 0xf5, 0xf6, 0xf9, 0xfb, 0xff, 0x07, 0x13, 0x21, 0x2e, 0x31, 0x2b, 0x1e, + 0x0d, 0xfd, 0xf2, 0xf2, 0xf6, 0xfd, 0x02, 0x03, 0x00, 0xfb, 0xf6, 0xf3, + 0xf2, 0xf0, 0xee, 0xec, 0xea, 0xe8, 0xe7, 0xe8, 0xeb, 0xed, 0xed, 0xef, + 0xf4, 0xfd, 0x08, 0x12, 0x19, 0x1a, 0x11, 0x05, 0xfa, 0xf1, 0xef, 0xf6, + 0x00, 0x0e, 0x19, 0x1e, 0x1f, 0x1c, 0x1a, 0x17, 0x12, 0x0f, 0x09, 0x04, + 0xfd, 0xfa, 0xf6, 0xf5, 0xf6, 0xf9, 0xfb, 0xff, 0x04, 0x10, 0x1d, 0x29, + 0x30, 0x2e, 0x22, 0x12, 0x02, 0xf4, 0xf0, 0xf4, 0xfa, 0x00, 0x04, 0x02, + 0xfd, 0xf8, 0xf5, 0xf3, 0xf2, 0xf0, 0xed, 0xea, 0xe8, 0xe8, 0xe9, 0xea, + 0xec, 0xed, 0xee, 0xf2, 0xfb, 0x02, 0x0e, 0x18, 0x1b, 0x15, 0x0a, 0xfe, + 0xf3, 0xf0, 0xf3, 0xfb, 0x09, 0x15, 0x1c, 0x1e, 0x1c, 0x1a, 0x17, 0x14, + 0x0f, 0x0b, 0x05, 0xfe, 0xfa, 0xf6, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0x02, + 0x0c, 0x17, 0x25, 0x2e, 0x2f, 0x26, 0x18, 0x05, 0xf9, 0xf2, 0xf3, 0xf7, + 0xff, 0x02, 0x03, 0xfe, 0xf9, 0xf5, 0xf3, 0xf2, 0xf2, 0xef, 0xeb, 0xea, + 0xe9, 0xe9, 0xeb, 0xed, 0xee, 0xf0, 0xf2, 0xf7, 0x00, 0x0b, 0x15, 0x1a, + 0x17, 0x0d, 0x01, 0xf4, 0xf0, 0xf1, 0xfb, 0x05, 0x13, 0x1a, 0x1d, 0x1d, + 0x1b, 0x19, 0x15, 0x11, 0x0c, 0x06, 0x00, 0xfd, 0xf7, 0xf4, 0xf4, 0xf6, + 0xf9, 0xfb, 0xff, 0x07, 0x12, 0x21, 0x2c, 0x30, 0x29, 0x1d, 0x0b, 0xfc, + 0xf3, 0xf2, 0xf5, 0xfc, 0x02, 0x03, 0x00, 0xfc, 0xf7, 0xf3, 0xf2, 0xf2, + 0xf0, 0xed, 0xea, 0xe9, 0xe9, 0xea, 0xee, 0xef, 0xf0, 0xf2, 0xf6, 0xfd, + 0x06, 0x12, 0x19, 0x1a, 0x12, 0x06, 0xf9, 0xf2, 0xf0, 0xf6, 0x00, 0x0d, + 0x18, 0x1d, 0x1d, 0x1c, 0x19, 0x15, 0x11, 0x0e, 0x08, 0x02, 0xfd, 0xf8, + 0xf5, 0xf4, 0xf5, 0xf7, 0xfa, 0xff, 0x04, 0x0e, 0x1b, 0x28, 0x2f, 0x2d, + 0x23, 0x10, 0x02, 0xf5, 0xf1, 0xf5, 0xf9, 0x01, 0x04, 0x01, 0xfd, 0xf7, + 0xf3, 0xf2, 0xf2, 0xf0, 0xed, 0xeb, 0xea, 0xe9, 0xeb, 0xed, 0xf0, 0xf1, + 0xf2, 0xf4, 0xfb, 0x03, 0x0f, 0x18, 0x19, 0x15, 0x09, 0xfc, 0xf3, 0xef, + 0xf2, 0xfc, 0x09, 0x15, 0x1c, 0x1d, 0x1c, 0x19, 0x16, 0x13, 0x0f, 0x0a, + 0x03, 0xfd, 0xf9, 0xf5, 0xf4, 0xf4, 0xf6, 0xf9, 0xfd, 0x01, 0x0a, 0x17, + 0x24, 0x2e, 0x2e, 0x26, 0x17, 0x05, 0xf9, 0xf3, 0xf2, 0xf8, 0xff, 0x03, + 0x02, 0xfe, 0xf9, 0xf5, 0xf3, 0xf3, 0xf2, 0xef, 0xed, 0xeb, 0xea, 0xea, + 0xed, 0xf0, 0xf1, 0xf2, 0xf4, 0xf9, 0x00, 0x0a, 0x14, 0x1a, 0x18, 0x0e, + 0x01, 0xf5, 0xf0, 0xf1, 0xf9, 0x05, 0x12, 0x1a, 0x1d, 0x1c, 0x1a, 0x17, + 0x14, 0x10, 0x0c, 0x05, 0xff, 0xfb, 0xf7, 0xf5, 0xf5, 0xf5, 0xf6, 0xfb, + 0xff, 0x06, 0x12, 0x20, 0x2a, 0x2f, 0x2a, 0x1c, 0x0c, 0xff, 0xf5, 0xf3, + 0xf6, 0xfc, 0x02, 0x03, 0x00, 0xfb, 0xf6, 0xf2, 0xf2, 0xf2, 0xf1, 0xee, + 0xec, 0xeb, 0xea, 0xee, 0xef, 0xf2, 0xf4, 0xf4, 0xf6, 0xfe, 0x06, 0x12, + 0x19, 0x1a, 0x11, 0x05, 0xf8, 0xf0, 0xef, 0xf5, 0x01, 0x0e, 0x17, 0x1d, + 0x1e, 0x1a, 0x17, 0x15, 0x11, 0x0e, 0x07, 0x01, 0xfc, 0xf8, 0xf4, 0xf4, + 0xf4, 0xf6, 0xf8, 0xfd, 0x02, 0x0d, 0x1b, 0x27, 0x2f, 0x2d, 0x22, 0x12, + 0x04, 0xf7, 0xf3, 0xf4, 0xf9, 0xff, 0x03, 0x02, 0xfd, 0xf6, 0xf3, 0xf2, + 0xf1, 0xf1, 0xf0, 0xee, 0xed, 0xec, 0xed, 0xef, 0xf1, 0xf4, 0xf4, 0xf6, + 0xfc, 0x02, 0x0d, 0x16, 0x1a, 0x14, 0x08, 0xfc, 0xf3, 0xf0, 0xf2, 0xfc, + 0x0a, 0x15, 0x1b, 0x1e, 0x1b, 0x18, 0x15, 0x12, 0x0e, 0x09, 0x03, 0xfc, + 0xf7, 0xf4, 0xf4, 0xf4, 0xf6, 0xf6, 0xfb, 0xff, 0x09, 0x16, 0x23, 0x2d, + 0x2f, 0x27, 0x17, 0x08, 0xfb, 0xf5, 0xf4, 0xf8, 0xfe, 0x01, 0x02, 0xfd, + 0xf8, 0xf4, 0xf2, 0xf1, 0xf1, 0xf1, 0xf0, 0xed, 0xee, 0xee, 0xef, 0xf1, + 0xf3, 0xf4, 0xf5, 0xfa, 0x01, 0x0a, 0x13, 0x1a, 0x17, 0x0d, 0x02, 0xf5, + 0xf0, 0xf1, 0xf9, 0x05, 0x12, 0x19, 0x1d, 0x1b, 0x19, 0x15, 0x13, 0x10, + 0x0b, 0x05, 0xff, 0xf9, 0xf7, 0xf4, 0xf3, 0xf4, 0xf6, 0xf8, 0xfd, 0x04, + 0x0f, 0x1e, 0x2a, 0x2f, 0x2a, 0x1d, 0x0c, 0xff, 0xf5, 0xf4, 0xf8, 0xfb, + 0x01, 0x02, 0xff, 0xfa, 0xf4, 0xf2, 0xf1, 0xf1, 0xf1, 0xef, 0xed, 0xed, + 0xed, 0xef, 0xf2, 0xf4, 0xf4, 0xf4, 0xf8, 0xfe, 0x06, 0x11, 0x19, 0x1a, + 0x12, 0x07, 0xfa, 0xf2, 0xf0, 0xf7, 0x00, 0x0d, 0x18, 0x1c, 0x1d, 0x1a, + 0x18, 0x13, 0x11, 0x0e, 0x07, 0x01, 0xfc, 0xf7, 0xf4, 0xf4, 0xf4, 0xf5, + 0xf7, 0xfb, 0x00, 0x0b, 0x18, 0x26, 0x2e, 0x2c, 0x22, 0x12, 0x03, 0xf8, + 0xf5, 0xf6, 0xfa, 0x00, 0x01, 0x00, 0xfb, 0xf7, 0xf3, 0xf2, 0xf2, 0xf1, + 0xef, 0xee, 0xee, 0xed, 0xf0, 0xf1, 0xf3, 0xf5, 0xf5, 0xf7, 0xfa, 0x03, + 0x0d, 0x16, 0x1b, 0x15, 0x0c, 0xff, 0xf4, 0xf0, 0xf3, 0xfc, 0x09, 0x16, + 0x1c, 0x1d, 0x1b, 0x18, 0x15, 0x12, 0x0f, 0x09, 0x04, 0xfc, 0xf8, 0xf3, + 0xf3, 0xf2, 0xf3, 0xf5, 0xf7, 0xfd, 0x04, 0x12, 0x22, 0x2c, 0x2e, 0x28, + 0x1a, 0x09, 0xfd, 0xf6, 0xf5, 0xfa, 0xff, 0x02, 0x00, 0xfe, 0xf8, 0xf3, + 0xf2, 0xf0, 0xf1, 0xef, 0xee, 0xee, 0xed, 0xee, 0xf0, 0xf3, 0xf4, 0xf5, + 0xf6, 0xf9, 0x01, 0x09, 0x14, 0x19, 0x18, 0x0f, 0x04, 0xf8, 0xf1, 0xf2, + 0xf9, 0x04, 0x11, 0x19, 0x1c, 0x1b, 0x19, 0x15, 0x12, 0x0f, 0x0b, 0x05, + 0xfe, 0xfa, 0xf6, 0xf2, 0xf3, 0xf3, 0xf4, 0xf6, 0xfa, 0x00, 0x0d, 0x1b, + 0x28, 0x2f, 0x2b, 0x1e, 0x0f, 0x01, 0xf8, 0xf6, 0xf8, 0xfe, 0x02, 0x03, + 0xff, 0xfb, 0xf5, 0xf1, 0xf1, 0xf0, 0xf0, 0xee, 0xef, 0xee, 0xee, 0xf1, + 0xf2, 0xf4, 0xf5, 0xf6, 0xf8, 0xfe, 0x06, 0x11, 0x19, 0x1a, 0x13, 0x08, + 0xfb, 0xf2, 0xf0, 0xf7, 0x00, 0x0c, 0x17, 0x1b, 0x1d, 0x1a, 0x17, 0x14, + 0x11, 0x0d, 0x07, 0x01, 0xfc, 0xf7, 0xf3, 0xf3, 0xf2, 0xf2, 0xf4, 0xf7, + 0xfe, 0x07, 0x15, 0x24, 0x2d, 0x2d, 0x24, 0x14, 0x06, 0xfa, 0xf6, 0xf8, + 0xfd, 0x01, 0x02, 0x00, 0xfb, 0xf6, 0xf2, 0xf1, 0xf1, 0xf0, 0xef, 0xee, + 0xee, 0xef, 0xf1, 0xf2, 0xf4, 0xf5, 0xf5, 0xf7, 0xfb, 0x03, 0x0e, 0x17, + 0x1b, 0x16, 0x0c, 0xff, 0xf5, 0xf0, 0xf4, 0xfb, 0x09, 0x14, 0x19, 0x1c, + 0x1b, 0x18, 0x14, 0x12, 0x0e, 0x0a, 0x05, 0xfd, 0xf9, 0xf4, 0xf2, 0xf2, + 0xf1, 0xf2, 0xf5, 0xfa, 0x01, 0x0f, 0x1d, 0x29, 0x2e, 0x28, 0x1b, 0x0b, + 0xff, 0xf8, 0xf7, 0xfc, 0x00, 0x03, 0x02, 0xfd, 0xf7, 0xf3, 0xf2, 0xf0, + 0xf0, 0xf0, 0xee, 0xee, 0xee, 0xf0, 0xf3, 0xf4, 0xf5, 0xf6, 0xf6, 0xfa, + 0x02, 0x0a, 0x15, 0x1b, 0x19, 0x10, 0x05, 0xf8, 0xf2, 0xf2, 0xf8, 0x03, + 0x0f, 0x17, 0x1c, 0x1c, 0x19, 0x15, 0x13, 0x0f, 0x0b, 0x06, 0x00, 0xfb, + 0xf6, 0xf3, 0xf1, 0xf0, 0xf1, 0xf2, 0xf6, 0xff, 0x09, 0x18, 0x26, 0x2d, + 0x2b, 0x20, 0x10, 0x04, 0xf9, 0xf7, 0xfb, 0xff, 0x03, 0x03, 0x00, 0xfa, + 0xf4, 0xf3, 0xf1, 0xf0, 0xf0, 0xee, 0xee, 0xee, 0xef, 0xf0, 0xf3, 0xf4, + 0xf5, 0xf5, 0xf7, 0xfe, 0x06, 0x11, 0x19, 0x1b, 0x15, 0x09, 0xfc, 0xf3, + 0xf0, 0xf6, 0xff, 0x0b, 0x16, 0x1a, 0x1b, 0x19, 0x17, 0x14, 0x11, 0x0e, + 0x09, 0x02, 0xfc, 0xf7, 0xf4, 0xf1, 0xf0, 0xf0, 0xf1, 0xf3, 0xfb, 0x03, + 0x11, 0x20, 0x2a, 0x2c, 0x24, 0x17, 0x08, 0xfc, 0xf8, 0xfa, 0xff, 0x02, + 0x04, 0x02, 0xfc, 0xf7, 0xf4, 0xf1, 0xf1, 0xf0, 0xef, 0xee, 0xed, 0xef, + 0xf0, 0xf1, 0xf3, 0xf5, 0xf5, 0xf7, 0xfb, 0x03, 0x0e, 0x18, 0x1c, 0x18, + 0x0c, 0x01, 0xf6, 0xf0, 0xf3, 0xfb, 0x07, 0x13, 0x19, 0x1c, 0x19, 0x18, + 0x15, 0x13, 0x0f, 0x0b, 0x06, 0xff, 0xfa, 0xf6, 0xf2, 0xf2, 0xf0, 0xf0, + 0xf1, 0xf5, 0xff, 0x0c, 0x1b, 0x28, 0x2c, 0x27, 0x1b, 0x0c, 0x00, 0xf9, + 0xf9, 0xfd, 0x01, 0x04, 0x03, 0xfe, 0xf9, 0xf4, 0xf3, 0xf1, 0xf0, 0xf0, + 0xee, 0xee, 0xef, 0xef, 0xf3, 0xf4, 0xf5, 0xf5, 0xf6, 0xf9, 0x01, 0x0a, + 0x15, 0x1c, 0x1b, 0x13, 0x06, 0xf9, 0xf2, 0xf2, 0xf7, 0x02, 0x0e, 0x17, + 0x1c, 0x1a, 0x19, 0x16, 0x13, 0x10, 0x0d, 0x07, 0x02, 0xfc, 0xf7, 0xf3, + 0xf2, 0xf0, 0xf0, 0xf0, 0xf5, 0xfc, 0x05, 0x14, 0x23, 0x2a, 0x29, 0x20, + 0x11, 0x04, 0xfb, 0xfa, 0xfc, 0x01, 0x04, 0x05, 0x01, 0xfb, 0xf6, 0xf2, + 0xf0, 0xf2, 0xf0, 0xed, 0xed, 0xed, 0xef, 0xf0, 0xf3, 0xf4, 0xf5, 0xf5, + 0xf7, 0xfd, 0x06, 0x12, 0x1b, 0x1d, 0x16, 0x0b, 0xfd, 0xf5, 0xf1, 0xf6, + 0xfe, 0x0b, 0x14, 0x19, 0x1a, 0x18, 0x16, 0x14, 0x11, 0x0f, 0x0a, 0x04, + 0xfe, 0xfa, 0xf6, 0xf3, 0xf2, 0xf0, 0xef, 0xf2, 0xf8, 0x01, 0x0f, 0x1d, + 0x27, 0x29, 0x24, 0x17, 0x08, 0xfe, 0xf9, 0xfa, 0xff, 0x03, 0x05, 0x04, + 0xfd, 0xf7, 0xf3, 0xf1, 0xf0, 0xf0, 0xef, 0xee, 0xed, 0xec, 0xee, 0xf1, + 0xf3, 0xf4, 0xf4, 0xf7, 0xfc, 0x03, 0x0f, 0x1a, 0x1d, 0x19, 0x0f, 0x03, + 0xf8, 0xf3, 0xf4, 0xfa, 0x07, 0x12, 0x17, 0x19, 0x19, 0x17, 0x14, 0x13, + 0x10, 0x0c, 0x06, 0x01, 0xfd, 0xf8, 0xf4, 0xf3, 0xf1, 0xf0, 0xf0, 0xf4, + 0xfd, 0x09, 0x18, 0x24, 0x29, 0x26, 0x1a, 0x0d, 0x01, 0xfa, 0xfa, 0xfe, + 0x03, 0x05, 0x06, 0x00, 0xfa, 0xf6, 0xf3, 0xf2, 0xf1, 0xef, 0xef, 0xec, + 0xec, 0xed, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf9, 0x01, 0x0c, 0x16, 0x1d, + 0x1d, 0x14, 0x09, 0xfb, 0xf4, 0xf4, 0xf7, 0x01, 0x0d, 0x15, 0x18, 0x18, + 0x16, 0x14, 0x13, 0x11, 0x0d, 0x08, 0x04, 0xff, 0xfa, 0xf7, 0xf4, 0xf2, + 0xef, 0xf0, 0xf1, 0xf8, 0x03, 0x11, 0x1f, 0x27, 0x26, 0x1d, 0x10, 0x04, + 0xfc, 0xfa, 0xfd, 0x02, 0x06, 0x06, 0x03, 0xfd, 0xf7, 0xf3, 0xf2, 0xf0, + 0xef, 0xee, 0xec, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf3, 0xf5, 0xf7, 0xfe, + 0x07, 0x14, 0x1c, 0x1f, 0x1a, 0x0e, 0x00, 0xf8, 0xf2, 0xf5, 0xff, 0x0a, + 0x13, 0x16, 0x18, 0x16, 0x14, 0x13, 0x12, 0x0f, 0x0c, 0x07, 0x00, 0xfd, + 0xf9, 0xf4, 0xf2, 0xf0, 0xee, 0xef, 0xf4, 0xfe, 0x0c, 0x1a, 0x25, 0x26, + 0x21, 0x14, 0x08, 0xfe, 0xf9, 0xfc, 0x01, 0x04, 0x06, 0x06, 0x01, 0xf9, + 0xf6, 0xf2, 0xf1, 0xf0, 0xef, 0xed, 0xeb, 0xec, 0xed, 0xee, 0xf0, 0xf2, + 0xf3, 0xf5, 0xfc, 0x03, 0x10, 0x1a, 0x20, 0x1d, 0x13, 0x06, 0xf9, 0xf5, + 0xf6, 0xfc, 0x07, 0x10, 0x16, 0x17, 0x16, 0x14, 0x12, 0x11, 0x10, 0x0e, + 0x09, 0x03, 0xff, 0xfa, 0xf8, 0xf4, 0xf2, 0xef, 0xee, 0xf2, 0xfb, 0x06, + 0x14, 0x20, 0x25, 0x21, 0x17, 0x0c, 0x00, 0xfb, 0xfa, 0x00, 0x04, 0x06, + 0x06, 0x03, 0xfc, 0xf8, 0xf3, 0xf2, 0xf0, 0xee, 0xed, 0xeb, 0xeb, 0xec, + 0xed, 0xef, 0xf0, 0xf1, 0xf3, 0xfa, 0x01, 0x0c, 0x17, 0x20, 0x20, 0x18, + 0x0c, 0xff, 0xf6, 0xf4, 0xf9, 0x03, 0x0c, 0x14, 0x16, 0x16, 0x14, 0x12, + 0x11, 0x10, 0x0e, 0x0b, 0x04, 0x00, 0xfd, 0xf9, 0xf6, 0xf4, 0xf0, 0xee, + 0xef, 0xf7, 0x01, 0x0f, 0x1c, 0x24, 0x23, 0x1a, 0x0f, 0x03, 0xfb, 0xf9, + 0xfe, 0x03, 0x08, 0x08, 0x06, 0x00, 0xfb, 0xf5, 0xf1, 0xf1, 0xf0, 0xee, + 0xec, 0xeb, 0xeb, 0xec, 0xee, 0xf0, 0xf0, 0xf2, 0xf6, 0xff, 0x08, 0x14, + 0x1f, 0x21, 0x1c, 0x11, 0x04, 0xf9, 0xf5, 0xf6, 0xfe, 0x09, 0x13, 0x16, + 0x16, 0x14, 0x12, 0x11, 0x10, 0x0f, 0x0c, 0x07, 0x01, 0xfe, 0xfa, 0xf7, + 0xf3, 0xf1, 0xef, 0xef, 0xf2, 0xfc, 0x08, 0x16, 0x21, 0x24, 0x1e, 0x13, + 0x07, 0xfd, 0xfa, 0xfd, 0x02, 0x07, 0x09, 0x06, 0x01, 0xfd, 0xf8, 0xf3, + 0xf1, 0xef, 0xee, 0xec, 0xea, 0xea, 0xea, 0xed, 0xef, 0xf0, 0xf1, 0xf5, + 0xfc, 0x04, 0x11, 0x1c, 0x21, 0x1f, 0x15, 0x09, 0xfc, 0xf5, 0xf6, 0xfb, + 0x07, 0x11, 0x15, 0x16, 0x15, 0x14, 0x11, 0x10, 0x0f, 0x0d, 0x09, 0x03, + 0x00, 0xfb, 0xf8, 0xf5, 0xf3, 0xf0, 0xee, 0xf1, 0xf9, 0x05, 0x11, 0x1c, + 0x22, 0x1f, 0x17, 0x0a, 0xff, 0xf9, 0xfb, 0x01, 0x06, 0x0a, 0x09, 0x04, + 0xff, 0xfc, 0xf6, 0xf2, 0xef, 0xed, 0xeb, 0xe9, 0xe8, 0xe8, 0xeb, 0xed, + 0xef, 0xf0, 0xf3, 0xf9, 0x00, 0x0d, 0x19, 0x20, 0x21, 0x1a, 0x0e, 0x01, + 0xf8, 0xf5, 0xf8, 0x02, 0x0e, 0x14, 0x17, 0x16, 0x15, 0x12, 0x10, 0x0f, + 0x0f, 0x0b, 0x06, 0x00, 0xfb, 0xf8, 0xf7, 0xf3, 0xf1, 0xef, 0xef, 0xf5, + 0xff, 0x0d, 0x1a, 0x21, 0x21, 0x19, 0x0d, 0x02, 0xfb, 0xfa, 0xfe, 0x06, + 0x0a, 0x0a, 0x06, 0x02, 0xfd, 0xf8, 0xf3, 0xf0, 0xed, 0xeb, 0xe9, 0xe7, + 0xe7, 0xe9, 0xeb, 0xed, 0xee, 0xf2, 0xf7, 0xff, 0x0a, 0x16, 0x1f, 0x23, + 0x1e, 0x13, 0x05, 0xfb, 0xf5, 0xf6, 0xff, 0x0b, 0x12, 0x16, 0x17, 0x15, + 0x13, 0x11, 0x10, 0x0f, 0x0c, 0x08, 0x03, 0xff, 0xfa, 0xf7, 0xf5, 0xf2, + 0xf1, 0xef, 0xf3, 0xfb, 0x07, 0x14, 0x1e, 0x21, 0x1b, 0x10, 0x05, 0xfd, + 0xf9, 0xfd, 0x05, 0x0a, 0x0b, 0x09, 0x03, 0xff, 0xfa, 0xf6, 0xf2, 0xef, + 0xec, 0xe9, 0xe7, 0xe6, 0xe7, 0xea, 0xec, 0xef, 0xf1, 0xf4, 0xfc, 0x04, + 0x12, 0x1d, 0x23, 0x20, 0x17, 0x0b, 0xfe, 0xf7, 0xf6, 0xfc, 0x07, 0x11, + 0x15, 0x17, 0x15, 0x13, 0x11, 0x10, 0x0e, 0x0c, 0x09, 0x04, 0x00, 0xfc, + 0xf9, 0xf6, 0xf4, 0xf3, 0xf0, 0xf1, 0xf7, 0x02, 0x0f, 0x1b, 0x22, 0x1e, + 0x16, 0x09, 0xff, 0xf9, 0xfa, 0x01, 0x08, 0x0b, 0x0b, 0x05, 0x00, 0xfa, + 0xf7, 0xf3, 0xee, 0xec, 0xea, 0xe7, 0xe6, 0xe7, 0xe9, 0xec, 0xef, 0xf1, + 0xf3, 0xf9, 0x00, 0x0e, 0x1b, 0x22, 0x23, 0x1b, 0x0e, 0x02, 0xfa, 0xf7, + 0xf9, 0x03, 0x0d, 0x14, 0x17, 0x16, 0x13, 0x11, 0x10, 0x0f, 0x0d, 0x0a, + 0x05, 0x01, 0xfd, 0xf9, 0xf6, 0xf4, 0xf2, 0xf1, 0xf0, 0xf5, 0xfe, 0x0b, + 0x17, 0x20, 0x1f, 0x19, 0x0d, 0x01, 0xfa, 0xf9, 0xff, 0x06, 0x0b, 0x0c, + 0x07, 0x00, 0xfb, 0xf7, 0xf3, 0xf0, 0xec, 0xe9, 0xe7, 0xe6, 0xe7, 0xe8, + 0xeb, 0xed, 0xf0, 0xf2, 0xf6, 0x00, 0x0a, 0x16, 0x21, 0x24, 0x1e, 0x11, + 0x07, 0xfd, 0xf7, 0xf7, 0x00, 0x0b, 0x13, 0x17, 0x17, 0x15, 0x12, 0x10, + 0x0f, 0x0e, 0x0b, 0x07, 0x02, 0x00, 0xfc, 0xf8, 0xf5, 0xf3, 0xf1, 0xf1, + 0xf4, 0xfa, 0x06, 0x13, 0x1f, 0x21, 0x1c, 0x11, 0x04, 0xfc, 0xfa, 0xfd, + 0x04, 0x09, 0x0c, 0x0a, 0x03, 0xfc, 0xf7, 0xf3, 0xf0, 0xee, 0xea, 0xe8, + 0xe6, 0xe6, 0xe8, 0xea, 0xed, 0xef, 0xf1, 0xf4, 0xfc, 0x05, 0x12, 0x1e, + 0x24, 0x21, 0x17, 0x0a, 0xfe, 0xf9, 0xf8, 0xfe, 0x08, 0x10, 0x17, 0x17, + 0x15, 0x13, 0x11, 0x0f, 0x0d, 0x0c, 0x08, 0x03, 0x00, 0xfd, 0xf9, 0xf6, + 0xf5, 0xf2, 0xf1, 0xf3, 0xf8, 0x02, 0x0e, 0x1b, 0x21, 0x1e, 0x15, 0x09, + 0xfe, 0xfa, 0xfa, 0x01, 0x08, 0x0c, 0x0c, 0x05, 0xfe, 0xf7, 0xf3, 0xf0, + 0xee, 0xeb, 0xe8, 0xe6, 0xe6, 0xe6, 0xe9, 0xeb, 0xee, 0xf1, 0xf3, 0xf9, + 0x00, 0x0d, 0x1b, 0x24, 0x23, 0x1b, 0x0e, 0x02, 0xfb, 0xf8, 0xfb, 0x04, + 0x0e, 0x15, 0x19, 0x16, 0x13, 0x11, 0x0f, 0x0d, 0x0c, 0x08, 0x04, 0x01, + 0xfe, 0xfa, 0xf7, 0xf5, 0xf3, 0xf1, 0xf2, 0xf6, 0xfe, 0x0a, 0x18, 0x20, + 0x1f, 0x18, 0x0e, 0x01, 0xfb, 0xfa, 0xff, 0x07, 0x0c, 0x0e, 0x08, 0x02, + 0xfa, 0xf3, 0xf0, 0xee, 0xea, 0xe8, 0xe6, 0xe5, 0xe5, 0xe8, 0xeb, 0xee, + 0xf0, 0xf3, 0xf8, 0xff, 0x09, 0x17, 0x21, 0x24, 0x1f, 0x13, 0x06, 0xfc, + 0xf9, 0xfa, 0x02, 0x0b, 0x12, 0x17, 0x17, 0x15, 0x12, 0x0f, 0x0d, 0x0c, + 0x0a, 0x06, 0x02, 0xff, 0xfc, 0xf9, 0xf6, 0xf4, 0xf2, 0xf2, 0xf4, 0xfb, + 0x06, 0x12, 0x1e, 0x21, 0x1e, 0x12, 0x06, 0xfd, 0xfa, 0xfd, 0x05, 0x0b, + 0x0d, 0x09, 0x03, 0xfc, 0xf5, 0xef, 0xec, 0xea, 0xe7, 0xe4, 0xe4, 0xe5, + 0xe5, 0xea, 0xed, 0xef, 0xf2, 0xf6, 0xfd, 0x04, 0x12, 0x1d, 0x23, 0x21, + 0x18, 0x0a, 0xff, 0xf9, 0xf9, 0xfe, 0x0a, 0x11, 0x16, 0x18, 0x16, 0x12, + 0x11, 0x0e, 0x0c, 0x0b, 0x07, 0x03, 0xff, 0xfc, 0xfa, 0xf8, 0xf5, 0xf2, + 0xf2, 0xf3, 0xf8, 0x03, 0x0f, 0x1a, 0x20, 0x20, 0x17, 0x0c, 0x01, 0xfb, + 0xfc, 0x02, 0x09, 0x0c, 0x0b, 0x05, 0xfe, 0xf6, 0xf0, 0xec, 0xea, 0xe7, + 0xe4, 0xe4, 0xe3, 0xe5, 0xe9, 0xec, 0xef, 0xf2, 0xf5, 0xfa, 0x01, 0x0d, + 0x1a, 0x21, 0x22, 0x1c, 0x10, 0x02, 0xfc, 0xf8, 0xfd, 0x06, 0x0f, 0x16, + 0x18, 0x17, 0x13, 0x10, 0x0d, 0x0b, 0x09, 0x08, 0x04, 0x00, 0xfd, 0xfb, + 0xf9, 0xf7, 0xf4, 0xf2, 0xf2, 0xf6, 0xff, 0x0b, 0x16, 0x1f, 0x20, 0x1a, + 0x0f, 0x03, 0xfe, 0xfc, 0x00, 0x09, 0x0d, 0x0d, 0x08, 0x00, 0xf8, 0xf0, + 0xeb, 0xe9, 0xe7, 0xe6, 0xe4, 0xe2, 0xe4, 0xe7, 0xeb, 0xed, 0xf1, 0xf4, + 0xf8, 0x00, 0x0a, 0x16, 0x21, 0x24, 0x20, 0x14, 0x07, 0xff, 0xf9, 0xfa, + 0x02, 0x0d, 0x15, 0x19, 0x18, 0x14, 0x11, 0x0d, 0x0b, 0x09, 0x09, 0x06, + 0x02, 0xff, 0xfc, 0xf9, 0xf8, 0xf5, 0xf4, 0xf3, 0xf4, 0xfb, 0x07, 0x12, + 0x1d, 0x20, 0x1d, 0x12, 0x06, 0xff, 0xfc, 0x00, 0x06, 0x0c, 0x0d, 0x0a, + 0x03, 0xf9, 0xf1, 0xec, 0xe8, 0xe6, 0xe5, 0xe2, 0xe1, 0xe2, 0xe4, 0xe9, + 0xee, 0xf1, 0xf2, 0xf6, 0xfd, 0x05, 0x13, 0x1d, 0x24, 0x22, 0x19, 0x0b, + 0x00, 0xfb, 0xfb, 0x01, 0x0c, 0x14, 0x18, 0x18, 0x15, 0x11, 0x0d, 0x0b, + 0x0a, 0x08, 0x06, 0x04, 0x00, 0xfe, 0xfc, 0xf9, 0xf7, 0xf6, 0xf3, 0xf4, + 0xf9, 0x03, 0x0f, 0x1a, 0x20, 0x1f, 0x17, 0x0a, 0x01, 0xfc, 0xff, 0x05, + 0x0b, 0x0e, 0x0d, 0x05, 0xfc, 0xf3, 0xeb, 0xe7, 0xe5, 0xe4, 0xe2, 0xe1, + 0xe1, 0xe3, 0xe7, 0xeb, 0xef, 0xf2, 0xf5, 0xfa, 0x01, 0x0f, 0x1a, 0x23, + 0x23, 0x1c, 0x10, 0x05, 0xfc, 0xf9, 0xff, 0x09, 0x12, 0x18, 0x1a, 0x15, + 0x12, 0x0e, 0x0b, 0x09, 0x08, 0x07, 0x05, 0x02, 0xff, 0xfd, 0xfa, 0xf8, + 0xf6, 0xf3, 0xf3, 0xf6, 0xff, 0x0a, 0x17, 0x1e, 0x21, 0x1b, 0x10, 0x04, + 0xfd, 0xfe, 0x04, 0x0a, 0x0f, 0x0e, 0x08, 0x00, 0xf6, 0xec, 0xe6, 0xe4, + 0xe2, 0xe2, 0xe0, 0xe0, 0xe2, 0xe5, 0xe9, 0xee, 0xf1, 0xf4, 0xf8, 0x00, + 0x0a, 0x17, 0x22, 0x26, 0x20, 0x15, 0x09, 0xff, 0xfa, 0xfe, 0x06, 0x0f, + 0x17, 0x1a, 0x18, 0x13, 0x0f, 0x0b, 0x09, 0x07, 0x06, 0x05, 0x02, 0xff, + 0xfe, 0xfc, 0xf9, 0xf7, 0xf4, 0xf3, 0xf4, 0xfb, 0x06, 0x13, 0x1f, 0x21, + 0x1e, 0x14, 0x07, 0xff, 0xff, 0x01, 0x09, 0x0e, 0x10, 0x0b, 0x03, 0xf9, + 0xef, 0xe7, 0xe3, 0xe1, 0xe0, 0xde, 0xdf, 0xe1, 0xe4, 0xe8, 0xec, 0xf0, + 0xf3, 0xf6, 0xfd, 0x05, 0x12, 0x1e, 0x25, 0x23, 0x1b, 0x0f, 0x03, 0xfc, + 0xfc, 0x04, 0x0c, 0x16, 0x1a, 0x1a, 0x15, 0x10, 0x0b, 0x08, 0x08, 0x07, + 0x06, 0x02, 0x00, 0xfe, 0xfd, 0xfa, 0xf8, 0xf6, 0xf3, 0xf4, 0xf9, 0x03, + 0x0e, 0x1c, 0x21, 0x21, 0x19, 0x0c, 0x02, 0xfe, 0x01, 0x07, 0x0e, 0x11, + 0x0e, 0x05, 0xfb, 0xf0, 0xe9, 0xe4, 0xe1, 0xde, 0xdc, 0xdd, 0xdf, 0xe2, + 0xe5, 0xeb, 0xee, 0xf3, 0xf5, 0xfb, 0x01, 0x0f, 0x1c, 0x24, 0x25, 0x1f, + 0x13, 0x07, 0xff, 0xfc, 0x00, 0x0a, 0x14, 0x1a, 0x1a, 0x17, 0x11, 0x0b, + 0x08, 0x08, 0x07, 0x07, 0x04, 0x02, 0xff, 0xfe, 0xfc, 0xf9, 0xf8, 0xf5, + 0xf4, 0xf6, 0xfe, 0x0a, 0x17, 0x1f, 0x21, 0x1b, 0x11, 0x07, 0x00, 0x00, + 0x05, 0x0d, 0x11, 0x10, 0x08, 0xff, 0xf3, 0xea, 0xe3, 0xde, 0xdd, 0xdb, + 0xdc, 0xdd, 0xe0, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf9, 0x00, 0x0a, 0x18, + 0x22, 0x26, 0x23, 0x18, 0x0b, 0x01, 0xfd, 0xff, 0x08, 0x11, 0x18, 0x1a, + 0x18, 0x12, 0x0c, 0x09, 0x07, 0x07, 0x05, 0x04, 0x02, 0xff, 0xff, 0xfd, + 0xfb, 0xf9, 0xf6, 0xf4, 0xf5, 0xfc, 0x06, 0x13, 0x1e, 0x21, 0x1e, 0x14, + 0x0a, 0x03, 0x00, 0x04, 0x0b, 0x10, 0x11, 0x0b, 0x03, 0xf8, 0xec, 0xe3, + 0xde, 0xdc, 0xda, 0xda, 0xda, 0xdd, 0xe1, 0xe6, 0xeb, 0xf0, 0xf3, 0xf6, + 0xfd, 0x05, 0x13, 0x1f, 0x26, 0x26, 0x1c, 0x10, 0x04, 0xfe, 0xff, 0x05, + 0x0f, 0x17, 0x1a, 0x19, 0x13, 0x0f, 0x09, 0x07, 0x06, 0x05, 0x05, 0x03, + 0xff, 0xfe, 0xfd, 0xfc, 0xf9, 0xf8, 0xf5, 0xf6, 0xf9, 0x03, 0x0e, 0x1b, + 0x21, 0x21, 0x1a, 0x0f, 0x06, 0x01, 0x03, 0x0b, 0x10, 0x11, 0x0e, 0x04, + 0xf9, 0xee, 0xe5, 0xdf, 0xdb, 0xda, 0xd9, 0xda, 0xdb, 0xdf, 0xe4, 0xea, + 0xee, 0xf3, 0xf6, 0xfb, 0x02, 0x0f, 0x1a, 0x25, 0x26, 0x20, 0x15, 0x09, + 0x00, 0xfe, 0x03, 0x0b, 0x16, 0x1a, 0x1b, 0x16, 0x0f, 0x0a, 0x07, 0x06, + 0x05, 0x05, 0x03, 0x01, 0x00, 0xfe, 0xfc, 0xfb, 0xfa, 0xf6, 0xf5, 0xf8, + 0x00, 0x0a, 0x18, 0x20, 0x23, 0x1d, 0x12, 0x08, 0x03, 0x03, 0x08, 0x0f, + 0x12, 0x11, 0x09, 0xfc, 0xef, 0xe6, 0xe0, 0xdd, 0xda, 0xd7, 0xd8, 0xd9, + 0xdd, 0xe1, 0xe7, 0xeb, 0xf0, 0xf4, 0xf9, 0xff, 0x09, 0x17, 0x22, 0x29, + 0x23, 0x19, 0x0d, 0x04, 0x01, 0x04, 0x0a, 0x12, 0x19, 0x1a, 0x17, 0x10, + 0x0b, 0x07, 0x06, 0x06, 0x05, 0x04, 0x02, 0x02, 0x00, 0xfe, 0xfc, 0xfa, + 0xf8, 0xf6, 0xf7, 0xfc, 0x05, 0x12, 0x1e, 0x23, 0x1e, 0x15, 0x0d, 0x04, + 0x04, 0x07, 0x0e, 0x12, 0x12, 0x0c, 0x01, 0xf4, 0xe8, 0xe0, 0xdc, 0xda, + 0xd8, 0xd6, 0xd7, 0xdb, 0xdf, 0xe3, 0xea, 0xee, 0xf2, 0xf6, 0xfc, 0x03, + 0x12, 0x1f, 0x27, 0x27, 0x1f, 0x12, 0x08, 0x00, 0x03, 0x09, 0x11, 0x18, + 0x1b, 0x19, 0x13, 0x0b, 0x07, 0x05, 0x06, 0x06, 0x04, 0x02, 0x01, 0x00, + 0xff, 0xfe, 0xfc, 0xf9, 0xf7, 0xf7, 0xf9, 0x03, 0x0e, 0x19, 0x21, 0x22, + 0x1b, 0x10, 0x08, 0x04, 0x06, 0x0c, 0x11, 0x14, 0x10, 0x04, 0xf7, 0xea, + 0xe1, 0xdc, 0xd9, 0xd7, 0xd5, 0xd6, 0xd8, 0xdd, 0xe2, 0xe8, 0xec, 0xf0, + 0xf3, 0xf9, 0x00, 0x0c, 0x1b, 0x25, 0x28, 0x23, 0x19, 0x0c, 0x04, 0x02, + 0x07, 0x0e, 0x17, 0x1b, 0x1a, 0x15, 0x0e, 0x08, 0x04, 0x04, 0x05, 0x04, + 0x03, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xfb, 0xf8, 0xf7, 0xf9, 0xff, 0x09, + 0x15, 0x1f, 0x24, 0x1e, 0x15, 0x0b, 0x04, 0x06, 0x0b, 0x10, 0x13, 0x10, + 0x08, 0xfc, 0xee, 0xe3, 0xdc, 0xd9, 0xd7, 0xd6, 0xd4, 0xd7, 0xda, 0xdf, + 0xe4, 0xea, 0xed, 0xf1, 0xf5, 0xfd, 0x08, 0x15, 0x23, 0x2a, 0x28, 0x1f, + 0x12, 0x08, 0x03, 0x06, 0x0d, 0x15, 0x19, 0x1a, 0x16, 0x0f, 0x08, 0x04, + 0x03, 0x04, 0x04, 0x02, 0x03, 0x01, 0x00, 0xff, 0x00, 0xfc, 0xf9, 0xf6, + 0xf7, 0xfd, 0x05, 0x12, 0x1c, 0x22, 0x21, 0x18, 0x0e, 0x07, 0x06, 0x09, + 0x0e, 0x12, 0x11, 0x0c, 0x01, 0xf4, 0xe6, 0xdd, 0xd8, 0xd7, 0xd6, 0xd5, + 0xd6, 0xd8, 0xdc, 0xe3, 0xe8, 0xec, 0xee, 0xf3, 0xf9, 0x04, 0x10, 0x1e, + 0x27, 0x2a, 0x24, 0x19, 0x0c, 0x05, 0x06, 0x0c, 0x14, 0x1a, 0x1a, 0x17, + 0x11, 0x0a, 0x04, 0x02, 0x03, 0x03, 0x02, 0x02, 0x01, 0x00, 0x01, 0x00, + 0xfe, 0xfa, 0xf7, 0xf6, 0xf9, 0x03, 0x0e, 0x19, 0x21, 0x22, 0x1c, 0x13, + 0x0a, 0x06, 0x08, 0x0e, 0x12, 0x12, 0x0d, 0x04, 0xf7, 0xea, 0xdf, 0xd9, + 0xd6, 0xd4, 0xd5, 0xd5, 0xd7, 0xdb, 0xe1, 0xe5, 0xea, 0xed, 0xf1, 0xf5, + 0xff, 0x0c, 0x1a, 0x25, 0x2a, 0x27, 0x1e, 0x11, 0x08, 0x06, 0x0a, 0x10, + 0x18, 0x1a, 0x19, 0x13, 0x0b, 0x05, 0x02, 0x02, 0x02, 0x04, 0x04, 0x02, + 0x01, 0x00, 0x02, 0x00, 0xfc, 0xf7, 0xf5, 0xf7, 0xff, 0x09, 0x15, 0x1f, + 0x24, 0x21, 0x17, 0x0e, 0x09, 0x08, 0x0d, 0x11, 0x13, 0x0f, 0x06, 0xfb, + 0xed, 0xe1, 0xda, 0xd6, 0xd4, 0xd4, 0xd4, 0xd5, 0xd8, 0xde, 0xe4, 0xe8, + 0xeb, 0xee, 0xf2, 0xf9, 0x06, 0x15, 0x22, 0x2a, 0x2a, 0x22, 0x17, 0x0e, + 0x08, 0x09, 0x10, 0x17, 0x1b, 0x1a, 0x15, 0x0c, 0x06, 0x03, 0x02, 0x02, + 0x02, 0x03, 0x03, 0x02, 0x00, 0x01, 0x01, 0xff, 0xfb, 0xf7, 0xf6, 0xfb, + 0x06, 0x12, 0x1d, 0x24, 0x22, 0x1a, 0x11, 0x0a, 0x08, 0x0a, 0x11, 0x13, + 0x11, 0x09, 0xfe, 0xf1, 0xe4, 0xdb, 0xd7, 0xd4, 0xd4, 0xd4, 0xd5, 0xd7, + 0xdb, 0xe0, 0xe5, 0xea, 0xec, 0xf0, 0xf4, 0x02, 0x0e, 0x1d, 0x28, 0x2a, + 0x27, 0x1c, 0x12, 0x09, 0x0a, 0x0e, 0x15, 0x1a, 0x1c, 0x17, 0x0f, 0x07, + 0x03, 0x01, 0x01, 0x02, 0x03, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0xfc, + 0xf8, 0xf6, 0xfb, 0x04, 0x0e, 0x1a, 0x23, 0x24, 0x1f, 0x15, 0x0c, 0x08, + 0x0b, 0x10, 0x12, 0x14, 0x0c, 0x01, 0xf3, 0xe7, 0xdd, 0xd8, 0xd5, 0xd5, + 0xd4, 0xd5, 0xd7, 0xd9, 0xdf, 0xe3, 0xe7, 0xe9, 0xeb, 0xef, 0xfa, 0x09, + 0x17, 0x24, 0x2a, 0x28, 0x20, 0x16, 0x0e, 0x0c, 0x0e, 0x15, 0x1b, 0x1d, + 0x18, 0x11, 0x08, 0x03, 0xff, 0xfe, 0x01, 0x03, 0x04, 0x03, 0x03, 0x00, + 0x02, 0x00, 0xfe, 0xf9, 0xf6, 0xf7, 0x00, 0x0b, 0x17, 0x21, 0x26, 0x22, + 0x1a, 0x11, 0x0a, 0x0a, 0x0e, 0x11, 0x14, 0x0e, 0x04, 0xf7, 0xea, 0xdf, + 0xd9, 0xd5, 0xd4, 0xd4, 0xd4, 0xd7, 0xd9, 0xdc, 0xe1, 0xe4, 0xe8, 0xe9, + 0xec, 0xf4, 0x03, 0x12, 0x20, 0x29, 0x2a, 0x24, 0x1b, 0x12, 0x0d, 0x0e, + 0x13, 0x1a, 0x1d, 0x1c, 0x14, 0x0b, 0x03, 0xff, 0xfe, 0x00, 0x00, 0x03, + 0x04, 0x03, 0x02, 0x01, 0x01, 0x00, 0xfb, 0xf8, 0xf7, 0xfc, 0x06, 0x14, + 0x20, 0x26, 0x24, 0x1d, 0x14, 0x0c, 0x09, 0x0b, 0x10, 0x13, 0x12, 0x08, + 0xfb, 0xed, 0xe2, 0xdb, 0xd6, 0xd4, 0xd3, 0xd4, 0xd6, 0xd9, 0xdb, 0xde, + 0xe1, 0xe5, 0xe6, 0xe9, 0xef, 0xfc, 0x0b, 0x1c, 0x27, 0x2b, 0x28, 0x21, + 0x16, 0x10, 0x0e, 0x14, 0x19, 0x1e, 0x1d, 0x17, 0x0e, 0x05, 0xff, 0xfe, + 0xfe, 0x00, 0x02, 0x05, 0x04, 0x03, 0x01, 0x02, 0x00, 0xfc, 0xf8, 0xf7, + 0xfa, 0x04, 0x10, 0x1c, 0x25, 0x26, 0x20, 0x17, 0x0e, 0x0a, 0x0b, 0x0f, + 0x13, 0x12, 0x0c, 0xff, 0xf1, 0xe5, 0xdb, 0xd6, 0xd5, 0xd3, 0xd2, 0xd5, + 0xd6, 0xda, 0xdc, 0xe0, 0xe2, 0xe4, 0xe7, 0xec, 0xf5, 0x06, 0x16, 0x23, + 0x2b, 0x2b, 0x24, 0x1a, 0x12, 0x10, 0x12, 0x18, 0x1e, 0x1e, 0x1a, 0x12, + 0x08, 0x02, 0xff, 0xfe, 0x00, 0x01, 0x03, 0x04, 0x04, 0x03, 0x02, 0x01, + 0xfe, 0xfa, 0xf6, 0xf8, 0xff, 0x0b, 0x19, 0x25, 0x2a, 0x25, 0x1a, 0x12, + 0x0b, 0x0c, 0x0e, 0x12, 0x12, 0x0e, 0x03, 0xf6, 0xe8, 0xde, 0xd9, 0xd5, + 0xd3, 0xd2, 0xd5, 0xd6, 0xd9, 0xdb, 0xdf, 0xe0, 0xe2, 0xe4, 0xe7, 0xef, + 0xfd, 0x0e, 0x1e, 0x2a, 0x2c, 0x27, 0x1f, 0x17, 0x12, 0x12, 0x17, 0x1e, + 0x21, 0x1d, 0x15, 0x0b, 0x03, 0xff, 0xfe, 0xfe, 0x00, 0x02, 0x03, 0x04, + 0x02, 0x01, 0x02, 0xff, 0xfb, 0xf9, 0xf6, 0xfb, 0x06, 0x15, 0x21, 0x29, + 0x28, 0x20, 0x15, 0x0e, 0x09, 0x0a, 0x0f, 0x12, 0x10, 0x06, 0xfa, 0xec, + 0xe0, 0xda, 0xd6, 0xd4, 0xd3, 0xd4, 0xd6, 0xd8, 0xda, 0xdd, 0xdf, 0xe0, + 0xe2, 0xe4, 0xe9, 0xf6, 0x06, 0x18, 0x27, 0x2c, 0x2a, 0x23, 0x1c, 0x15, + 0x14, 0x17, 0x1d, 0x21, 0x21, 0x1a, 0x0f, 0x05, 0xff, 0xfe, 0xfe, 0xfe, + 0x02, 0x02, 0x03, 0x03, 0x01, 0x02, 0x00, 0xfe, 0xf9, 0xf7, 0xfa, 0x03, + 0x10, 0x1e, 0x27, 0x2a, 0x23, 0x19, 0x11, 0x0b, 0x0a, 0x0e, 0x10, 0x10, + 0x08, 0xfe, 0xf0, 0xe4, 0xdd, 0xd7, 0xd4, 0xd5, 0xd5, 0xd5, 0xd6, 0xd9, + 0xda, 0xdd, 0xe0, 0xe0, 0xe1, 0xe4, 0xef, 0x00, 0x11, 0x22, 0x2c, 0x2c, + 0x28, 0x1f, 0x19, 0x15, 0x17, 0x1d, 0x21, 0x21, 0x1c, 0x12, 0x08, 0x01, + 0xfe, 0xfe, 0xfe, 0x01, 0x03, 0x03, 0x03, 0x02, 0x01, 0x02, 0xfe, 0xfa, + 0xf8, 0xf8, 0x01, 0x0d, 0x1a, 0x26, 0x2b, 0x28, 0x1d, 0x14, 0x0c, 0x09, + 0x0c, 0x0f, 0x0f, 0x0b, 0x02, 0xf5, 0xe7, 0xdf, 0xda, 0xd6, 0xd5, 0xd6, + 0xd6, 0xd7, 0xd8, 0xda, 0xdb, 0xdc, 0xdd, 0xdf, 0xe1, 0xea, 0xfa, 0x0a, + 0x1b, 0x29, 0x2d, 0x2a, 0x23, 0x1b, 0x16, 0x17, 0x1b, 0x20, 0x21, 0x1f, + 0x16, 0x0c, 0x03, 0xff, 0xfe, 0xfe, 0x01, 0x03, 0x04, 0x04, 0x02, 0x01, + 0x02, 0x00, 0xfd, 0xf8, 0xf7, 0xfd, 0x07, 0x16, 0x24, 0x2b, 0x2b, 0x21, + 0x16, 0x0e, 0x09, 0x0b, 0x0e, 0x0f, 0x0d, 0x04, 0xf9, 0xed, 0xe2, 0xdc, + 0xd7, 0xd6, 0xd6, 0xd7, 0xd7, 0xd8, 0xda, 0xdb, 0xdb, 0xdc, 0xdc, 0xde, + 0xe5, 0xf3, 0x05, 0x15, 0x24, 0x2c, 0x2c, 0x26, 0x1e, 0x18, 0x16, 0x1a, + 0x20, 0x22, 0x21, 0x1a, 0x10, 0x07, 0xff, 0xfe, 0xfe, 0x01, 0x03, 0x04, + 0x04, 0x02, 0x01, 0x01, 0x00, 0xfd, 0xf8, 0xf7, 0xfb, 0x02, 0x11, 0x20, + 0x29, 0x2b, 0x25, 0x1c, 0x10, 0x0a, 0x09, 0x0c, 0x0e, 0x0d, 0x07, 0xfd, + 0xef, 0xe4, 0xdd, 0xd8, 0xd7, 0xd6, 0xd8, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, + 0xdb, 0xda, 0xdd, 0xe0, 0xeb, 0xfd, 0x0f, 0x20, 0x2b, 0x2c, 0x2a, 0x20, + 0x19, 0x16, 0x1a, 0x1e, 0x23, 0x23, 0x1d, 0x13, 0x0b, 0x03, 0xfe, 0xfe, + 0xff, 0x02, 0x04, 0x05, 0x03, 0x00, 0x01, 0x02, 0xfe, 0xf9, 0xf6, 0xf8, + 0x02, 0x0d, 0x1c, 0x28, 0x2e, 0x2a, 0x20, 0x15, 0x0b, 0x08, 0x0a, 0x0c, + 0x0e, 0x09, 0x01, 0xf3, 0xe8, 0xe0, 0xda, 0xd8, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xda, 0xdb, 0xda, 0xdb, 0xdd, 0xe6, 0xf5, 0x07, 0x1a, 0x28, + 0x2e, 0x2b, 0x24, 0x1b, 0x16, 0x17, 0x1c, 0x22, 0x25, 0x20, 0x18, 0x0f, + 0x06, 0x00, 0xfe, 0x00, 0x01, 0x04, 0x04, 0x03, 0x00, 0x01, 0x00, 0xfd, + 0xf9, 0xf7, 0xf7, 0xfe, 0x08, 0x18, 0x26, 0x2d, 0x2c, 0x25, 0x1a, 0x0f, + 0x08, 0x08, 0x0a, 0x0c, 0x0a, 0x01, 0xf8, 0xec, 0xe2, 0xdb, 0xda, 0xd9, + 0xd8, 0xd8, 0xd9, 0xd8, 0xd8, 0xd8, 0xda, 0xd9, 0xda, 0xdc, 0xe0, 0xed, + 0x01, 0x14, 0x22, 0x2c, 0x2c, 0x27, 0x1e, 0x19, 0x17, 0x1b, 0x21, 0x25, + 0x22, 0x1c, 0x12, 0x09, 0x03, 0x00, 0x00, 0x02, 0x03, 0x04, 0x04, 0x00, + 0x00, 0x01, 0xfe, 0xfb, 0xf8, 0xf7, 0xfa, 0x05, 0x14, 0x22, 0x2c, 0x2f, + 0x28, 0x1d, 0x13, 0x0b, 0x07, 0x08, 0x0b, 0x0a, 0x04, 0xfc, 0xef, 0xe5, + 0xde, 0xda, 0xda, 0xd9, 0xda, 0xda, 0xd9, 0xd7, 0xd9, 0xd9, 0xd9, 0xda, + 0xda, 0xdd, 0xe7, 0xfa, 0x0c, 0x1e, 0x28, 0x2c, 0x28, 0x20, 0x1a, 0x17, + 0x18, 0x1e, 0x25, 0x25, 0x1e, 0x15, 0x0e, 0x07, 0x03, 0x01, 0x02, 0x03, + 0x04, 0x04, 0x02, 0x00, 0x00, 0xfe, 0xfc, 0xf9, 0xf8, 0xf9, 0x01, 0x0f, + 0x1e, 0x2a, 0x30, 0x2d, 0x23, 0x16, 0x0d, 0x07, 0x06, 0x09, 0x0a, 0x06, + 0xff, 0xf2, 0xe7, 0xe0, 0xdd, 0xdb, 0xd9, 0xda, 0xd9, 0xd8, 0xd8, 0xd8, + 0xd8, 0xd8, 0xd9, 0xd9, 0xda, 0xe3, 0xf3, 0x05, 0x17, 0x25, 0x2b, 0x28, + 0x22, 0x1c, 0x16, 0x17, 0x1c, 0x22, 0x25, 0x21, 0x1b, 0x11, 0x09, 0x05, + 0x04, 0x03, 0x04, 0x05, 0x05, 0x02, 0x00, 0xfe, 0xfe, 0xfc, 0xfb, 0xf7, + 0xf8, 0xff, 0x0a, 0x19, 0x28, 0x30, 0x2f, 0x26, 0x1a, 0x0f, 0x08, 0x05, + 0x06, 0x09, 0x06, 0x01, 0xf6, 0xeb, 0xe2, 0xe0, 0xdc, 0xdb, 0xdc, 0xdc, + 0xda, 0xd8, 0xd7, 0xd7, 0xd7, 0xd8, 0xd8, 0xda, 0xe0, 0xec, 0x00, 0x11, + 0x22, 0x29, 0x29, 0x25, 0x1d, 0x18, 0x15, 0x19, 0x20, 0x24, 0x24, 0x1e, + 0x16, 0x0e, 0x08, 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x00, 0xff, 0xfd, + 0xfc, 0xfa, 0xf7, 0xf7, 0xfd, 0x06, 0x15, 0x24, 0x2f, 0x31, 0x2a, 0x1e, + 0x12, 0x08, 0x04, 0x05, 0x07, 0x07, 0x03, 0xfa, 0xef, 0xe5, 0xe0, 0xde, + 0xdd, 0xdd, 0xdd, 0xd9, 0xd8, 0xd7, 0xd8, 0xd7, 0xd8, 0xd8, 0xd8, 0xdc, + 0xe7, 0xf8, 0x0b, 0x1d, 0x28, 0x29, 0x27, 0x1f, 0x18, 0x15, 0x18, 0x1d, + 0x22, 0x23, 0x20, 0x19, 0x11, 0x0b, 0x08, 0x07, 0x07, 0x07, 0x06, 0x04, + 0x00, 0xff, 0xfc, 0xfa, 0xfa, 0xf7, 0xf7, 0xfb, 0x03, 0x10, 0x20, 0x2d, + 0x31, 0x2d, 0x23, 0x16, 0x0b, 0x04, 0x03, 0x05, 0x07, 0x03, 0xfd, 0xf1, + 0xe7, 0xe2, 0xe0, 0xde, 0xdf, 0xde, 0xdc, 0xda, 0xd8, 0xd6, 0xd5, 0xd7, + 0xd7, 0xd7, 0xdb, 0xe3, 0xf2, 0x04, 0x17, 0x25, 0x29, 0x26, 0x1f, 0x18, + 0x14, 0x14, 0x1b, 0x20, 0x23, 0x23, 0x1d, 0x14, 0x0e, 0x0a, 0x08, 0x08, + 0x09, 0x08, 0x05, 0x02, 0x00, 0xfc, 0xfa, 0xf8, 0xf7, 0xf7, 0xfa, 0x00, + 0x0d, 0x1c, 0x2b, 0x32, 0x31, 0x27, 0x1a, 0x0d, 0x05, 0x02, 0x03, 0x05, + 0x04, 0x00, 0xf6, 0xec, 0xe4, 0xe0, 0xdf, 0xdf, 0xde, 0xdd, 0xda, 0xd9, + 0xd5, 0xd5, 0xd5, 0xd5, 0xd7, 0xd9, 0xdf, 0xed, 0x00, 0x12, 0x21, 0x29, + 0x27, 0x21, 0x1a, 0x15, 0x13, 0x15, 0x1c, 0x22, 0x24, 0x20, 0x1a, 0x13, + 0x0e, 0x0a, 0x0a, 0x0b, 0x0a, 0x07, 0x04, 0x00, 0xfc, 0xfa, 0xf8, 0xf7, + 0xf7, 0xf8, 0xfd, 0x06, 0x17, 0x27, 0x31, 0x32, 0x2b, 0x1f, 0x10, 0x06, + 0x00, 0x00, 0x03, 0x05, 0x00, 0xf8, 0xef, 0xe7, 0xe3, 0xe1, 0xe1, 0xe0, + 0xdd, 0xdb, 0xd8, 0xd6, 0xd4, 0xd6, 0xd5, 0xd5, 0xd8, 0xde, 0xe7, 0xf8, + 0x0b, 0x1c, 0x27, 0x27, 0x22, 0x1b, 0x14, 0x12, 0x13, 0x18, 0x20, 0x23, + 0x22, 0x1d, 0x17, 0x11, 0x0e, 0x0d, 0x0c, 0x0b, 0x09, 0x04, 0x00, 0xfd, + 0xfa, 0xf7, 0xf6, 0xf6, 0xf7, 0xfb, 0x02, 0x13, 0x24, 0x30, 0x35, 0x30, + 0x23, 0x15, 0x08, 0x00, 0x00, 0x02, 0x04, 0x02, 0xfd, 0xf4, 0xea, 0xe3, + 0xe2, 0xe3, 0xe2, 0xe0, 0xde, 0xda, 0xd8, 0xd7, 0xd5, 0xd5, 0xd5, 0xd7, + 0xda, 0xe2, 0xf1, 0x05, 0x17, 0x23, 0x29, 0x24, 0x1c, 0x14, 0x0f, 0x0f, + 0x15, 0x1c, 0x21, 0x22, 0x1f, 0x19, 0x13, 0x0f, 0x0f, 0x0e, 0x0c, 0x0a, + 0x06, 0x02, 0xfe, 0xfb, 0xf7, 0xf6, 0xf6, 0xf6, 0xfa, 0x00, 0x0c, 0x1f, + 0x2d, 0x35, 0x33, 0x28, 0x18, 0x0c, 0x02, 0x00, 0x00, 0x02, 0x02, 0x00, + 0xf7, 0xee, 0xe6, 0xe3, 0xe3, 0xe2, 0xe0, 0xdf, 0xdc, 0xd7, 0xd7, 0xd5, + 0xd4, 0xd4, 0xd7, 0xd8, 0xdf, 0xec, 0x00, 0x12, 0x22, 0x2a, 0x26, 0x1e, + 0x15, 0x0e, 0x0b, 0x0f, 0x18, 0x20, 0x23, 0x22, 0x1c, 0x16, 0x12, 0x10, + 0x10, 0x0f, 0x0c, 0x08, 0x03, 0x00, 0xfd, 0xf8, 0xf6, 0xf5, 0xf6, 0xf7, + 0xfe, 0x08, 0x1a, 0x2a, 0x35, 0x35, 0x2c, 0x1d, 0x0f, 0x03, 0xff, 0x00, + 0x00, 0x02, 0x00, 0xfb, 0xf1, 0xe9, 0xe5, 0xe4, 0xe3, 0xe2, 0xe0, 0xdd, + 0xd9, 0xd7, 0xd5, 0xd4, 0xd4, 0xd6, 0xd7, 0xdc, 0xe8, 0xfa, 0x0b, 0x1c, + 0x27, 0x27, 0x20, 0x16, 0x0d, 0x09, 0x0b, 0x14, 0x1c, 0x21, 0x22, 0x1e, + 0x18, 0x15, 0x13, 0x12, 0x10, 0x0f, 0x0b, 0x05, 0x00, 0xfd, 0xfa, 0xf6, + 0xf5, 0xf5, 0xf6, 0xfb, 0x04, 0x14, 0x25, 0x33, 0x37, 0x30, 0x24, 0x15, + 0x06, 0xff, 0xfd, 0x00, 0x01, 0x00, 0xfc, 0xf4, 0xeb, 0xe7, 0xe4, 0xe3, + 0xe3, 0xe2, 0xde, 0xda, 0xd6, 0xd5, 0xd3, 0xd3, 0xd3, 0xd6, 0xda, 0xe3, + 0xf3, 0x04, 0x17, 0x24, 0x28, 0x22, 0x1a, 0x10, 0x09, 0x0a, 0x10, 0x19, + 0x21, 0x23, 0x21, 0x1c, 0x17, 0x15, 0x15, 0x13, 0x12, 0x0f, 0x00, 0x00, + 0x02, 0xff, 0xff, 0x02, 0x00, 0xfe, 0xfd, 0xfe, 0x06, 0x0b, 0x07, 0x05, + 0x07, 0x06, 0xfd, 0xfe, 0x00, 0x03, 0x02, 0x01, 0x0b, 0x03, 0x01, 0xfe, + 0xff, 0x02, 0x07, 0x09, 0x07, 0x03, 0x03, 0x06, 0x0a, 0x05, 0x06, 0x07, + 0x07, 0x10, 0x0f, 0x07, 0x07, 0x06, 0x00, 0xff, 0x00, 0x09, 0x07, 0x06, + 0x06, 0x02, 0x00, 0xfa, 0xf9, 0xf9, 0xfe, 0xfa, 0xfd, 0xfe, 0x02, 0x03, + 0x0b, 0x06, 0x02, 0x01, 0x0a, 0x0e, 0x05, 0x02, 0x03, 0xff, 0xff, 0x00, + 0x00, 0x03, 0x07, 0x06, 0x05, 0x02, 0x00, 0x00, 0x03, 0x07, 0x07, 0x09, + 0x03, 0x00, 0xfb, 0xf7, 0xfa, 0xfb, 0xff, 0x02, 0x0a, 0x10, 0x07, 0x0d, + 0x0f, 0x0e, 0x03, 0x01, 0x00, 0xff, 0xfb, 0x01, 0xfe, 0x01, 0x02, 0x02, + 0x05, 0x07, 0x03, 0x06, 0x06, 0x06, 0x02, 0x01, 0x02, 0xff, 0x02, 0x05, + 0x0e, 0x12, 0x0d, 0x0a, 0x05, 0x03, 0x00, 0x01, 0x00, 0xff, 0xfb, 0xfb, + 0x02, 0x07, 0xf7, 0xfa, 0xfa, 0xf9, 0xfb, 0xfb, 0xff, 0xfb, 0x00, 0x00, + 0x05, 0x01, 0x01, 0x01, 0x06, 0x0b, 0x07, 0x05, 0x07, 0x0f, 0x10, 0x10, + 0x0a, 0x09, 0x07, 0x03, 0x06, 0x07, 0x00, 0xff, 0xfb, 0xf9, 0xf7, 0x00, + 0x03, 0xff, 0x07, 0x0a, 0x07, 0x02, 0x05, 0x05, 0x0a, 0x10, 0x0a, 0x0b, + 0x0b, 0x06, 0x00, 0x01, 0x01, 0x00, 0x00, 0x03, 0x09, 0x03, 0xff, 0xff, + 0xfd, 0xfa, 0xff, 0x01, 0x01, 0xfd, 0xfd, 0xfd, 0xfe, 0xff, 0xff, 0x00, + 0x07, 0x0a, 0x0b, 0x0b, 0x09, 0x06, 0x01, 0xfe, 0xfe, 0x03, 0x02, 0x05, + 0x0a, 0x0b, 0x09, 0x03, 0x09, 0x03, 0x00, 0x06, 0x03, 0x06, 0x07, 0x03, + 0xff, 0xfb, 0x02, 0x09, 0x0d, 0x0f, 0x0d, 0x07, 0x09, 0x0d, 0x07, 0x01, + 0xfe, 0xfa, 0xf7, 0xf6, 0xf7, 0x01, 0xfd, 0xfd, 0x00, 0x02, 0x05, 0x07, + 0x02, 0x05, 0x03, 0x02, 0x02, 0x02, 0x00, 0x02, 0x07, 0x0f, 0x0d, 0x09, + 0x0a, 0x05, 0x00, 0x05, 0x09, 0x0d, 0x05, 0xff, 0x00, 0x05, 0x00, 0xfe, + 0xf5, 0xf5, 0xf1, 0xf7, 0xfd, 0x01, 0x07, 0x07, 0x02, 0xfe, 0x0a, 0x0b, + 0x06, 0x0b, 0x0e, 0x0d, 0x09, 0x0e, 0x0e, 0x05, 0x03, 0x07, 0x06, 0x06, + 0x07, 0x07, 0x06, 0x07, 0x05, 0x01, 0xfd, 0xff, 0xff, 0x00, 0x01, 0x02, + 0x03, 0x01, 0xfe, 0x00, 0xfe, 0xfa, 0xff, 0x00, 0x02, 0x07, 0x07, 0x03, + 0x02, 0x00, 0xff, 0x03, 0x03, 0x02, 0x06, 0x03, 0x01, 0xfe, 0xfd, 0x01, + 0x06, 0xfe, 0x02, 0x05, 0x02, 0xfe, 0x02, 0x0d, 0x12, 0x14, 0x14, 0x0d, + 0x0b, 0x03, 0xfd, 0xfe, 0x00, 0xf7, 0xf5, 0xfa, 0xfb, 0x06, 0x0a, 0x07, + 0x09, 0x05, 0x06, 0x0a, 0x09, 0x0b, 0x05, 0x0a, 0x0d, 0x05, 0x00, 0xff, + 0x02, 0x03, 0x0a, 0x0b, 0x09, 0x03, 0xff, 0xff, 0x03, 0x05, 0xfe, 0xf5, + 0xf7, 0xf6, 0xf3, 0xfb, 0xf9, 0xf7, 0xf7, 0xf9, 0x05, 0x05, 0xff, 0x06, + 0x0d, 0x0a, 0x0e, 0x07, 0x07, 0x0d, 0x12, 0x0f, 0x0d, 0x09, 0x0b, 0x0a, + 0x0b, 0x0e, 0x06, 0x03, 0xfd, 0x01, 0x00, 0x01, 0x03, 0xff, 0xf9, 0xfd, + 0x00, 0xfb, 0xfd, 0xfe, 0xf9, 0xff, 0xff, 0xfd, 0x03, 0x06, 0x09, 0x07, + 0x03, 0x09, 0x0e, 0x0a, 0x0d, 0x07, 0x0b, 0x0b, 0x07, 0x02, 0x00, 0x02, + 0x03, 0x01, 0xff, 0xff, 0xfd, 0xfb, 0x05, 0x06, 0xff, 0x03, 0x01, 0x01, + 0x03, 0x07, 0x09, 0x03, 0x01, 0x00, 0xff, 0x01, 0x03, 0xfa, 0xfe, 0xfe, + 0xfa, 0xfe, 0x02, 0x0a, 0x0f, 0x0a, 0x05, 0x0d, 0x07, 0x06, 0x06, 0x09, + 0x02, 0x07, 0x01, 0x00, 0x00, 0x02, 0x10, 0x12, 0x0b, 0x05, 0x09, 0xfe, + 0xfe, 0x01, 0x05, 0xfb, 0xfe, 0x02, 0xff, 0x09, 0x06, 0xff, 0x01, 0xfe, + 0xfb, 0xff, 0xfe, 0xfd, 0xfe, 0x01, 0x07, 0x09, 0x09, 0x02, 0x06, 0x09, + 0x0e, 0x07, 0x02, 0x06, 0x01, 0x00, 0x09, 0x05, 0xfb, 0xf5, 0xf9, 0xfd, + 0xf7, 0xfb, 0xf7, 0x01, 0x07, 0x09, 0x09, 0x14, 0x0d, 0x0d, 0x06, 0x02, + 0x02, 0xff, 0x06, 0x07, 0x01, 0x02, 0x0a, 0x0a, 0x09, 0x0b, 0x0e, 0x0f, + 0x09, 0x06, 0x03, 0x02, 0x06, 0x09, 0x03, 0x02, 0xf9, 0xfe, 0xff, 0x02, + 0xff, 0xfe, 0x00, 0xf9, 0xfd, 0x05, 0x03, 0x03, 0x07, 0x05, 0x00, 0xfe, + 0xfd, 0xfd, 0x02, 0x01, 0xfd, 0xff, 0xfd, 0x05, 0x09, 0x0e, 0x0f, 0x07, + 0x06, 0x07, 0x09, 0x02, 0x06, 0x06, 0x0d, 0x01, 0x02, 0x02, 0x05, 0x00, + 0x12, 0x09, 0x00, 0xfb, 0x01, 0x02, 0x0e, 0x10, 0x02, 0xfd, 0xfd, 0xff, + 0x02, 0xff, 0xfe, 0xfb, 0x00, 0xfd, 0xf9, 0xff, 0x03, 0x01, 0x0d, 0x09, + 0x10, 0x0d, 0x07, 0x05, 0x0f, 0x14, 0x07, 0x00, 0x03, 0xff, 0xf9, 0xf3, + 0xf9, 0xfe, 0xfd, 0xfb, 0xfd, 0x07, 0x0b, 0xfd, 0x05, 0x05, 0x05, 0x10, + 0x0d, 0x03, 0xfb, 0xfe, 0x02, 0x03, 0x01, 0xfe, 0x03, 0x01, 0x07, 0x06, + 0x0e, 0x13, 0x0d, 0x0e, 0x0d, 0x01, 0x01, 0xff, 0x00, 0xff, 0xfd, 0xfe, + 0xf7, 0xfd, 0x01, 0x06, 0x05, 0x02, 0x06, 0x07, 0x03, 0x00, 0x02, 0x00, + 0x09, 0x0a, 0x00, 0x05, 0x02, 0xfe, 0xfe, 0x06, 0x01, 0x02, 0x00, 0x02, + 0x01, 0x09, 0x0e, 0x0d, 0x07, 0x05, 0xfd, 0x00, 0x06, 0xfe, 0xec, 0xfd, + 0xf9, 0xfe, 0xff, 0xff, 0x0d, 0x0d, 0xfe, 0x02, 0x06, 0x03, 0xfb, 0x0a, + 0x09, 0x00, 0x07, 0x09, 0x07, 0x0a, 0x0a, 0x0a, 0x01, 0x0a, 0x03, 0x06, + 0x06, 0x01, 0x03, 0x0e, 0x0b, 0x07, 0xff, 0x01, 0xfe, 0x03, 0x0a, 0x07, + 0xfb, 0xfa, 0x03, 0x09, 0x05, 0x00, 0x02, 0x00, 0xf7, 0xfe, 0xf9, 0xf7, + 0xf9, 0xfa, 0x07, 0x0a, 0x09, 0x03, 0x01, 0x0b, 0x05, 0x09, 0x0a, 0x01, + 0xfb, 0xfe, 0x02, 0x09, 0x14, 0x10, 0x10, 0x09, 0xfe, 0xf1, 0xf3, 0xf7, + 0xfd, 0xf6, 0x05, 0x09, 0xff, 0xfd, 0x09, 0x0e, 0x0a, 0x0d, 0x05, 0x06, + 0x02, 0xff, 0x0d, 0x0d, 0x0e, 0x0b, 0x17, 0x12, 0x0e, 0x06, 0x00, 0x02, + 0x00, 0xf7, 0xfe, 0x01, 0xfd, 0xff, 0xff, 0x03, 0x02, 0xfb, 0xfd, 0xf9, + 0x05, 0x0a, 0xff, 0xfd, 0x02, 0x00, 0xfa, 0xf6, 0x06, 0x02, 0x01, 0xfd, + 0xfd, 0x05, 0x0a, 0xfb, 0x01, 0x02, 0x10, 0x14, 0x12, 0x10, 0x12, 0x0d, + 0xff, 0xff, 0x01, 0x00, 0xfe, 0x01, 0x01, 0x00, 0x03, 0x00, 0x01, 0x06, + 0x07, 0x09, 0x0a, 0x09, 0x0e, 0x12, 0x00, 0xfa, 0x06, 0x03, 0x00, 0x01, + 0xfb, 0xff, 0x0a, 0x09, 0x02, 0x0f, 0x20, 0x14, 0x13, 0x13, 0x05, 0xfe, + 0xfb, 0xf9, 0xf7, 0xf7, 0xf1, 0xf1, 0xf5, 0xf5, 0x00, 0xfd, 0xfb, 0x06, + 0x0b, 0x05, 0x01, 0x00, 0x00, 0x02, 0x00, 0xf7, 0xf6, 0xf2, 0xf9, 0x01, + 0x02, 0x0d, 0x07, 0xff, 0x03, 0x1a, 0x1a, 0x13, 0x14, 0x0e, 0x0e, 0x14, + 0x12, 0x12, 0x0d, 0x06, 0x07, 0x06, 0xf9, 0xf0, 0xf9, 0x00, 0x03, 0x05, + 0x0d, 0x0b, 0x09, 0x02, 0xfb, 0xfd, 0x00, 0xfe, 0xfd, 0xfb, 0xf9, 0xf9, + 0xff, 0x07, 0x07, 0x07, 0x0e, 0x1b, 0x0e, 0x03, 0x00, 0x0b, 0x01, 0xfa, + 0xfe, 0xf6, 0xfe, 0x01, 0xfb, 0xfa, 0xff, 0xfb, 0xfa, 0xfa, 0x03, 0x02, + 0xf7, 0xf5, 0x05, 0x0e, 0x05, 0xfa, 0xf7, 0x03, 0x0b, 0x09, 0xfa, 0xfa, + 0x01, 0x0d, 0x0e, 0x02, 0x1b, 0x21, 0x20, 0x21, 0x14, 0x10, 0x0d, 0x13, + 0x10, 0x06, 0x10, 0x0e, 0x01, 0xf3, 0xed, 0xf3, 0xea, 0xf2, 0xf3, 0xfd, + 0x0d, 0x05, 0x00, 0x07, 0x07, 0x02, 0xfd, 0xf7, 0xf6, 0xf3, 0x01, 0x00, + 0x05, 0x0a, 0xff, 0x05, 0x1b, 0x16, 0x13, 0x09, 0x02, 0x06, 0xff, 0xfe, + 0x00, 0xfb, 0xf2, 0xfb, 0x03, 0x01, 0x09, 0x01, 0xf9, 0x00, 0xff, 0xfe, + 0xfb, 0x00, 0x03, 0x0b, 0x01, 0x02, 0x0a, 0x06, 0x05, 0x02, 0x0a, 0x0e, + 0x17, 0x0d, 0x05, 0x17, 0x23, 0x18, 0x0f, 0x10, 0x10, 0x0f, 0x12, 0x03, + 0x00, 0x01, 0x03, 0xfa, 0xf5, 0xf6, 0xfe, 0x05, 0x02, 0x00, 0xf9, 0xfa, + 0xf9, 0xf0, 0xf3, 0xfb, 0xf9, 0xf6, 0xf3, 0xf2, 0xf7, 0xf1, 0xf1, 0x02, + 0x0e, 0x1b, 0x13, 0x1f, 0x07, 0x00, 0x01, 0xfd, 0xfd, 0x06, 0x12, 0x13, + 0x0b, 0x07, 0x06, 0x06, 0x06, 0x02, 0x00, 0x01, 0x06, 0x0b, 0x00, 0xf7, + 0xfa, 0xfe, 0xff, 0xfe, 0x01, 0x03, 0x02, 0x03, 0x05, 0x00, 0x05, 0x10, + 0x06, 0x03, 0x0f, 0x34, 0x30, 0x28, 0x1d, 0x13, 0x0e, 0x0a, 0x07, 0x07, + 0x00, 0xfd, 0xfb, 0xf7, 0xec, 0xee, 0xed, 0xf0, 0xee, 0xf9, 0xfd, 0xf1, + 0xe5, 0xe5, 0xee, 0xf1, 0xee, 0xee, 0xf3, 0xf9, 0xfb, 0xfe, 0x03, 0x09, + 0x12, 0x1b, 0x24, 0x21, 0x1a, 0x1a, 0x16, 0x0e, 0x02, 0xfd, 0x01, 0x09, + 0x0d, 0x07, 0x0a, 0x0d, 0x06, 0x05, 0x0b, 0x0a, 0x01, 0xff, 0x05, 0x07, + 0x0f, 0x06, 0x0a, 0xfe, 0xf7, 0xf6, 0xf7, 0x02, 0xfb, 0xfa, 0x06, 0x01, + 0xff, 0x10, 0x23, 0x13, 0x0d, 0x06, 0x13, 0x17, 0x0b, 0xfd, 0xf6, 0xf0, + 0xf5, 0xf6, 0xf2, 0xf2, 0x02, 0xff, 0x06, 0x01, 0x00, 0x00, 0xfa, 0xf1, + 0xec, 0xed, 0xf7, 0xf5, 0x01, 0x06, 0x03, 0x02, 0xfe, 0x07, 0x07, 0x09, + 0x05, 0x1a, 0x18, 0x16, 0x16, 0x0d, 0x0a, 0x0a, 0x32, 0x31, 0x1d, 0x0e, + 0x07, 0x06, 0x09, 0x03, 0xff, 0xfe, 0x03, 0x00, 0xf3, 0xf0, 0xf6, 0xf7, + 0xf1, 0xf3, 0xfb, 0xf7, 0xf3, 0xf5, 0xee, 0xee, 0x00, 0x02, 0xfd, 0xfe, + 0x1c, 0x2c, 0x21, 0x17, 0x13, 0x1b, 0x13, 0x02, 0x05, 0x0e, 0x12, 0x0d, + 0xfb, 0xf5, 0xed, 0xed, 0xe4, 0xe8, 0xec, 0xfd, 0x05, 0xf7, 0xf5, 0xf7, + 0xf9, 0xf3, 0xf2, 0xf1, 0x0d, 0x17, 0x18, 0x1b, 0x14, 0x0b, 0x06, 0x0a, + 0x21, 0x21, 0x0f, 0x01, 0x00, 0x01, 0x00, 0x07, 0x06, 0x01, 0x03, 0x13, + 0x12, 0x0e, 0x02, 0x02, 0x09, 0x07, 0x03, 0x03, 0x0d, 0x17, 0x0f, 0x07, + 0xfe, 0xff, 0xfd, 0xf3, 0xf2, 0xf0, 0xec, 0x00, 0xfd, 0xf3, 0xf3, 0x03, + 0x07, 0x09, 0x00, 0xf3, 0xf5, 0xf9, 0xee, 0xee, 0xf7, 0xf1, 0xfe, 0x01, + 0x14, 0x3b, 0x28, 0x17, 0x12, 0x06, 0xf7, 0xfb, 0x06, 0x06, 0x02, 0xff, + 0xfb, 0x01, 0x06, 0x0b, 0x0d, 0x10, 0x0b, 0x0d, 0x03, 0x03, 0x0e, 0x1a, + 0x16, 0x0b, 0x03, 0xff, 0xfd, 0x13, 0x0a, 0x0b, 0x0b, 0x06, 0x07, 0xff, + 0xfe, 0xfb, 0x12, 0x17, 0x0e, 0xfe, 0xf6, 0xe9, 0xe5, 0xe9, 0xea, 0xe4, + 0xe3, 0xed, 0xee, 0xf1, 0x07, 0x05, 0x05, 0xfe, 0xfe, 0x13, 0x21, 0x25, + 0x21, 0x20, 0x24, 0x12, 0x0e, 0x10, 0x03, 0xfd, 0xf5, 0xf7, 0xfa, 0xf7, + 0xf3, 0xf5, 0xfa, 0xfe, 0x07, 0x00, 0x06, 0x06, 0x0a, 0x05, 0xfd, 0xfa, + 0xfa, 0x16, 0x16, 0x1a, 0x14, 0x14, 0x13, 0x01, 0xfb, 0x03, 0x10, 0x0f, + 0x0f, 0x06, 0x01, 0x00, 0xff, 0xfa, 0xfa, 0xf2, 0xec, 0xec, 0xe9, 0xf3, + 0x09, 0x0a, 0x03, 0x01, 0x09, 0x30, 0x30, 0x1b, 0x1a, 0x10, 0xea, 0xe3, + 0xe4, 0xf7, 0xf9, 0xee, 0xf6, 0x0b, 0x05, 0x02, 0x07, 0x10, 0x07, 0x05, + 0x02, 0xfe, 0x00, 0x09, 0x14, 0x0a, 0xf7, 0xee, 0xf5, 0x0b, 0x0b, 0xff, + 0x00, 0x06, 0x0b, 0x01, 0xf6, 0xfd, 0x0f, 0x1a, 0x0d, 0x0a, 0x06, 0x03, + 0xfd, 0x07, 0x13, 0x13, 0x10, 0x09, 0x05, 0x09, 0x2c, 0x1d, 0x07, 0x09, + 0x03, 0x12, 0x14, 0x09, 0xff, 0xff, 0xfb, 0xf3, 0xee, 0xf0, 0xec, 0xe5, + 0xe5, 0xe1, 0xec, 0xfa, 0xee, 0xdd, 0xd9, 0xe8, 0x12, 0x0a, 0xfe, 0xfe, + 0x10, 0x12, 0x05, 0x0d, 0x0a, 0x1b, 0x2c, 0x25, 0x2d, 0x28, 0x25, 0x24, + 0x1a, 0x17, 0x0b, 0x07, 0x07, 0x06, 0x02, 0x03, 0xfa, 0xe4, 0xe4, 0xe4, + 0xed, 0xea, 0xe5, 0xe9, 0x02, 0x03, 0xf6, 0xf1, 0xf2, 0x13, 0x34, 0x1d, + 0x1c, 0x23, 0x1d, 0x03, 0xfa, 0xfb, 0x01, 0x0b, 0x09, 0x06, 0x0d, 0x05, + 0x00, 0x00, 0xfb, 0xf9, 0xf2, 0xf2, 0xee, 0xf2, 0xfd, 0xfe, 0xfd, 0xff, + 0xfa, 0x09, 0x1c, 0x0b, 0x01, 0x09, 0x07, 0xf7, 0xe8, 0xf1, 0xf5, 0x0f, + 0x1d, 0x1d, 0x1d, 0x0a, 0x02, 0x00, 0x06, 0x12, 0x0e, 0x14, 0x0e, 0x0d, + 0x16, 0x14, 0x05, 0xfa, 0xf5, 0xfd, 0x13, 0x0e, 0x03, 0xfe, 0xfe, 0xf7, + 0xf6, 0xf3, 0xf6, 0xee, 0xea, 0xea, 0xee, 0xfb, 0xfa, 0xf6, 0xee, 0xf6, + 0x14, 0x25, 0x1a, 0x18, 0x1f, 0x1b, 0x23, 0x02, 0xff, 0x1a, 0x28, 0x17, + 0x0f, 0x12, 0x1a, 0x07, 0x02, 0xfe, 0xfd, 0xf2, 0xf0, 0xec, 0xec, 0xf1, + 0xfa, 0xec, 0xdf, 0xdf, 0xdc, 0xe3, 0xe5, 0xed, 0x05, 0xfa, 0xf3, 0xfd, + 0x06, 0x17, 0x3f, 0x2e, 0x2d, 0x3a, 0x32, 0x27, 0x25, 0x23, 0x21, 0x17, + 0x0f, 0x0f, 0x0e, 0x0e, 0x0b, 0x06, 0xf6, 0xe3, 0xe4, 0xe5, 0xe5, 0xee, + 0xf2, 0xf0, 0xec, 0xe8, 0xe3, 0xe5, 0xfe, 0xfa, 0xf9, 0x01, 0x07, 0x07, + 0xf9, 0xf1, 0xf1, 0x00, 0x1b, 0x31, 0x2a, 0x1d, 0x17, 0x17, 0x09, 0x02, + 0x01, 0x01, 0x03, 0x0f, 0x0f, 0x07, 0xfd, 0xfd, 0xff, 0x00, 0x0f, 0x0b, + 0x09, 0x0a, 0x00, 0xfd, 0xfe, 0xf3, 0xe5, 0xec, 0xed, 0xfb, 0x17, 0x0a, + 0x0d, 0x0a, 0xfe, 0xf9, 0x12, 0x21, 0x1c, 0x28, 0x2a, 0x1a, 0x06, 0xf2, + 0xf6, 0xf9, 0x0a, 0x0b, 0x09, 0x0b, 0x03, 0xf5, 0xf5, 0xf3, 0xed, 0xee, + 0xec, 0xee, 0xf0, 0xec, 0xe8, 0xee, 0xed, 0xf1, 0x02, 0x03, 0x05, 0x1c, + 0x1d, 0x0e, 0x06, 0x10, 0x09, 0x0a, 0x37, 0x37, 0x30, 0x2d, 0x29, 0x17, + 0x0e, 0x0a, 0xff, 0x00, 0xfd, 0xfa, 0xfa, 0xf3, 0xf5, 0xf0, 0xe6, 0xe5, + 0xe5, 0xe8, 0xf3, 0xf7, 0xf2, 0xed, 0xea, 0xf2, 0x00, 0x02, 0x0b, 0x0b, + 0x18, 0x20, 0x27, 0x1a, 0x0f, 0x14, 0x0f, 0x18, 0x20, 0x18, 0x1a, 0x14, + 0x0e, 0x0d, 0x09, 0xf1, 0xe4, 0xe9, 0xfd, 0xfe, 0xf9, 0xf3, 0xf2, 0xfa, + 0xf6, 0x01, 0x0a, 0xfb, 0xfd, 0x00, 0x05, 0x09, 0xee, 0xee, 0xf0, 0xf2, + 0xf5, 0x02, 0x17, 0x10, 0x13, 0x0f, 0x09, 0x02, 0x05, 0x17, 0x13, 0x12, + 0x16, 0x1d, 0x12, 0x00, 0xf7, 0x07, 0x18, 0x10, 0x13, 0x1c, 0x16, 0x0e, + 0x03, 0x01, 0xf6, 0xe4, 0xf1, 0xf9, 0x06, 0xfe, 0xf2, 0xf2, 0xf5, 0xf9, + 0xfa, 0x0a, 0x0e, 0x0a, 0x09, 0x03, 0xf5, 0xe4, 0xe1, 0xee, 0x12, 0x05, + 0x09, 0x20, 0x1b, 0x16, 0x0d, 0x00, 0xf7, 0xfa, 0xfa, 0x03, 0x05, 0x06, + 0x02, 0xff, 0xfe, 0xf9, 0xff, 0x14, 0x0d, 0x02, 0x00, 0xfd, 0xfa, 0x02, + 0x10, 0x0d, 0x0b, 0x21, 0x2d, 0x29, 0x18, 0x0a, 0x0d, 0x09, 0x03, 0x09, + 0x0f, 0x02, 0x05, 0x0a, 0xfe, 0xf3, 0xe5, 0xe1, 0xe3, 0xf1, 0xf1, 0xf2, + 0xf2, 0xf2, 0xf0, 0xf6, 0xfa, 0xff, 0x06, 0x01, 0x09, 0x07, 0x05, 0x12, + 0x0d, 0x0a, 0x09, 0x0a, 0x23, 0x21, 0x17, 0x18, 0x0f, 0x01, 0x05, 0x0a, + 0x07, 0x0b, 0x02, 0x03, 0xff, 0xfb, 0xf7, 0xf9, 0xf7, 0x00, 0x03, 0x06, + 0x10, 0x12, 0x0f, 0x0b, 0xf3, 0xee, 0xf0, 0xf0, 0xf3, 0xf3, 0x09, 0x10, + 0x07, 0x07, 0x05, 0x06, 0x12, 0x1b, 0x0e, 0x05, 0x00, 0xff, 0xf5, 0xf2, + 0xfb, 0x0a, 0x17, 0x0e, 0x17, 0x16, 0x06, 0x01, 0x00, 0x05, 0xff, 0xec, + 0xe1, 0x02, 0x12, 0x0a, 0xfb, 0xf6, 0xfa, 0x07, 0x12, 0x18, 0x1f, 0x16, + 0x0f, 0x06, 0xfa, 0xed, 0xf1, 0x00, 0x0a, 0x06, 0x0a, 0x03, 0xff, 0xf7, + 0xec, 0xed, 0xf6, 0x02, 0xff, 0x00, 0xff, 0xfa, 0x00, 0x03, 0x03, 0x0e, + 0x1f, 0x17, 0x17, 0x14, 0x0f, 0x06, 0x07, 0x06, 0x0a, 0x2c, 0x18, 0x0e, + 0x23, 0x1f, 0x10, 0x00, 0xff, 0xfd, 0xfb, 0x02, 0xfb, 0xf9, 0xfe, 0xfb, + 0xf1, 0xd3, 0xd2, 0xe1, 0xf3, 0xf1, 0xe8, 0xe9, 0xe4, 0xf1, 0xf9, 0xfb, + 0x0d, 0x1a, 0x0d, 0x0f, 0x21, 0x24, 0x17, 0x0e, 0x1b, 0x23, 0x18, 0x14, + 0x10, 0x10, 0x18, 0x0b, 0x0f, 0x09, 0x07, 0x0d, 0x16, 0x02, 0xf2, 0xfb, + 0xfb, 0xed, 0xe6, 0xe5, 0xec, 0x01, 0x0e, 0x06, 0x17, 0x1c, 0x1a, 0x02, + 0xf1, 0xf9, 0xfa, 0xf0, 0xe9, 0xec, 0xfe, 0x0b, 0x12, 0x14, 0x0a, 0x0e, + 0x05, 0x01, 0x03, 0x01, 0xff, 0xf9, 0xf5, 0xf3, 0xf5, 0x0e, 0x09, 0x09, + 0x14, 0x18, 0x0e, 0x02, 0xf7, 0xf7, 0xfd, 0x0a, 0x03, 0x07, 0x09, 0x0d, + 0x09, 0xff, 0x00, 0x0e, 0x0d, 0x02, 0x0d, 0x1b, 0x23, 0x1d, 0x07, 0xf6, + 0xf9, 0x0d, 0x03, 0x02, 0x00, 0x06, 0xff, 0xfb, 0xf6, 0xf7, 0xfa, 0xfa, + 0xf7, 0xf6, 0xf7, 0xf9, 0xf3, 0xed, 0xf2, 0xfe, 0x14, 0x17, 0x18, 0x16, + 0x07, 0x01, 0xfd, 0xf3, 0xfe, 0x1d, 0x24, 0x14, 0x12, 0x27, 0x1a, 0x09, + 0x01, 0x02, 0x01, 0x09, 0x01, 0xfe, 0xff, 0x01, 0x06, 0xf7, 0xfe, 0xfb, + 0xf5, 0xf0, 0xe4, 0xe8, 0xe4, 0xe0, 0xe3, 0xea, 0xf6, 0x0e, 0x1c, 0x1a, + 0x13, 0x16, 0x12, 0x09, 0x07, 0x0d, 0x10, 0x23, 0x21, 0x1d, 0x20, 0x18, + 0x24, 0x24, 0x20, 0x16, 0x0a, 0x05, 0xf9, 0xee, 0xf2, 0xea, 0xea, 0xec, + 0xf7, 0x05, 0x01, 0xfa, 0xf1, 0xfb, 0x03, 0xfd, 0xec, 0xe3, 0xe3, 0xf7, + 0xfb, 0xf0, 0xf2, 0xf1, 0xfe, 0x0b, 0x1d, 0x1b, 0x14, 0x14, 0x10, 0x1a, + 0x1a, 0x12, 0x0f, 0x03, 0x01, 0x14, 0x16, 0x0e, 0x05, 0x0a, 0x10, 0x05, + 0xfe, 0xfb, 0xf9, 0xf5, 0xff, 0xfd, 0xf7, 0xf3, 0xf0, 0xff, 0x02, 0xff, + 0x0b, 0x18, 0x0e, 0x1a, 0x18, 0x16, 0x0b, 0x00, 0x01, 0x12, 0x0a, 0x0b, + 0x03, 0x07, 0x10, 0x01, 0xfa, 0xf2, 0xf3, 0xf0, 0xf1, 0xf3, 0xf2, 0xf1, + 0xee, 0xfb, 0xfe, 0x00, 0x01, 0x01, 0x00, 0xff, 0xfd, 0x07, 0x05, 0xfd, + 0xff, 0x1d, 0x36, 0x34, 0x1d, 0x12, 0x14, 0x0f, 0x09, 0x01, 0x00, 0x01, + 0x0b, 0x10, 0x07, 0x06, 0xff, 0x09, 0x02, 0x02, 0xff, 0xf5, 0xec, 0xec, + 0xe5, 0xe1, 0xe0, 0xf2, 0x0e, 0x18, 0x0b, 0x06, 0xff, 0x05, 0x0e, 0x02, + 0xfb, 0xfd, 0x0a, 0x21, 0x21, 0x1d, 0x1b, 0x16, 0x0a, 0x17, 0x18, 0x10, + 0x03, 0xfe, 0x0b, 0x02, 0xf1, 0xe9, 0xe9, 0xed, 0xfd, 0x02, 0xfa, 0xfb, + 0x02, 0x00, 0x09, 0x09, 0xfe, 0xfb, 0xf9, 0xf9, 0xfa, 0xf2, 0xec, 0xec, + 0xf2, 0x05, 0x10, 0x10, 0x14, 0x1d, 0x1a, 0x10, 0x0b, 0x0a, 0x05, 0x07, + 0x14, 0x12, 0x09, 0x0b, 0x0e, 0x0d, 0x16, 0x12, 0x10, 0x0b, 0x07, 0x01, + 0xf7, 0xff, 0x03, 0xe6, 0xe4, 0xf5, 0x03, 0x02, 0xff, 0x05, 0x00, 0xfb, + 0x02, 0x06, 0xf9, 0xf5, 0x05, 0x1a, 0x1b, 0x0d, 0x01, 0xf5, 0xf9, 0xfa, + 0xf3, 0xf3, 0xf6, 0xf9, 0xfe, 0x03, 0x01, 0x06, 0x0a, 0x0d, 0x13, 0x07, + 0x06, 0x0a, 0x09, 0x07, 0xff, 0xfb, 0xfa, 0xfe, 0x0e, 0x1b, 0x0f, 0x10, + 0x18, 0x13, 0xf9, 0xfd, 0x03, 0x0a, 0x0a, 0x14, 0x0f, 0x07, 0x05, 0x09, + 0x14, 0x0f, 0x05, 0xfd, 0xf7, 0xfb, 0xfe, 0xff, 0xec, 0xea, 0xf1, 0xfb, + 0x02, 0x07, 0xff, 0xf6, 0xf3, 0xf9, 0xf7, 0xfb, 0x03, 0x0a, 0x0b, 0x0f, + 0x09, 0x03, 0x01, 0x02, 0x0a, 0x1c, 0x29, 0x1d, 0x1a, 0x1f, 0x1f, 0x13, + 0xfe, 0xe9, 0xed, 0xf1, 0xf7, 0x02, 0xfd, 0xf7, 0xfe, 0x06, 0x09, 0x0d, + 0x0d, 0x06, 0xfb, 0xf3, 0xf3, 0xf5, 0xf1, 0xec, 0xee, 0xfe, 0x0f, 0x18, + 0x0b, 0x07, 0x10, 0x1a, 0x12, 0x07, 0x0a, 0x09, 0x0a, 0x0f, 0x18, 0x14, + 0x07, 0x03, 0x02, 0x09, 0x0f, 0x03, 0xfe, 0xf9, 0xf3, 0x00, 0x00, 0xfd, + 0xf3, 0xf3, 0xfb, 0xfa, 0xf1, 0xf1, 0xf7, 0xfb, 0x02, 0x10, 0x10, 0x03, + 0x0d, 0x0f, 0x09, 0x12, 0x0d, 0x0b, 0x00, 0xf3, 0xff, 0xff, 0x00, 0x02, + 0x00, 0xfd, 0xff, 0x00, 0x01, 0x09, 0x07, 0x07, 0x07, 0x06, 0x0b, 0x0a, + 0x07, 0x09, 0x0a, 0x02, 0x03, 0x0f, 0x0d, 0x12, 0x18, 0x18, 0x06, 0xfa, + 0xfb, 0x06, 0x12, 0x06, 0x01, 0xfe, 0x01, 0x00, 0xff, 0x07, 0x06, 0x05, + 0xf7, 0xfe, 0x02, 0x00, 0xf7, 0xf1, 0xe4, 0xe0, 0xe1, 0xfa, 0xf9, 0xf2, + 0xfe, 0x07, 0x06, 0x01, 0x0d, 0x0f, 0x0f, 0x0d, 0x17, 0x1a, 0x12, 0x07, + 0x09, 0x12, 0x20, 0x25, 0x1b, 0x16, 0x14, 0x0b, 0x05, 0x02, 0xf9, 0xe1, + 0xe6, 0xf9, 0xfd, 0x00, 0xff, 0x02, 0xfb, 0xfd, 0x0f, 0x16, 0x0e, 0xff, + 0xed, 0xe9, 0xf0, 0x02, 0xfe, 0xf7, 0x03, 0x0b, 0x14, 0x18, 0x0d, 0x06, + 0x0b, 0x10, 0x06, 0x01, 0xfe, 0x10, 0x09, 0x03, 0x01, 0x06, 0xfe, 0xf7, + 0x03, 0x09, 0x02, 0x02, 0x0d, 0x05, 0xfb, 0xfb, 0x00, 0x03, 0xfe, 0xff, + 0x01, 0xfb, 0xf2, 0xf5, 0x0a, 0x0e, 0x09, 0x0a, 0x0f, 0x14, 0x13, 0x06, + 0x0a, 0x0b, 0x09, 0xfd, 0xfe, 0xfb, 0xfd, 0xff, 0xfe, 0xf9, 0xf5, 0xfe, + 0x0d, 0x09, 0x0e, 0x10, 0x0d, 0x09, 0x0b, 0x0d, 0x14, 0x0b, 0x01, 0xfa, + 0xf7, 0xfd, 0x00, 0xfe, 0xff, 0x01, 0x09, 0x09, 0x13, 0x0e, 0xfd, 0x03, + 0x09, 0xff, 0xfd, 0xfa, 0xfb, 0xfe, 0x09, 0x14, 0x14, 0x09, 0xff, 0xfa, + 0x05, 0x07, 0x00, 0xf1, 0xe0, 0xe5, 0xf1, 0x02, 0x06, 0x02, 0xfe, 0xfa, + 0x07, 0x0b, 0x07, 0x09, 0x03, 0xfb, 0x02, 0x10, 0x1a, 0x13, 0x16, 0x2a, + 0x2a, 0x21, 0x1d, 0x21, 0x10, 0x03, 0x01, 0xf9, 0xee, 0xea, 0xfd, 0xfb, + 0xfa, 0xfe, 0x02, 0xfd, 0xfd, 0x01, 0xff, 0x01, 0xff, 0xfd, 0xed, 0xec, + 0xed, 0xf5, 0xfd, 0x05, 0xfd, 0xfa, 0xfb, 0xff, 0x0a, 0x14, 0x14, 0x0e, + 0x09, 0x0d, 0x1b, 0x14, 0x10, 0x10, 0x0a, 0x07, 0x0b, 0x0d, 0x02, 0x06, + 0x0a, 0x03, 0xfb, 0xf6, 0xfd, 0xf9, 0x01, 0x13, 0xfd, 0xf1, 0xfa, 0x02, + 0xff, 0xfe, 0xfe, 0xff, 0xfa, 0x07, 0x18, 0x13, 0x07, 0x02, 0x12, 0x13, + 0x16, 0x17, 0x06, 0xff, 0xfe, 0xfa, 0xfa, 0xf7, 0xf6, 0xfa, 0x00, 0x14, + 0x0e, 0x0d, 0x05, 0x00, 0xff, 0x02, 0x03, 0xfe, 0xf5, 0xe9, 0xf1, 0xf9, + 0x0a, 0x0b, 0xfb, 0xfa, 0x0b, 0x18, 0x17, 0x0d, 0x00, 0x02, 0xfe, 0x05, + 0x0f, 0x0e, 0x0d, 0x17, 0x17, 0x17, 0x12, 0x0e, 0x06, 0xf2, 0xf6, 0xfd, + 0xf0, 0xe1, 0xe8, 0xf3, 0xf0, 0xf7, 0x01, 0x00, 0x0a, 0x13, 0x0b, 0x03, + 0x06, 0x05, 0x03, 0x00, 0x09, 0x12, 0x16, 0x1f, 0x25, 0x1d, 0x16, 0x13, + 0x07, 0x09, 0x06, 0x05, 0xf9, 0xf9, 0xfb, 0xf6, 0xf1, 0xf5, 0xff, 0xf6, + 0xfd, 0xff, 0xf5, 0xf7, 0x02, 0x03, 0xfa, 0xfb, 0xf5, 0xff, 0x05, 0x0b, + 0x05, 0xfa, 0xf7, 0x0a, 0x0e, 0x07, 0x06, 0x0a, 0x13, 0x0f, 0x0b, 0x13, + 0x09, 0x03, 0x0a, 0x0e, 0x17, 0x17, 0x0e, 0x07, 0x03, 0x06, 0x05, 0x01, + 0x00, 0x00, 0x01, 0xff, 0x0a, 0x07, 0xff, 0xfd, 0xfe, 0xff, 0xfe, 0xfa, + 0xf3, 0xf1, 0xf3, 0x06, 0x06, 0x0e, 0x0d, 0x10, 0x16, 0x17, 0x0e, 0xfd, + 0xf3, 0xf1, 0xec, 0xed, 0xfa, 0xfd, 0x03, 0x0b, 0x10, 0x12, 0x12, 0x0f, + 0x0a, 0x06, 0x01, 0x00, 0x01, 0xfd, 0xfb, 0x0a, 0x0a, 0x05, 0x09, 0x03, + 0x06, 0x06, 0x02, 0x0b, 0x03, 0x00, 0xfb, 0x02, 0x09, 0x09, 0x07, 0x0b, + 0x09, 0x09, 0x0f, 0x13, 0x09, 0x0d, 0x0b, 0x05, 0xff, 0xf6, 0xf2, 0xf5, + 0xf7, 0xf2, 0xf9, 0xfe, 0x02, 0x0a, 0x07, 0x05, 0x05, 0x05, 0x01, 0xfd, + 0xff, 0xff, 0x0a, 0x07, 0x0b, 0x13, 0x14, 0x13, 0x0f, 0x06, 0x05, 0x05, + 0xf7, 0xf6, 0xf7, 0xfb, 0x03, 0xf7, 0xfb, 0x06, 0x0b, 0x14, 0x09, 0x03, + 0xfb, 0x00, 0xff, 0xfb, 0x02, 0x07, 0x10, 0x07, 0xfd, 0xfa, 0xf5, 0xfd, + 0x00, 0xfe, 0x00, 0xff, 0x06, 0x0e, 0x13, 0x13, 0x1a, 0x0a, 0x0f, 0x0e, + 0x0f, 0x16, 0x0e, 0x0a, 0xff, 0xff, 0xff, 0xfe, 0x03, 0x01, 0x05, 0xfb, + 0xf9, 0xfd, 0x02, 0x0b, 0x07, 0xf5, 0xfb, 0xff, 0xf3, 0xea, 0xea, 0xee, + 0xfa, 0x02, 0x12, 0x0f, 0x1f, 0x29, 0x1c, 0x10, 0x03, 0xfa, 0xf6, 0xf9, + 0x00, 0x01, 0xff, 0xfb, 0x02, 0x02, 0x09, 0x0e, 0x0d, 0x0d, 0x05, 0x00, + 0xfb, 0xf7, 0xfa, 0x00, 0x0d, 0x0b, 0x05, 0x06, 0x12, 0x1d, 0x07, 0x02, + 0x06, 0x06, 0x06, 0x12, 0x0d, 0x06, 0x0d, 0x07, 0x01, 0xff, 0xfd, 0x05, + 0x03, 0x03, 0x02, 0x00, 0xfb, 0xfe, 0xfa, 0xed, 0xe3, 0xec, 0xf6, 0xfe, + 0xfe, 0x02, 0x06, 0x06, 0x0b, 0x0f, 0x0e, 0x07, 0x06, 0x0e, 0x06, 0x05, + 0x09, 0x0d, 0x17, 0x20, 0x17, 0x18, 0x12, 0x0b, 0xfd, 0xf2, 0xf1, 0xf7, + 0xf9, 0xfb, 0xfb, 0xff, 0xff, 0x07, 0x06, 0x00, 0xf9, 0xf6, 0xf9, 0x03, + 0x12, 0x10, 0x0e, 0x18, 0x14, 0x0f, 0x06, 0xfb, 0xfd, 0xfe, 0xfd, 0xff, + 0xfd, 0x03, 0x0b, 0x07, 0x03, 0x07, 0x0a, 0x0e, 0x18, 0x13, 0x0d, 0x02, + 0xfb, 0xfd, 0xf6, 0xf6, 0xff, 0x03, 0xfa, 0xee, 0xf7, 0xfa, 0xf9, 0xfd, + 0x02, 0x0f, 0x12, 0x0a, 0x00, 0x00, 0xfe, 0xfa, 0xfb, 0xfe, 0x00, 0x05, + 0x1d, 0x2e, 0x2c, 0x1c, 0x13, 0x0b, 0xfd, 0xf3, 0xfe, 0xff, 0xff, 0xf7, + 0xf6, 0xf7, 0x00, 0x07, 0x0d, 0x0b, 0x0a, 0x09, 0xfe, 0xf9, 0xf7, 0xf2, + 0xf7, 0xfe, 0x09, 0x13, 0x18, 0x0b, 0x03, 0x02, 0x01, 0x02, 0x03, 0x0a, + 0x1b, 0x1d, 0x1b, 0x07, 0x03, 0x01, 0xfd, 0xf7, 0xf5, 0xf9, 0x00, 0x00, + 0x03, 0xfe, 0xf9, 0xfa, 0xf5, 0xf3, 0xf6, 0xf2, 0x00, 0x07, 0x03, 0x05, + 0x06, 0x02, 0x00, 0x0d, 0x16, 0x0e, 0x0f, 0x09, 0x06, 0x02, 0x02, 0x12, + 0x1b, 0x10, 0x16, 0x16, 0x06, 0x06, 0x06, 0x00, 0xf9, 0xf5, 0xfa, 0x03, + 0x0b, 0x0d, 0x10, 0x02, 0xfa, 0xfa, 0xfd, 0x02, 0xf9, 0xf5, 0x00, 0x06, + 0x05, 0x03, 0xfd, 0xfa, 0xf5, 0x00, 0x05, 0xff, 0xf6, 0xf3, 0xfd, 0x07, + 0x07, 0x0a, 0x09, 0x13, 0x24, 0x29, 0x23, 0x12, 0x07, 0x02, 0xfd, 0x00, + 0x00, 0x06, 0x03, 0xf5, 0xf6, 0xf6, 0xf2, 0xf9, 0xfe, 0x00, 0x00, 0x02, + 0x02, 0xff, 0xf6, 0xed, 0xea, 0xea, 0xfa, 0x0f, 0x1d, 0x27, 0x34, 0x2d, + 0x23, 0x20, 0x1b, 0x12, 0x0e, 0x0a, 0x0b, 0xff, 0xfb, 0xfb, 0xf5, 0xf2, + 0xf5, 0xfa, 0xfe, 0x01, 0x01, 0xfb, 0xfa, 0xf3, 0xfa, 0xfe, 0xf9, 0xf7, + 0x06, 0xfe, 0xff, 0x02, 0xfb, 0xf9, 0xff, 0x07, 0x1a, 0x1f, 0x1c, 0x1b, + 0x17, 0x16, 0x0b, 0x06, 0x07, 0x02, 0xff, 0x05, 0x01, 0x00, 0xfb, 0xf7, + 0xfb, 0xf6, 0xea, 0xee, 0x06, 0x0d, 0x03, 0xf7, 0xfe, 0x03, 0x10, 0x0f, + 0x0a, 0x01, 0xfb, 0x00, 0x0b, 0x0b, 0x00, 0xfd, 0x07, 0x18, 0x18, 0x17, + 0x0d, 0x09, 0x07, 0x01, 0xfd, 0xfa, 0xfb, 0xfe, 0x13, 0x1a, 0x10, 0x0a, + 0x0a, 0x06, 0x00, 0xf5, 0xee, 0xf2, 0xfe, 0xff, 0xfb, 0xff, 0x01, 0x03, + 0xfe, 0xf1, 0xee, 0xf2, 0xf7, 0xfe, 0x00, 0xff, 0xfe, 0xfb, 0x0b, 0x16, + 0x24, 0x2c, 0x25, 0x1a, 0x14, 0x1a, 0x14, 0x05, 0xff, 0xff, 0xff, 0xfa, + 0xfe, 0x09, 0x05, 0xfa, 0xf2, 0xfb, 0xff, 0x01, 0x03, 0xfe, 0xfe, 0xfe, + 0xfb, 0xf2, 0xee, 0xf6, 0x02, 0x0b, 0x13, 0x16, 0x14, 0x16, 0x18, 0x13, + 0x16, 0x0f, 0x0a, 0x09, 0x0a, 0x05, 0xfe, 0xf5, 0xf3, 0xf5, 0xfa, 0x02, + 0x02, 0xfe, 0x00, 0xfe, 0x01, 0xfd, 0xf6, 0xf7, 0x03, 0x07, 0x07, 0xfa, + 0xfe, 0x06, 0x06, 0x02, 0x05, 0x07, 0x0d, 0x09, 0x06, 0x0e, 0x12, 0x0a, + 0x03, 0x05, 0x02, 0x05, 0x0d, 0x09, 0x03, 0x02, 0x02, 0x01, 0xfe, 0xfa, + 0x0b, 0x0f, 0x14, 0x0d, 0x0e, 0x0f, 0x06, 0xfb, 0xf6, 0xf9, 0xf6, 0xf5, + 0xfb, 0xff, 0x03, 0x05, 0x03, 0x0f, 0x0a, 0x02, 0xf7, 0xf9, 0xfb, 0x01, + 0xfe, 0xf6, 0xfa, 0x03, 0x0e, 0x12, 0x14, 0x12, 0x13, 0x14, 0x0b, 0x0f, + 0x0a, 0x02, 0x00, 0x02, 0x05, 0x03, 0xff, 0xff, 0xfe, 0xf3, 0xe6, 0xed, + 0xf2, 0xf2, 0xf9, 0x05, 0x0a, 0x02, 0xfb, 0x09, 0x1c, 0x21, 0x17, 0x14, + 0x14, 0x18, 0x14, 0x0d, 0x0d, 0x0a, 0x03, 0xfb, 0xfe, 0xfb, 0xff, 0x01, + 0xfd, 0xff, 0x05, 0x00, 0x01, 0x00, 0x00, 0xff, 0xfd, 0xf6, 0xf2, 0xf3, + 0x02, 0x03, 0x03, 0x14, 0x24, 0x1a, 0x0e, 0x0a, 0x0b, 0x09, 0x06, 0x05, + 0x02, 0x01, 0xf9, 0xfa, 0xfb, 0xfd, 0xfb, 0xfb, 0x00, 0xff, 0xfd, 0x01, + 0x07, 0x05, 0x01, 0x06, 0x17, 0x10, 0xff, 0xfb, 0x03, 0x07, 0x07, 0x01, + 0x00, 0x02, 0x0a, 0x12, 0x0f, 0x16, 0x13, 0x0b, 0x07, 0x07, 0x0b, 0x07, + 0x05, 0xfb, 0xf2, 0xee, 0xec, 0xf2, 0xfe, 0x07, 0x09, 0x06, 0x06, 0x09, + 0x1a, 0x14, 0x0a, 0x09, 0x0d, 0x0a, 0xfd, 0xf9, 0xfa, 0xf9, 0xfb, 0xfa, + 0xfb, 0xfd, 0x06, 0x0d, 0x05, 0xf9, 0xf9, 0xff, 0x00, 0x05, 0xff, 0x06, + 0x18, 0x0d, 0x03, 0xff, 0x07, 0x0a, 0xff, 0x03, 0x0d, 0x0d, 0x0a, 0x13, + 0x0e, 0x03, 0x02, 0x09, 0x0a, 0x07, 0x06, 0xf9, 0xf7, 0xf9, 0xf9, 0xfd, + 0xfe, 0x05, 0x0d, 0x0d, 0x16, 0x0b, 0x03, 0x06, 0x1b, 0x20, 0x14, 0x0e, + 0x05, 0x02, 0xff, 0xfe, 0xf1, 0xe8, 0xec, 0xee, 0xee, 0xf6, 0x06, 0x02, + 0x00, 0xfe, 0xff, 0xfb, 0xfd, 0x03, 0x05, 0x0a, 0x13, 0x0d, 0x0a, 0x0b, + 0x12, 0x1b, 0x13, 0x0e, 0x0e, 0x09, 0x05, 0xfb, 0x01, 0x03, 0x06, 0x06, + 0x01, 0xfd, 0xfd, 0x00, 0xff, 0xf6, 0xf9, 0xf6, 0xf7, 0xfb, 0xff, 0x14, + 0x1b, 0x12, 0x07, 0xfe, 0x00, 0x02, 0x07, 0x09, 0x03, 0x01, 0x05, 0x03, + 0x0a, 0x0e, 0x09, 0x07, 0x06, 0x01, 0x01, 0x02, 0x05, 0x06, 0x09, 0x09, + 0xff, 0xfa, 0xfd, 0x01, 0x0e, 0x07, 0xf9, 0xf9, 0x02, 0x01, 0x00, 0x00, + 0x02, 0x09, 0x09, 0x02, 0xf7, 0xf2, 0xf9, 0x03, 0x06, 0x0a, 0x02, 0x03, + 0x0a, 0x09, 0x02, 0xfa, 0xfd, 0xfe, 0x00, 0x07, 0x18, 0x18, 0x0e, 0x09, + 0x14, 0x13, 0x0a, 0x09, 0x06, 0x02, 0x03, 0x03, 0x05, 0x01, 0xfe, 0xfe, + 0xf6, 0xee, 0xf9, 0x00, 0x01, 0xf3, 0xf2, 0xf6, 0x00, 0x07, 0x0e, 0x16, + 0x23, 0x20, 0x14, 0x0e, 0x0e, 0x07, 0x01, 0x09, 0x0e, 0x07, 0xff, 0xfd, + 0xf7, 0xf3, 0xf6, 0xf6, 0xf0, 0xf6, 0xf7, 0xfb, 0x00, 0xfb, 0xff, 0xfb, + 0xfa, 0xf3, 0xee, 0xfa, 0x0e, 0x14, 0x13, 0x0e, 0x12, 0x10, 0x1c, 0x2e, + 0x29, 0x17, 0x12, 0x14, 0x06, 0xff, 0x02, 0x00, 0x02, 0x02, 0x02, 0x00, + 0xfe, 0xfa, 0xfb, 0xf7, 0xf9, 0xf9, 0xff, 0x09, 0x09, 0x09, 0x05, 0xff, + 0x00, 0xf3, 0xea, 0xee, 0xf7, 0x00, 0x00, 0x01, 0xff, 0xfe, 0x0d, 0x0f, + 0x12, 0x0d, 0x0b, 0x0a, 0x06, 0x02, 0x05, 0x0a, 0x09, 0x07, 0x07, 0x07, + 0x09, 0x0f, 0x09, 0x01, 0xff, 0x07, 0x05, 0x05, 0x03, 0x0e, 0x07, 0x01, + 0xfe, 0xfb, 0xfe, 0xf9, 0xf2, 0xf6, 0xfe, 0x03, 0xfd, 0x03, 0x0d, 0x06, + 0xff, 0x05, 0x0f, 0x0b, 0x09, 0x13, 0x0e, 0x0d, 0x0f, 0x0d, 0x03, 0x02, + 0xff, 0x03, 0x01, 0xff, 0xf7, 0xfd, 0x0e, 0x0e, 0x05, 0x05, 0x05, 0x03, + 0xfe, 0xfa, 0xff, 0xf2, 0xf1, 0xf6, 0xf6, 0xf3, 0x00, 0x1b, 0x18, 0x16, + 0x12, 0x0f, 0x09, 0x0e, 0x0b, 0x0b, 0x0b, 0x09, 0x05, 0xff, 0xfb, 0xfa, + 0xf5, 0xf5, 0xf6, 0xf6, 0xf7, 0x02, 0x03, 0x03, 0x07, 0x06, 0x06, 0x03, + 0x06, 0x12, 0x0d, 0x0a, 0x09, 0x09, 0x05, 0xff, 0x02, 0x0b, 0x1a, 0x14, + 0x05, 0x06, 0x06, 0x00, 0x09, 0x03, 0x06, 0x05, 0x05, 0x06, 0x07, 0x06, + 0xfe, 0xf7, 0xfa, 0xfb, 0xfe, 0x09, 0x01, 0x01, 0xfb, 0x00, 0xfb, 0xf2, + 0xf6, 0xf7, 0xfd, 0x06, 0xff, 0xfa, 0xf7, 0xfa, 0x05, 0x02, 0x05, 0x05, + 0x07, 0x05, 0x07, 0x0d, 0x0b, 0x0e, 0x18, 0x18, 0x1c, 0x23, 0x24, 0x1c, + 0x0d, 0x07, 0xfe, 0xfb, 0x00, 0x02, 0x00, 0xff, 0xfe, 0xfe, 0x00, 0x01, + 0xfd, 0xfd, 0x02, 0xff, 0xf6, 0xf7, 0x00, 0xff, 0x00, 0xfe, 0xf5, 0xf5, + 0xf6, 0x09, 0x17, 0x0d, 0x05, 0x06, 0x12, 0x13, 0x0b, 0x06, 0x06, 0x05, + 0x00, 0xfe, 0xfb, 0xfe, 0x02, 0x02, 0x05, 0x02, 0xfd, 0xfe, 0x03, 0x02, + 0x02, 0x02, 0x02, 0x01, 0xff, 0x09, 0x14, 0x1b, 0x13, 0x0a, 0x0a, 0x0a, + 0x02, 0xfe, 0x01, 0x06, 0x05, 0x00, 0xff, 0x07, 0x0e, 0x06, 0xff, 0xfb, + 0xf6, 0xfb, 0xfe, 0xfe, 0xfe, 0xff, 0x00, 0x00, 0x02, 0x02, 0x07, 0x00, + 0x03, 0x06, 0x09, 0x0d, 0x0b, 0x0b, 0x0f, 0x18, 0x1a, 0x16, 0x0e, 0x03, + 0xfe, 0xf3, 0xf5, 0xf2, 0xf6, 0x00, 0x05, 0x02, 0xff, 0x09, 0x0e, 0x09, + 0x01, 0xfb, 0x06, 0x0d, 0x0a, 0x03, 0xfe, 0xfb, 0xfb, 0xf5, 0xf3, 0xf5, + 0xfb, 0xff, 0x02, 0x03, 0x0b, 0x0f, 0x14, 0x0f, 0x0b, 0x0d, 0x0a, 0x06, + 0x03, 0x02, 0x05, 0x01, 0x00, 0x01, 0x18, 0x20, 0x1a, 0x14, 0x0f, 0x18, + 0x03, 0xf9, 0xfe, 0x01, 0x00, 0x00, 0x01, 0x02, 0x00, 0xfe, 0xfd, 0x01, + 0xf6, 0xf2, 0xf3, 0xf5, 0xf3, 0xfa, 0x0d, 0x0a, 0x00, 0xfa, 0x00, 0x0d, + 0x0a, 0x07, 0xff, 0xfb, 0xfb, 0xf7, 0xff, 0x02, 0x12, 0x0f, 0x05, 0x01, + 0x07, 0x10, 0x13, 0x0d, 0x05, 0x05, 0x14, 0x14, 0x0e, 0x07, 0x06, 0x02, + 0xfa, 0xf7, 0xfb, 0x06, 0x09, 0x13, 0x0d, 0x0d, 0x0f, 0x05, 0x06, 0x00, + 0x05, 0x09, 0x06, 0x01, 0xfa, 0xf3, 0xf6, 0xf3, 0xf3, 0xf2, 0x00, 0xfe, + 0xfe, 0x00, 0x09, 0x0b, 0x05, 0x01, 0x02, 0x0a, 0x09, 0x06, 0x02, 0xfe, + 0xff, 0xfd, 0xff, 0x01, 0x03, 0x0f, 0x13, 0x14, 0x13, 0x13, 0x1a, 0x03, + 0xfd, 0x00, 0x06, 0x09, 0x00, 0xfb, 0xfe, 0x00, 0xfb, 0xff, 0xff, 0x0d, + 0x13, 0x0b, 0x06, 0x00, 0x03, 0x03, 0x02, 0x00, 0xf7, 0xfa, 0x03, 0x05, + 0xff, 0xf7, 0xf7, 0x00, 0x07, 0x0b, 0x09, 0x01, 0xff, 0x01, 0x0a, 0x10, + 0x09, 0x02, 0x09, 0x1b, 0x1f, 0x1c, 0x13, 0x05, 0x05, 0x03, 0xf9, 0xe6, + 0xf0, 0x02, 0x09, 0x05, 0x02, 0x01, 0xff, 0xff, 0xfd, 0x00, 0xfe, 0xfb, + 0xfa, 0xf9, 0xfa, 0xfd, 0x06, 0x02, 0x01, 0x01, 0x03, 0x06, 0x0b, 0x02, + 0x01, 0x17, 0x12, 0x0b, 0x0d, 0x0d, 0x10, 0x14, 0x0a, 0x00, 0xfa, 0xf7, + 0xfa, 0x00, 0x06, 0x12, 0x0f, 0x0b, 0x0d, 0x14, 0x13, 0x0f, 0xfd, 0xf2, + 0x05, 0x07, 0x03, 0xfe, 0xff, 0x03, 0x01, 0x06, 0x06, 0x06, 0x01, 0x01, + 0x00, 0x00, 0xfb, 0xff, 0xfe, 0x00, 0x02, 0x00, 0xfa, 0xf5, 0xf2, 0xee, + 0xed, 0xf6, 0xf9, 0xfd, 0x0d, 0x17, 0x0d, 0x06, 0x02, 0x0f, 0x0b, 0x09, + 0x09, 0x0b, 0x12, 0x1f, 0x23, 0x17, 0x13, 0x1a, 0x16, 0x07, 0xf6, 0xfa, + 0x00, 0xfe, 0xfd, 0xfe, 0x00, 0x03, 0x01, 0x05, 0x0b, 0x0b, 0x00, 0xf9, + 0xf1, 0xf9, 0xf9, 0xf7, 0xfa, 0xf7, 0x02, 0x0a, 0x07, 0x00, 0x00, 0x06, + 0x05, 0x03, 0x00, 0x09, 0x07, 0x02, 0x01, 0xff, 0x03, 0x03, 0xff, 0xfe, + 0x02, 0x12, 0x0d, 0x09, 0x07, 0x06, 0x14, 0x1c, 0x17, 0x02, 0xfb, 0x00, + 0x05, 0x07, 0xfb, 0xf9, 0xfa, 0xf6, 0xf7, 0x00, 0x0f, 0x0e, 0x07, 0x05, + 0x07, 0xff, 0x01, 0x0a, 0x06, 0x0b, 0x0f, 0x09, 0xfb, 0xf5, 0xfe, 0x07, + 0x02, 0xff, 0x05, 0x0b, 0x09, 0x06, 0xff, 0x00, 0x06, 0x05, 0x00, 0x03, + 0x09, 0x10, 0x0d, 0x07, 0x03, 0xff, 0xfe, 0x03, 0x00, 0xfa, 0x0e, 0x0d, + 0x01, 0xf9, 0xfe, 0x0f, 0x0e, 0x09, 0x0a, 0x0b, 0x01, 0xff, 0xfa, 0x00, + 0x03, 0xf7, 0xf5, 0xfe, 0x01, 0x01, 0xff, 0xf6, 0xf1, 0xf5, 0xfb, 0x05, + 0x0f, 0x14, 0x1b, 0x0f, 0x00, 0xf9, 0xf7, 0x02, 0x09, 0x07, 0x0e, 0x13, + 0x1a, 0x16, 0x1f, 0x20, 0x1c, 0x1b, 0x17, 0x0f, 0x06, 0xf5, 0xf2, 0xf2, + 0xf0, 0xf5, 0xfb, 0xf9, 0xf7, 0xf9, 0x02, 0x01, 0xfa, 0xf1, 0xee, 0xf9, + 0x07, 0x16, 0x10, 0x0b, 0x01, 0x00, 0x01, 0xfa, 0xf2, 0xf9, 0xf7, 0xf7, + 0xfb, 0x03, 0x17, 0x0b, 0x07, 0x12, 0x0f, 0x10, 0x0a, 0x09, 0x0b, 0x0d, + 0x07, 0x05, 0x05, 0x0e, 0x1b, 0x1a, 0x14, 0x12, 0x00, 0xf3, 0xf7, 0xfb, + 0x00, 0x01, 0xff, 0x07, 0x03, 0x02, 0x02, 0xfa, 0xfb, 0xfa, 0xfb, 0xf5, + 0xee, 0xfb, 0x06, 0x16, 0x17, 0x0b, 0x01, 0x01, 0xff, 0x0b, 0x07, 0x09, + 0x06, 0x00, 0xff, 0x00, 0x02, 0x02, 0x00, 0xfb, 0x01, 0xfd, 0xfb, 0xfa, + 0x03, 0x0a, 0x0a, 0x06, 0x0a, 0x14, 0x16, 0x18, 0x09, 0xf9, 0xf1, 0xf1, + 0xfa, 0x07, 0x12, 0x0f, 0x0d, 0x13, 0x12, 0x0f, 0x10, 0x10, 0x0d, 0x02, + 0xff, 0xfa, 0xf7, 0xf2, 0xf7, 0xf7, 0x00, 0xfe, 0xf0, 0xf2, 0xf5, 0x00, + 0x09, 0x02, 0xfb, 0xf7, 0xfe, 0x0b, 0x16, 0x1f, 0x1a, 0x0f, 0x0d, 0x09, + 0x07, 0x13, 0x0e, 0x10, 0x13, 0x0b, 0x07, 0x0b, 0xfe, 0xf6, 0xfa, 0x00, + 0xff, 0xf9, 0xf6, 0xf5, 0xfd, 0xfa, 0xf1, 0xf3, 0xfd, 0xfe, 0xff, 0x06, + 0x03, 0x03, 0x00, 0x05, 0x05, 0x0a, 0x0b, 0x0d, 0x01, 0x02, 0x06, 0x0a, + 0x07, 0x10, 0x09, 0x07, 0x02, 0x00, 0x00, 0x01, 0x0a, 0x1b, 0x14, 0x0b, + 0x0f, 0x14, 0x17, 0x1b, 0x13, 0x09, 0x00, 0xfd, 0xed, 0xf2, 0xf9, 0xf9, + 0xf7, 0xfa, 0xf7, 0xf9, 0xfb, 0xfa, 0xf7, 0x00, 0x03, 0x02, 0x00, 0x01, + 0x05, 0x17, 0x07, 0x03, 0x01, 0xfe, 0x00, 0x03, 0x02, 0x00, 0xfd, 0x0a, + 0x0b, 0x06, 0x07, 0x0d, 0x0a, 0x05, 0x01, 0x01, 0x00, 0x00, 0x02, 0x03, + 0x0b, 0x09, 0x0b, 0x0e, 0x0e, 0x16, 0x0e, 0xff, 0xf2, 0xfe, 0x03, 0x06, + 0x12, 0x20, 0x1a, 0x10, 0x0a, 0x02, 0x01, 0x00, 0xfd, 0xf7, 0xf9, 0xf5, + 0xf2, 0xfd, 0xff, 0xfd, 0x00, 0x06, 0x03, 0xf3, 0xe4, 0xea, 0xfa, 0x00, + 0x05, 0x09, 0x05, 0x07, 0x0f, 0x17, 0x0f, 0x0e, 0x0d, 0x0b, 0x0e, 0x10, + 0x18, 0x16, 0x12, 0x10, 0x0e, 0x0a, 0x07, 0xfa, 0xe9, 0xf5, 0xf3, 0xf6, + 0xf3, 0xf3, 0xfe, 0x0b, 0x07, 0x03, 0x07, 0x12, 0x0b, 0x0b, 0x05, 0x00, + 0x00, 0x00, 0x03, 0x05, 0x03, 0x09, 0x09, 0x00, 0xf6, 0xfb, 0xfe, 0x00, + 0x09, 0x0e, 0x07, 0x00, 0x00, 0x07, 0x0b, 0x14, 0x0b, 0x07, 0x07, 0x07, + 0x01, 0x07, 0x0e, 0x10, 0x0e, 0x12, 0x0a, 0xf9, 0xf5, 0xfb, 0xf7, 0xf0, + 0xf6, 0xfb, 0xf9, 0xf7, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x07, + 0x0b, 0x0a, 0x0b, 0x10, 0x10, 0x0b, 0x16, 0x0a, 0x05, 0x02, 0x0b, 0x0d, + 0x03, 0xf9, 0xf7, 0xfb, 0xff, 0x00, 0x00, 0x0a, 0x06, 0x05, 0x0f, 0x10, + 0x0b, 0x01, 0xfe, 0x02, 0x0b, 0x07, 0x06, 0xfd, 0xfe, 0x01, 0x01, 0x07, + 0x0f, 0x0d, 0x09, 0x09, 0x06, 0x00, 0xfe, 0x00, 0x02, 0x0a, 0x05, 0xfd, + 0xf6, 0xf2, 0xf6, 0xf9, 0xf1, 0xf1, 0xf0, 0xe8, 0xf6, 0x07, 0x07, 0x0e, + 0x14, 0x0f, 0x0a, 0x13, 0x12, 0x13, 0x0f, 0x10, 0x13, 0x0e, 0x0f, 0x0d, + 0x13, 0x0f, 0x12, 0x13, 0x09, 0x03, 0x00, 0xf7, 0xf3, 0xf3, 0xf7, 0x00, + 0x05, 0x0f, 0x0a, 0x03, 0xfe, 0xf9, 0xf5, 0x02, 0x02, 0x00, 0xfd, 0x0a, + 0x03, 0x03, 0x02, 0x00, 0x00, 0x06, 0xff, 0xf5, 0xf6, 0xfa, 0xff, 0x09, + 0x13, 0x05, 0x00, 0x02, 0x07, 0x18, 0x14, 0x0d, 0x0d, 0x0f, 0x0d, 0x10, + 0x12, 0x18, 0x0b, 0x07, 0x05, 0xfe, 0xf6, 0xe3, 0xdf, 0xf0, 0xf7, 0xff, + 0x00, 0x05, 0x05, 0x01, 0x00, 0x03, 0x09, 0x09, 0x01, 0x03, 0x0b, 0x0e, + 0x0e, 0x13, 0x12, 0x0f, 0x1a, 0x13, 0x06, 0xfe, 0x03, 0x05, 0xfd, 0xf7, + 0xf6, 0xfd, 0x00, 0x05, 0x02, 0x02, 0xfa, 0xf6, 0xf3, 0xfb, 0xfd, 0xff, + 0xff, 0xff, 0x0e, 0x1c, 0x18, 0x1b, 0x10, 0x00, 0x01, 0x03, 0x00, 0x05, + 0x0d, 0x0a, 0x07, 0x03, 0x01, 0x01, 0x00, 0x01, 0x03, 0x02, 0xfa, 0xf5, + 0xec, 0xf2, 0xfa, 0xfb, 0x02, 0x00, 0x00, 0x09, 0x00, 0x02, 0x0e, 0x0d, + 0x0a, 0x0e, 0x10, 0x0a, 0x09, 0x1a, 0x1b, 0x10, 0x07, 0x07, 0x0a, 0x0e, + 0x0b, 0x03, 0x01, 0x03, 0x00, 0xff, 0xfd, 0xf2, 0xf2, 0xf9, 0x00, 0x07, + 0x02, 0x00, 0x05, 0x00, 0x00, 0x06, 0x10, 0x0e, 0x03, 0x02, 0x02, 0xf9, + 0xf2, 0xf5, 0xf9, 0xfe, 0x00, 0xfb, 0xf7, 0x00, 0x01, 0xfa, 0xf9, 0x0a, + 0x13, 0x0a, 0x05, 0x13, 0x20, 0x18, 0x17, 0x16, 0x14, 0x1a, 0x14, 0x0f, + 0x05, 0x00, 0x06, 0x06, 0xfd, 0xfb, 0xfb, 0xee, 0xfa, 0x05, 0x06, 0x01, + 0xff, 0xf5, 0xf2, 0xf6, 0xf9, 0xfd, 0xfe, 0xfe, 0x0d, 0x0d, 0x0a, 0x13, + 0x10, 0x0f, 0x13, 0x0e, 0x07, 0x00, 0xff, 0xfe, 0xfe, 0x03, 0x00, 0xfe, + 0x01, 0x01, 0x00, 0xfe, 0xfd, 0xfd, 0xf5, 0xf7, 0x02, 0x10, 0x13, 0x0b, + 0x13, 0x1a, 0x0f, 0x06, 0x05, 0x10, 0x0a, 0xfb, 0xfe, 0xfd, 0xfb, 0x0d, + 0x0a, 0x0a, 0x07, 0x05, 0x05, 0x02, 0x05, 0x05, 0x01, 0xf9, 0xf5, 0xf9, + 0xfb, 0xff, 0x00, 0xff, 0xf7, 0x05, 0x01, 0xfe, 0x06, 0x13, 0x13, 0x16, + 0x0f, 0x0a, 0x06, 0x02, 0x00, 0x00, 0xff, 0xfe, 0xfe, 0x01, 0xff, 0x06, + 0x00, 0x0b, 0x0f, 0x09, 0x0a, 0x0a, 0x02, 0xf7, 0xfd, 0x06, 0x0d, 0x02, + 0x09, 0x10, 0x0d, 0x07, 0x03, 0x01, 0xf9, 0xf9, 0x00, 0xfb, 0xfb, 0xfe, + 0x00, 0x09, 0x00, 0xf7, 0xf6, 0x00, 0xfd, 0xf5, 0xf3, 0xfd, 0x09, 0x16, + 0x0d, 0x0e, 0x1a, 0x1c, 0x27, 0x29, 0x20, 0x13, 0x12, 0x0a, 0xfe, 0xfa, + 0xfd, 0xfb, 0xfb, 0xfe, 0x00, 0x00, 0xf7, 0xf3, 0xf9, 0xf9, 0xf5, 0xf9, + 0xfa, 0xfd, 0x03, 0x05, 0x0b, 0x0e, 0x14, 0x0e, 0x07, 0x07, 0x0d, 0x0f, + 0x07, 0x07, 0x01, 0xf6, 0xf7, 0x03, 0x02, 0x00, 0xfb, 0xfe, 0xff, 0xfb, + 0xfa, 0xf9, 0xff, 0x01, 0x00, 0x00, 0x07, 0x0d, 0x0d, 0x07, 0x0d, 0x16, + 0x0e, 0x16, 0x1b, 0x16, 0x1d, 0x1c, 0x0b, 0xfa, 0xf7, 0xfb, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xfe, 0xf3, 0xf1, 0x00, 0xfd, 0xf6, 0xf9, 0xfb, + 0xf3, 0xf6, 0xf5, 0x09, 0x0b, 0x09, 0x17, 0x18, 0x17, 0x10, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x07, 0x0f, 0x12, 0x0a, 0x03, 0xff, 0x05, 0x09, + 0x03, 0x00, 0x00, 0x07, 0x0a, 0x07, 0xf9, 0xf9, 0x03, 0x0f, 0x16, 0x06, + 0x01, 0x01, 0x01, 0xfe, 0xf9, 0x00, 0x09, 0x05, 0x00, 0x00, 0xfe, 0xfb, + 0xf6, 0xf3, 0xf3, 0xfe, 0x01, 0xfd, 0x00, 0x07, 0x02, 0x05, 0x0f, 0x10, + 0x1c, 0x23, 0x21, 0x1a, 0x12, 0x09, 0x02, 0xfe, 0xf9, 0xf6, 0xfe, 0x07, + 0x05, 0x00, 0x00, 0x02, 0x07, 0x05, 0xf6, 0xfe, 0xfe, 0xfb, 0xfe, 0x00, + 0xfd, 0xfe, 0x00, 0x02, 0x0f, 0x17, 0x12, 0x0a, 0x0d, 0x0d, 0x14, 0x06, + 0x00, 0xfb, 0x00, 0x01, 0x00, 0xf6, 0xf3, 0xf6, 0xf7, 0xfd, 0xfe, 0xfd, + 0xfd, 0x07, 0x06, 0x02, 0x0a, 0x07, 0x06, 0x0a, 0x0d, 0x20, 0x1c, 0x0a, + 0x0a, 0x0d, 0x0e, 0x12, 0x0e, 0x00, 0xf1, 0xf1, 0xf6, 0x06, 0x09, 0x07, + 0x09, 0x0b, 0x09, 0x07, 0x03, 0xfd, 0xf9, 0xf3, 0xf3, 0xf1, 0xf0, 0xed, + 0xf3, 0x0d, 0x16, 0x1a, 0x10, 0x06, 0x03, 0x06, 0x00, 0xfd, 0xff, 0xfe, + 0x02, 0x05, 0x07, 0x0a, 0x05, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x0f, 0x0f, + 0x12, 0x1a, 0x1f, 0x1a, 0x0f, 0x0d, 0x10, 0x06, 0xfe, 0xfe, 0xf9, 0xf7, + 0xfb, 0xf7, 0xf9, 0xfb, 0xfb, 0x03, 0x00, 0xf7, 0xf6, 0xf9, 0xf2, 0xec, + 0xf3, 0x00, 0x05, 0x00, 0x01, 0x02, 0x00, 0x01, 0x07, 0x1c, 0x32, 0x25, + 0x21, 0x20, 0x1f, 0x14, 0x0a, 0x02, 0x00, 0x00, 0xfb, 0xf9, 0xf6, 0xf9, + 0xf6, 0x00, 0x0a, 0x07, 0x02, 0xf5, 0xf3, 0xfe, 0xf3, 0xf6, 0xfe, 0x00, + 0x00, 0x05, 0x21, 0x1c, 0x0f, 0x09, 0x07, 0x05, 0x03, 0x02, 0xf9, 0xfb, + 0x00, 0x0d, 0x0b, 0x02, 0xfe, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xfe, 0xfb, + 0xfe, 0x05, 0x00, 0x00, 0x01, 0x07, 0x1a, 0x1f, 0x12, 0x0f, 0x07, 0x0d, + 0x12, 0x14, 0x0d, 0x05, 0x00, 0xf6, 0xf9, 0xf9, 0x00, 0x05, 0x02, 0x05, + 0x02, 0x00, 0x05, 0x07, 0xff, 0x01, 0x00, 0xfb, 0xf6, 0xf1, 0x00, 0x0d, + 0x0d, 0x07, 0x02, 0x00, 0xfe, 0xfe, 0xfb, 0xf9, 0xfb, 0x00, 0x05, 0x07, + 0x02, 0x0d, 0x07, 0x05, 0x00, 0x00, 0x00, 0x05, 0x14, 0x0d, 0x05, 0x0b, + 0x16, 0x1c, 0x1c, 0x24, 0x1b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0xfb, 0xfe, 0x00, 0xfa, 0xf3, 0xe6, 0xec, 0xf0, 0xf1, + 0x07, 0x05, 0x00, 0x00, 0xfe, 0x05, 0x06, 0x17, 0x27, 0x1a, 0x0d, 0x0e, + 0x0d, 0x07, 0x05, 0x05, 0x05, 0x0d, 0x03, 0x00, 0x02, 0x02, 0x07, 0x0d, + 0x14, 0x0f, 0x0a, 0x05, 0xf7, 0xf6, 0xf3, 0xf1, 0xf9, 0x02, 0x02, 0x01, + 0x0d, 0x07, 0x07, 0x00, 0x05, 0x05, 0xfe, 0xf6, 0xf9, 0xf9, 0xfb, 0x02, + 0x05, 0x05, 0x05, 0x02, 0x00, 0x00, 0x02, 0x03, 0x00, 0x0d, 0x0f, 0x0a, + 0x07, 0x10, 0x0f, 0x0d, 0x1a, 0x12, 0x06, 0x02, 0x02, 0x00, 0x02, 0x05, + 0x02, 0xfe, 0xfd, 0xfb, 0xf7, 0xff, 0x02, 0x0a, 0x03, 0x00, 0xfe, 0xfb, + 0xfe, 0x05, 0x00, 0xff, 0x07, 0x0d, 0xfb, 0xfb, 0x0d, 0x13, 0x0d, 0x07, + 0x03, 0x02, 0x02, 0x00, 0x00, 0xfe, 0xfe, 0xfe, 0xff, 0x00, 0x05, 0x00, + 0xfe, 0xfb, 0xfd, 0x00, 0x00, 0x0d, 0x17, 0x1a, 0x14, 0x1a, 0x14, 0x12, + 0x1a, 0x21, 0x1a, 0x00, 0xf6, 0xf7, 0xfa, 0xfe, 0x0a, 0x0d, 0x00, 0xfb, + 0xfe, 0x05, 0x07, 0x00, 0xf6, 0xee, 0xee, 0xf1, 0xf0, 0xfb, 0xfb, 0xfb, + 0x00, 0x01, 0xfe, 0xf9, 0xfb, 0x07, 0x0f, 0x1f, 0x1a, 0x12, 0x0f, 0x0a, + 0x05, 0x02, 0x03, 0x01, 0x01, 0x01, 0x09, 0x0e, 0x0b, 0x10, 0x13, 0x0e, + 0x0b, 0x13, 0x06, 0xf5, 0x03, 0x09, 0x06, 0x03, 0x03, 0x0b, 0x06, 0x06, + 0xfd, 0xf7, 0xfb, 0xf6, 0xf0, 0xf0, 0xfa, 0xf2, 0xf2, 0x0a, 0x13, 0x0e, + 0x03, 0x00, 0xfd, 0xfd, 0xf7, 0xfd, 0x03, 0x03, 0x0d, 0x0b, 0x0d, 0x13, + 0x0b, 0x17, 0x1c, 0x1b, 0x10, 0x06, 0x06, 0x09, 0x09, 0x03, 0x06, 0x0d, + 0x09, 0x06, 0xfa, 0xf2, 0xf5, 0xfb, 0xfd, 0xf7, 0xf1, 0xf2, 0x01, 0x18, + 0x1d, 0x0b, 0xf2, 0xf2, 0xf2, 0x03, 0x09, 0x09, 0x03, 0xff, 0x01, 0x09, + 0x13, 0x0d, 0x06, 0x03, 0x02, 0x06, 0x0b, 0x0d, 0x07, 0x01, 0xfe, 0xfe, + 0xff, 0x03, 0x03, 0x09, 0x10, 0x16, 0x0e, 0x06, 0x01, 0x03, 0x13, 0x10, + 0x20, 0x13, 0xf6, 0xf7, 0x02, 0x01, 0xff, 0xfb, 0xf2, 0xf2, 0xff, 0x02, + 0xf7, 0xfd, 0x02, 0x00, 0x02, 0x03, 0xfd, 0x01, 0x03, 0x00, 0x00, 0xfd, + 0xfd, 0xfd, 0x0b, 0x09, 0x0e, 0x09, 0x01, 0x01, 0x03, 0x09, 0x0b, 0x03, + 0x00, 0x09, 0x25, 0x23, 0x13, 0x09, 0x06, 0x03, 0x09, 0x0b, 0x06, 0x10, + 0x13, 0x05, 0x03, 0x07, 0x06, 0x01, 0x05, 0x05, 0x01, 0x00, 0xfb, 0xf1, + 0xf6, 0xee, 0xec, 0xf6, 0x00, 0xfd, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xf6, + 0xf6, 0xf7, 0xfe, 0x0f, 0x1a, 0x14, 0x0f, 0x07, 0x05, 0x02, 0x0d, 0x0e, + 0x09, 0x0f, 0x0a, 0x12, 0x17, 0x14, 0x0f, 0x09, 0x07, 0x07, 0x07, 0x0a, + 0x07, 0xf9, 0xf9, 0xfb, 0x05, 0x00, 0x00, 0x02, 0x03, 0x02, 0xfe, 0xf9, + 0xf2, 0xf3, 0xf7, 0x00, 0x00, 0x0a, 0x07, 0xfe, 0xfe, 0x02, 0x02, 0x00, + 0x00, 0xfe, 0x00, 0x03, 0x0f, 0x0a, 0x00, 0xff, 0x02, 0x06, 0x0d, 0x0f, + 0x0d, 0x0b, 0x07, 0x0d, 0x07, 0x02, 0x01, 0x12, 0x14, 0x1c, 0x12, 0x0d, + 0x00, 0xf5, 0xf6, 0xf6, 0xf1, 0xf1, 0xfb, 0x09, 0x02, 0x00, 0xfb, 0xf6, + 0xf6, 0xff, 0x0f, 0x07, 0x00, 0x07, 0x07, 0x02, 0x00, 0x00, 0x00, 0x07, + 0x05, 0x05, 0x07, 0x0d, 0x09, 0x05, 0x00, 0x02, 0x09, 0x0a, 0x10, 0x14, + 0x0f, 0x0a, 0x02, 0xff, 0x00, 0xfe, 0x0a, 0x09, 0x0f, 0x18, 0x0d, 0x01, + 0xfb, 0xfb, 0xfd, 0x02, 0xfe, 0xf6, 0xfe, 0xfb, 0xfd, 0xf6, 0xf1, 0xf5, + 0xfe, 0x02, 0x0d, 0x05, 0x01, 0xfe, 0xf9, 0xfb, 0x02, 0x0a, 0x17, 0x0f, + 0x07, 0x05, 0x05, 0x00, 0xfe, 0xf9, 0xf6, 0x07, 0x0f, 0x0d, 0x1c, 0x1a, + 0x14, 0x17, 0x0e, 0x07, 0x05, 0x05, 0x07, 0x0f, 0x0f, 0x0a, 0x02, 0xf6, + 0xfe, 0x0a, 0x0f, 0x06, 0x00, 0xf7, 0xf9, 0xfd, 0xfe, 0xf9, 0xf6, 0xfb, + 0x00, 0xfb, 0x00, 0xfe, 0xf3, 0xf3, 0xf3, 0xf3, 0xfb, 0xff, 0xfe, 0x02, + 0x10, 0x07, 0x00, 0x07, 0x0a, 0x0f, 0x0d, 0x0b, 0x0f, 0x0e, 0x0b, 0x09, + 0x0a, 0x14, 0x12, 0x12, 0x1c, 0x0f, 0x14, 0x1c, 0x18, 0x0f, 0xfb, 0xf3, + 0xfb, 0x01, 0xfe, 0xf5, 0xec, 0xf1, 0xf3, 0xf9, 0xf3, 0xfe, 0x00, 0x00, + 0x00, 0x07, 0x07, 0xfe, 0xfa, 0xfb, 0xfb, 0xfb, 0x02, 0x02, 0x09, 0x0b, + 0x0a, 0x10, 0x07, 0x02, 0x06, 0x0d, 0x12, 0x17, 0x12, 0x0d, 0x06, 0x07, + 0x06, 0x0a, 0x05, 0x02, 0x05, 0x07, 0x0a, 0x0f, 0x07, 0xf9, 0xf1, 0xf9, + 0x00, 0xf9, 0xf3, 0xfa, 0xf9, 0xfe, 0xfe, 0xf6, 0xf3, 0xfe, 0x02, 0x07, + 0x0f, 0x07, 0x02, 0x05, 0x0d, 0x17, 0x1a, 0x14, 0x0d, 0x07, 0x03, 0x00, + 0xfe, 0xfa, 0xf6, 0xfe, 0x07, 0x03, 0x09, 0x10, 0x0f, 0x07, 0x07, 0x07, + 0x06, 0x00, 0x00, 0x02, 0x0b, 0x0b, 0x0a, 0x0a, 0x05, 0xf9, 0xf9, 0x07, + 0x0d, 0x01, 0xf6, 0xf9, 0xfb, 0xfe, 0x00, 0x00, 0x05, 0x02, 0x03, 0x00, + 0x00, 0xfb, 0xf6, 0xf1, 0xf5, 0xfb, 0x00, 0x07, 0x0a, 0x05, 0x07, 0x07, + 0x12, 0x0a, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0f, 0x07, 0x05, 0x0d, 0x0f, + 0x17, 0x1f, 0x1a, 0x17, 0x20, 0x17, 0x14, 0x12, 0x00, 0xfb, 0xfd, 0xfe, + 0xee, 0xe9, 0xf3, 0xf3, 0xf6, 0xf6, 0xfb, 0x00, 0x00, 0x00, 0xfb, 0xf6, + 0xf1, 0xf0, 0xf0, 0xea, 0xf9, 0xfb, 0xfa, 0x02, 0x07, 0x00, 0x06, 0x0b, + 0x0d, 0x0f, 0x1a, 0x23, 0x1d, 0x1a, 0x18, 0x17, 0x1a, 0x14, 0x16, 0x12, + 0x12, 0x07, 0x0a, 0x07, 0x0a, 0x06, 0x03, 0xf2, 0xf9, 0x00, 0x00, 0xf1, + 0xf3, 0xf0, 0xea, 0xf1, 0xee, 0xee, 0xec, 0xf1, 0xf9, 0x0f, 0x0e, 0x09, + 0x0e, 0x06, 0x09, 0x17, 0x1d, 0x18, 0x10, 0x0b, 0x06, 0x00, 0x02, 0x02, + 0x0d, 0x0a, 0x00, 0xfb, 0x07, 0x0a, 0x05, 0x01, 0x02, 0x00, 0x00, 0x05, + 0x07, 0x05, 0x00, 0x05, 0x17, 0x07, 0xf9, 0xf1, 0xf3, 0xfe, 0xfb, 0xf9, + 0xf9, 0xfb, 0x00, 0x00, 0x14, 0x23, 0x14, 0x03, 0x0a, 0x07, 0xfe, 0x02, + 0x02, 0xfb, 0xfd, 0x02, 0x0d, 0x0d, 0x00, 0x01, 0x07, 0x00, 0x00, 0x00, + 0x06, 0x07, 0x01, 0xfd, 0x01, 0x01, 0xff, 0xfa, 0x10, 0x16, 0x0d, 0x0d, + 0x20, 0x20, 0x16, 0x16, 0x14, 0x07, 0x00, 0x00, 0x02, 0xf6, 0xf1, 0xf1, + 0xf9, 0xfe, 0x00, 0x00, 0x00, 0xfb, 0xf3, 0xfb, 0xfb, 0xf9, 0xf1, 0xec, + 0xf6, 0xfe, 0xfb, 0xfd, 0x00, 0x05, 0x00, 0x0a, 0x12, 0x06, 0x02, 0x0b, + 0x18, 0x1d, 0x1b, 0x1d, 0x1b, 0x14, 0x14, 0x20, 0x23, 0x18, 0x0b, 0x06, + 0x06, 0x0e, 0x0a, 0x05, 0x0b, 0x00, 0xf9, 0xf3, 0xea, 0xe3, 0xe8, 0xf1, + 0xee, 0xed, 0xee, 0xf9, 0xfd, 0xf9, 0xfb, 0x0a, 0x03, 0xff, 0xff, 0x00, + 0xfd, 0xfe, 0x0e, 0x12, 0x09, 0x02, 0xff, 0xff, 0x0e, 0x1c, 0x1b, 0x13, + 0x0f, 0x0d, 0x0f, 0x0e, 0x0d, 0x07, 0x07, 0x0f, 0x0f, 0x06, 0x07, 0x10, + 0x0f, 0x07, 0x05, 0x02, 0xf3, 0xf1, 0xfb, 0xf9, 0xea, 0xea, 0xf6, 0xf2, + 0xfe, 0x03, 0x01, 0x01, 0x0d, 0x02, 0x01, 0x02, 0x01, 0x01, 0x0a, 0x0d, + 0x09, 0x0b, 0x07, 0x0e, 0x0f, 0x0d, 0x10, 0x0b, 0x06, 0x02, 0x00, 0xfd, + 0xf7, 0xf7, 0xf6, 0xf6, 0x00, 0x0f, 0x12, 0x10, 0x0b, 0x0d, 0x0f, 0x0d, + 0x0d, 0x0f, 0x0a, 0xff, 0xf6, 0x00, 0xfb, 0xed, 0xf3, 0xf9, 0x03, 0x0f, + 0x0d, 0x0b, 0x06, 0x00, 0xfe, 0x00, 0xfe, 0xff, 0x05, 0x05, 0xfd, 0xfe, + 0xfd, 0xfb, 0xfe, 0xfe, 0x01, 0x07, 0x07, 0x06, 0x0a, 0x10, 0x0b, 0x12, + 0x16, 0x12, 0x0f, 0x0b, 0x0a, 0x07, 0x0d, 0x16, 0x0f, 0x0a, 0x06, 0x06, + 0x10, 0x1b, 0x01, 0x00, 0xf9, 0xed, 0xe6, 0xe8, 0xf1, 0xf6, 0xf9, 0xf5, + 0xf1, 0xf1, 0xf0, 0xf6, 0x0d, 0x02, 0x00, 0x00, 0x02, 0xfe, 0x01, 0x02, + 0x06, 0x09, 0x05, 0x00, 0x0d, 0x0f, 0x0a, 0x13, 0x1d, 0x14, 0x10, 0x0d, + 0x0b, 0x0e, 0x18, 0x18, 0x13, 0x0f, 0x0e, 0x0d, 0x0d, 0x0a, 0x0e, 0x0e, + 0x06, 0xf5, 0xf1, 0xf5, 0xf1, 0xe5, 0xe4, 0xea, 0xfb, 0x02, 0x05, 0x07, + 0x0b, 0x02, 0xfe, 0xfe, 0xfd, 0xfb, 0xfb, 0xfb, 0xf6, 0xfe, 0x02, 0xfd, + 0x05, 0x03, 0x03, 0x09, 0x16, 0x14, 0x12, 0x0e, 0x06, 0x00, 0x00, 0x01, + 0x0e, 0x10, 0x16, 0x1a, 0x10, 0x0e, 0x07, 0x0e, 0x10, 0x17, 0x17, 0x12, + 0x01, 0xfe, 0xf9, 0xf2, 0xf6, 0xf0, 0xf3, 0xf2, 0xf5, 0xf5, 0xf9, 0x00, + 0xf9, 0xf3, 0xf6, 0xf9, 0x03, 0x10, 0x10, 0x07, 0x01, 0x05, 0x01, 0x02, + 0x07, 0x17, 0x20, 0x13, 0x09, 0x02, 0x05, 0x01, 0x05, 0x0a, 0x0f, 0x0b, + 0x0d, 0x0e, 0x0a, 0x03, 0x01, 0x00, 0x00, 0x00, 0x0a, 0x0e, 0x0a, 0xf7, + 0xfd, 0xfb, 0xf6, 0xf3, 0xf2, 0xf5, 0xfb, 0x02, 0xff, 0xfa, 0x00, 0x00, + 0x05, 0x13, 0x0d, 0x0d, 0x0d, 0x0a, 0x07, 0xfb, 0xfa, 0xfe, 0x00, 0x02, + 0x10, 0x10, 0x10, 0x13, 0x0e, 0x0a, 0x05, 0x01, 0x06, 0x06, 0x02, 0x01, + 0xfe, 0x09, 0x16, 0x0b, 0x0a, 0x10, 0x0b, 0x0a, 0x0b, 0x0f, 0x00, 0xf7, + 0x00, 0xfd, 0xf1, 0xe9, 0xfd, 0x01, 0x00, 0xfb, 0xfd, 0x00, 0xfe, 0xfd, + 0x07, 0x05, 0x03, 0x03, 0x01, 0xfb, 0xf7, 0xf3, 0xf6, 0x01, 0xff, 0xfb, + 0x00, 0x05, 0x0f, 0x17, 0x0b, 0x06, 0x01, 0x03, 0x17, 0x1b, 0x1a, 0x21, + 0x24, 0x1d, 0x16, 0x0a, 0x0b, 0x14, 0x17, 0x0e, 0x0b, 0xf7, 0xf3, 0xee, + 0xf0, 0xfe, 0x00, 0xf2, 0xf3, 0x00, 0xfe, 0xf7, 0xf3, 0xed, 0xe9, 0xed, + 0x00, 0xff, 0xfb, 0xfe, 0x0a, 0x00, 0xfd, 0xfb, 0x00, 0x01, 0x10, 0x12, + 0x14, 0x0b, 0x0e, 0x14, 0x0d, 0x13, 0x12, 0x13, 0x14, 0x16, 0x0e, 0x07, + 0x07, 0x07, 0x00, 0xff, 0x13, 0x1c, 0x18, 0x0a, 0xfd, 0xf2, 0xf2, 0xf6, + 0xfb, 0xf6, 0xea, 0xe6, 0xe9, 0xf5, 0xf6, 0xf3, 0xf1, 0xff, 0x0f, 0x0b, + 0x02, 0x07, 0x0e, 0x0a, 0x0b, 0x05, 0x02, 0x09, 0x20, 0x21, 0x17, 0x12, + 0x16, 0x0e, 0x07, 0x01, 0x03, 0x03, 0x05, 0x05, 0x00, 0xfd, 0xf9, 0xfb, + 0xf6, 0xf7, 0x05, 0xff, 0xf9, 0x02, 0x0d, 0x00, 0xfb, 0x00, 0xfb, 0xfe, + 0x0e, 0x0a, 0xfb, 0x00, 0x0d, 0x07, 0x05, 0x06, 0x07, 0x0a, 0x0f, 0x0e, + 0x06, 0x00, 0xfd, 0xf7, 0xf6, 0xf6, 0x02, 0x00, 0x00, 0x07, 0x05, 0x01, + 0xff, 0x01, 0xfd, 0xfe, 0x0e, 0x0a, 0x05, 0x0b, 0x25, 0x20, 0x16, 0x12, + 0x0f, 0x0f, 0x0f, 0x10, 0x0e, 0x0a, 0x00, 0xf6, 0xf7, 0xfe, 0x05, 0x07, + 0x00, 0xf6, 0xed, 0xf0, 0xed, 0xe9, 0xe6, 0xf2, 0x06, 0x09, 0x0a, 0x05, + 0x01, 0xff, 0xf9, 0xf9, 0xf7, 0xfb, 0xfe, 0x02, 0x03, 0x0d, 0x0b, 0x0b, + 0x0b, 0x0a, 0x0b, 0x1f, 0x1c, 0x1c, 0x16, 0x16, 0x1a, 0x17, 0x12, 0x16, + 0x1f, 0x17, 0x0f, 0x0a, 0x05, 0xf5, 0xed, 0xf1, 0xf9, 0xf3, 0xf7, 0xfe, + 0xfb, 0xed, 0xe6, 0xea, 0xea, 0xe6, 0xf2, 0x02, 0xfe, 0xfd, 0x02, 0x09, + 0x03, 0xfd, 0xfe, 0x09, 0x1b, 0x13, 0x0e, 0x0e, 0x10, 0x16, 0x17, 0x1f, + 0x17, 0x10, 0x13, 0x13, 0x07, 0x00, 0xfb, 0xfb, 0xfb, 0xfa, 0xfe, 0xfe, + 0x09, 0x07, 0x03, 0x02, 0xfa, 0xf6, 0xfb, 0x02, 0x0d, 0x02, 0xfe, 0x02, + 0x09, 0xfb, 0xfe, 0x07, 0xff, 0xfd, 0x00, 0x07, 0x03, 0xff, 0xfe, 0x07, + 0x00, 0xfe, 0x01, 0x0a, 0x10, 0x09, 0x05, 0x03, 0x00, 0xfe, 0x01, 0x06, + 0x10, 0x0a, 0x0e, 0x0b, 0x0b, 0x12, 0x0e, 0x07, 0x02, 0x03, 0xff, 0xff, + 0xfb, 0x02, 0x0d, 0x00, 0xfa, 0xfa, 0xfd, 0x02, 0x0d, 0x0a, 0x07, 0x00, + 0xf7, 0xf9, 0xfb, 0x00, 0x0b, 0x09, 0x00, 0x00, 0x03, 0x01, 0xfe, 0xfe, + 0xfb, 0xfe, 0x00, 0x07, 0x0e, 0x05, 0x01, 0xfe, 0xfe, 0x00, 0xfe, 0xfe, + 0x02, 0x0a, 0x1b, 0x1b, 0x0f, 0x13, 0x18, 0x1b, 0x24, 0x20, 0x14, 0x0e, + 0x09, 0x06, 0x00, 0x00, 0xf9, 0xfd, 0xff, 0xfd, 0xf9, 0xf2, 0xee, 0xe9, + 0xdf, 0xe1, 0xe6, 0xf0, 0xfd, 0x0e, 0x07, 0x03, 0x01, 0x00, 0x00, 0xff, + 0x05, 0x09, 0x0d, 0x09, 0x12, 0x13, 0x14, 0x16, 0x17, 0x0f, 0x0f, 0x0f, + 0x12, 0x0d, 0x03, 0x00, 0x05, 0x0b, 0x09, 0x09, 0x07, 0x06, 0x06, 0x03, + 0x00, 0xf5, 0xf6, 0xff, 0x0a, 0x09, 0x09, 0x03, 0x03, 0x03, 0x03, 0xfe, + 0xf7, 0xf0, 0xf3, 0xfa, 0xfb, 0x01, 0xfe, 0xfd, 0x00, 0x00, 0xfa, 0xfb, + 0x00, 0x01, 0x0a, 0x05, 0xfe, 0x01, 0x03, 0x10, 0x24, 0x1f, 0x17, 0x13, + 0x0f, 0x0d, 0x13, 0x0e, 0x0d, 0x07, 0x05, 0x02, 0x02, 0x00, 0xfe, 0x00, + 0xf3, 0xea, 0xf1, 0xf1, 0xfb, 0x01, 0x09, 0x17, 0x0b, 0x0d, 0x09, 0x07, + 0x05, 0x00, 0x02, 0x01, 0xfd, 0xf5, 0xf7, 0xfb, 0x03, 0x05, 0x03, 0x05, + 0x02, 0x0b, 0x0a, 0x01, 0xfe, 0xfd, 0xfa, 0x00, 0x05, 0x03, 0x0a, 0x10, + 0x0b, 0x0b, 0x10, 0x10, 0x18, 0x0e, 0x09, 0x06, 0x0d, 0x09, 0x0d, 0x0e, + 0x03, 0x02, 0x00, 0x00, 0xfe, 0xf9, 0xf3, 0xf1, 0xed, 0xf1, 0xf7, 0xff, + 0xfa, 0x02, 0x02, 0x05, 0xff, 0xfa, 0xfb, 0x03, 0x10, 0x0a, 0x0d, 0x0d, + 0x0a, 0x0a, 0x0f, 0x10, 0x12, 0x0a, 0x06, 0x05, 0x03, 0x09, 0x0e, 0x0b, + 0x05, 0x05, 0x05, 0x07, 0x05, 0x03, 0xff, 0x00, 0x06, 0x05, 0xff, 0xfb, + 0x1b, 0x18, 0x0f, 0x06, 0x00, 0xff, 0xfa, 0xfd, 0xfe, 0xfb, 0xf7, 0xee, + 0xea, 0xfa, 0x02, 0x00, 0xfd, 0xfd, 0xfb, 0xfb, 0xf9, 0xfa, 0xfb, 0x0a, + 0x12, 0x0f, 0x0d, 0x0f, 0x1a, 0x16, 0x12, 0x0a, 0x05, 0x05, 0x05, 0x0e, + 0x1c, 0x1d, 0x1d, 0x17, 0x0b, 0x02, 0xff, 0x00, 0xfa, 0xf2, 0xe8, 0xea, + 0xea, 0xf5, 0x09, 0x0a, 0x06, 0x0a, 0x07, 0x0d, 0x0f, 0x05, 0x02, 0xfd, + 0xff, 0x02, 0x01, 0xfa, 0xfa, 0x00, 0x00, 0x00, 0xfe, 0xf9, 0xf9, 0x02, + 0x00, 0xfb, 0xfe, 0x00, 0x06, 0x13, 0x0f, 0x10, 0x0f, 0x10, 0x0f, 0x10, + 0x16, 0x14, 0x17, 0x14, 0x12, 0x0b, 0x09, 0x07, 0x02, 0xfe, 0xfa, 0xf9, + 0xee, 0xf1, 0xfd, 0xfb, 0xfb, 0xfd, 0xff, 0xfe, 0xfa, 0xfe, 0x03, 0x00, + 0xf9, 0xfb, 0x00, 0x00, 0x09, 0x09, 0x0f, 0x13, 0x06, 0x02, 0x03, 0x03, + 0xff, 0x0f, 0x17, 0x12, 0x0b, 0x0b, 0x0e, 0x09, 0x03, 0x03, 0x05, 0x00, + 0xfd, 0xfa, 0xf5, 0xfd, 0x01, 0x01, 0x06, 0x0b, 0x14, 0x12, 0x16, 0x0f, + 0x05, 0x01, 0xff, 0xfb, 0xfa, 0x03, 0x09, 0x03, 0x00, 0x03, 0xfa, 0xf3, + 0xe9, 0xf5, 0xfa, 0xf6, 0xf7, 0xfa, 0xfd, 0x05, 0x12, 0x0f, 0x0d, 0x12, + 0x16, 0x12, 0x06, 0x00, 0x01, 0x0e, 0x0a, 0x0a, 0x0b, 0x1a, 0x1d, 0x14, + 0x0d, 0x06, 0x01, 0xfb, 0xfb, 0xfd, 0x00, 0xfe, 0xf2, 0xf5, 0xfa, 0xfb, + 0xff, 0x09, 0x07, 0x09, 0x12, 0x10, 0x03, 0xff, 0x03, 0x07, 0x02, 0x01, + 0xf9, 0xf5, 0xfa, 0xf7, 0xf7, 0xf5, 0xfd, 0x00, 0x05, 0x06, 0x02, 0x05, + 0x07, 0x06, 0x02, 0x02, 0x06, 0x07, 0x09, 0x0d, 0x1f, 0x1f, 0x0f, 0x0a, + 0x1d, 0x29, 0x16, 0x07, 0x06, 0x03, 0x06, 0xfd, 0xff, 0xfe, 0xf7, 0xf9, + 0xf5, 0xf3, 0xf0, 0xea, 0xed, 0xf1, 0xf0, 0xf9, 0x0d, 0x0b, 0x09, 0x05, + 0x06, 0x0f, 0x0a, 0x02, 0x03, 0x06, 0x00, 0xfd, 0xfe, 0xff, 0x00, 0x0a, + 0x0d, 0x13, 0x17, 0x17, 0x0e, 0x09, 0x09, 0x09, 0x05, 0x05, 0x01, 0x00, + 0x00, 0x06, 0x02, 0x01, 0x05, 0x0f, 0xff, 0xfe, 0x02, 0x07, 0x05, 0xfe, + 0xff, 0x01, 0x01, 0x0a, 0x0a, 0x05, 0x00, 0xfd, 0xf5, 0xf2, 0xf6, 0xf9, + 0xf9, 0x01, 0xfd, 0xfb, 0x05, 0x0d, 0x06, 0x02, 0x06, 0x1a, 0x13, 0x09, + 0x09, 0x09, 0x07, 0x09, 0x05, 0x02, 0x02, 0x0f, 0x0d, 0x06, 0xfe, 0x05, + 0x05, 0x00, 0xfe, 0x00, 0xff, 0x00, 0xfe, 0xfe, 0xfd, 0x00, 0xfd, 0x02, + 0x0b, 0x24, 0x1d, 0x10, 0x0d, 0x0b, 0x0a, 0x07, 0xfb, 0xfa, 0xf6, 0xf1, + 0xf5, 0xf1, 0xf1, 0xf5, 0xf9, 0xfa, 0x02, 0x06, 0x05, 0xfe, 0xfe, 0xfd, + 0x05, 0x16, 0x14, 0x0e, 0x0d, 0x1d, 0x20, 0x14, 0x12, 0x10, 0x05, 0x07, + 0x0b, 0x12, 0x13, 0x0f, 0x13, 0x06, 0xff, 0xfb, 0xfe, 0xf7, 0xf0, 0xf1, + 0xf0, 0xf0, 0xf2, 0xf0, 0xee, 0xf6, 0x06, 0x06, 0x03, 0x0d, 0x14, 0x06, + 0x05, 0x00, 0x00, 0x09, 0x03, 0x01, 0x06, 0x0a, 0x07, 0x0b, 0x06, 0x07, + 0x0e, 0x0e, 0x09, 0x09, 0x0a, 0x0a, 0x09, 0x05, 0x00, 0x01, 0x09, 0x09, + 0x05, 0x0d, 0x18, 0x0d, 0x06, 0x05, 0x02, 0x00, 0x02, 0xff, 0xf9, 0xfb, + 0xfe, 0xfe, 0xf6, 0xf1, 0xfb, 0x01, 0xfe, 0xfb, 0xfe, 0xfd, 0xfa, 0xfa, + 0x02, 0x03, 0x06, 0x09, 0x0a, 0x0d, 0x1a, 0x14, 0x0f, 0x05, 0xfa, 0x00, + 0x10, 0x0d, 0x06, 0x01, 0x05, 0x10, 0x0d, 0x09, 0x02, 0x05, 0x06, 0x07, + 0x03, 0x01, 0xf7, 0xf2, 0xed, 0xf6, 0x03, 0x05, 0x02, 0x00, 0x0a, 0x1f, + 0x24, 0x17, 0x07, 0x0a, 0x0b, 0x0b, 0x03, 0x00, 0xfa, 0xfd, 0xf9, 0xed, + 0xea, 0xf2, 0xf6, 0xf6, 0xff, 0xff, 0xfb, 0xfd, 0xfa, 0x01, 0x09, 0x0d, + 0x10, 0x0d, 0x0a, 0x16, 0x16, 0x0d, 0x05, 0x0a, 0x12, 0x0e, 0x05, 0x0e, + 0x12, 0x12, 0x12, 0x0f, 0x05, 0x00, 0x00, 0x00, 0xfb, 0xf9, 0xf5, 0xf5, + 0xf7, 0xf7, 0xf6, 0xfd, 0x07, 0x05, 0x03, 0x0a, 0x0e, 0x0a, 0xfe, 0xf7, + 0xfd, 0x00, 0x00, 0xff, 0xfe, 0xfb, 0xff, 0x07, 0x01, 0x07, 0x13, 0x17, + 0x0f, 0x0d, 0x10, 0x0f, 0x09, 0x05, 0x01, 0x01, 0x07, 0x09, 0x06, 0x10, + 0x14, 0x0f, 0x05, 0xfb, 0xff, 0x05, 0x03, 0xfe, 0xfb, 0xfd, 0xfb, 0xfe, + 0xfb, 0xf2, 0xf5, 0xf2, 0xf6, 0xf6, 0xf7, 0xfe, 0xfe, 0xfa, 0xff, 0x13, + 0x18, 0x14, 0x10, 0x1c, 0x23, 0x18, 0x0b, 0x02, 0x02, 0x07, 0x06, 0x01, + 0xfd, 0xfe, 0x01, 0x09, 0x07, 0xff, 0xff, 0x0a, 0x06, 0x03, 0x07, 0x0a, + 0x03, 0x02, 0xfd, 0xf3, 0xf7, 0xfd, 0x01, 0x0b, 0x12, 0x06, 0x0a, 0x07, + 0x0b, 0x16, 0x0d, 0xff, 0xfa, 0xfb, 0xff, 0x01, 0xfd, 0xf0, 0xf0, 0xfb, + 0xfd, 0xf6, 0xfe, 0x03, 0xff, 0xfb, 0xfb, 0xfe, 0x03, 0x0f, 0x13, 0x14, + 0x20, 0x1d, 0x0f, 0x07, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0f, 0x10, + 0x0f, 0x09, 0xff, 0x00, 0xfe, 0xfa, 0xfe, 0x00, 0xff, 0xfa, 0xf6, 0xf9, + 0xfe, 0x05, 0x0d, 0x0f, 0x16, 0x13, 0x0b, 0x02, 0xf6, 0xf5, 0x00, 0x00, + 0xfd, 0xf9, 0xf7, 0xfa, 0xfa, 0xfb, 0xfd, 0xff, 0xff, 0x05, 0x0a, 0x10, + 0x0d, 0x07, 0x02, 0x00, 0x0d, 0x12, 0x0f, 0x0a, 0x16, 0x1a, 0x17, 0x10, + 0x09, 0x05, 0x06, 0x0a, 0x09, 0x05, 0xff, 0x01, 0xfe, 0xfa, 0xf5, 0xf7, + 0xff, 0xfa, 0xf5, 0xf6, 0xf5, 0xf7, 0xf9, 0xf3, 0xf3, 0x03, 0x0f, 0x0e, + 0x14, 0x1c, 0x0e, 0x07, 0x06, 0x0b, 0x12, 0x0d, 0x0b, 0x02, 0x00, 0x00, + 0xff, 0x05, 0x0a, 0x09, 0x09, 0x06, 0x06, 0x05, 0x02, 0x01, 0xfe, 0xf9, + 0xfa, 0xf7, 0xfe, 0x03, 0x07, 0x16, 0x0e, 0x0d, 0x0b, 0x05, 0x03, 0x06, + 0x02, 0xfb, 0xf6, 0xf3, 0xf6, 0x00, 0xfe, 0xfb, 0x02, 0xff, 0x00, 0xfe, + 0xff, 0x07, 0x06, 0x06, 0x09, 0x0d, 0x0b, 0x0b, 0x07, 0x17, 0x10, 0x07, + 0x06, 0x00, 0x00, 0x07, 0x0a, 0x07, 0x07, 0x0d, 0x10, 0x10, 0x16, 0x10, + 0x09, 0xf7, 0xf6, 0xf9, 0xf7, 0xf9, 0xfd, 0xf9, 0xf2, 0xff, 0x02, 0xfd, + 0x00, 0x16, 0x0d, 0x0e, 0x0f, 0x09, 0xff, 0xfd, 0x00, 0xff, 0xfd, 0xfd, + 0xf3, 0xf0, 0xf5, 0xf9, 0x01, 0x03, 0x06, 0x07, 0x07, 0x10, 0x0f, 0x0d, + 0x07, 0x06, 0x0b, 0x0a, 0x0b, 0x1a, 0x1d, 0x17, 0x16, 0x0b, 0x01, 0x06, + 0x05, 0xff, 0xff, 0x00, 0xfe, 0x03, 0x01, 0x01, 0xff, 0xfa, 0xf9, 0xfd, + 0xfd, 0xfa, 0xf7, 0xf6, 0xf6, 0xf9, 0x02, 0x02, 0x09, 0x1a, 0x1c, 0x14, + 0x0a, 0x05, 0x01, 0x00, 0xfe, 0xf9, 0xf7, 0xf9, 0xfd, 0xfe, 0xff, 0x01, + 0x07, 0x14, 0x10, 0x0d, 0x0b, 0x05, 0x09, 0x09, 0x05, 0x06, 0x09, 0x05, + 0xff, 0x0a, 0x10, 0x14, 0x0d, 0x09, 0x05, 0x07, 0x0a, 0x03, 0xff, 0xfe, + 0xfb, 0xf7, 0xf7, 0xfb, 0xf3, 0xf5, 0xf3, 0xf5, 0xfa, 0xf9, 0xf9, 0xfb, + 0x01, 0x03, 0x0a, 0x18, 0x14, 0x17, 0x12, 0x16, 0x13, 0x0f, 0x07, 0x07, + 0x06, 0x03, 0x01, 0x07, 0x0a, 0x0b, 0x03, 0x03, 0x07, 0x0d, 0x09, 0x01, + 0xfb, 0xfe, 0xfb, 0xf9, 0xfd, 0xfe, 0xfb, 0xfa, 0xf9, 0xfe, 0xff, 0x0a, + 0x16, 0x0f, 0x05, 0xfb, 0xfb, 0x03, 0xff, 0x00, 0x00, 0xff, 0x05, 0x06, + 0x06, 0x05, 0x03, 0x05, 0x07, 0x05, 0x00, 0xff, 0xff, 0x02, 0x07, 0x0d, + 0x0f, 0x13, 0x0e, 0x1a, 0x1d, 0x1a, 0x13, 0x0b, 0x07, 0x02, 0xfd, 0xff, + 0xff, 0xff, 0xfe, 0xfe, 0xfd, 0xf9, 0xf9, 0xfe, 0xfa, 0xf6, 0xf2, 0xf2, + 0xf3, 0xfd, 0x01, 0x00, 0x03, 0x0b, 0x0d, 0x13, 0x13, 0x0d, 0x05, 0x06, + 0x03, 0x01, 0x00, 0xfd, 0xfe, 0xfd, 0xfa, 0xfe, 0x07, 0x05, 0x06, 0x0a, + 0x10, 0x10, 0x0d, 0x0b, 0x06, 0x05, 0x02, 0x00, 0x07, 0x18, 0x0b, 0x02, + 0x07, 0x0e, 0x13, 0x0e, 0x07, 0x01, 0x00, 0x00, 0xff, 0xff, 0xfe, 0xfd, + 0x03, 0xfe, 0xf9, 0xf7, 0xf7, 0xf9, 0xfa, 0xf9, 0xf7, 0xfd, 0xfe, 0x03, + 0x09, 0x0d, 0x09, 0x03, 0x07, 0x0a, 0x0a, 0x05, 0x03, 0x00, 0x00, 0x05, + 0x05, 0x0d, 0x0e, 0x12, 0x1b, 0x1c, 0x13, 0x06, 0x06, 0x07, 0x01, 0xfa, + 0xf9, 0xff, 0x02, 0x02, 0x02, 0x03, 0x07, 0xff, 0xff, 0x09, 0x03, 0x0e, + 0x03, 0xfb, 0xf5, 0xf0, 0xf2, 0xfa, 0xfd, 0x01, 0xfe, 0xfd, 0xfe, 0xfe, + 0x05, 0x0d, 0x07, 0x06, 0x03, 0x0b, 0x0f, 0x0a, 0x0e, 0x12, 0x12, 0x10, + 0x0e, 0x16, 0x10, 0x13, 0x0a, 0x05, 0x00, 0xfd, 0xff, 0xff, 0x03, 0x06, + 0x06, 0x05, 0xfb, 0xf9, 0xf3, 0xf6, 0xfb, 0xf5, 0xf3, 0xf6, 0xf2, 0xf5, + 0xfa, 0xf9, 0xff, 0x0e, 0x0f, 0x16, 0x1c, 0x1c, 0x17, 0x0b, 0x02, 0x00, + 0xfd, 0xfd, 0xfd, 0x00, 0x05, 0x05, 0x00, 0x00, 0x02, 0x02, 0x06, 0x0f, + 0x0f, 0x0f, 0x0b, 0x0b, 0x0f, 0x0f, 0x0e, 0x0f, 0x0b, 0x06, 0x12, 0x07, + 0x00, 0xfe, 0xf9, 0xf0, 0xf9, 0x00, 0xf9, 0xfd, 0x06, 0x02, 0xfa, 0xf6, + 0xfa, 0xfb, 0xf7, 0xf6, 0xf9, 0xff, 0xfd, 0x00, 0x02, 0x00, 0x0b, 0x14, + 0x0e, 0x06, 0x09, 0x10, 0x07, 0x03, 0xfe, 0xff, 0x03, 0x0d, 0x13, 0x0e, + 0x14, 0x12, 0x0b, 0x09, 0x06, 0x03, 0x03, 0x09, 0x07, 0x0a, 0x06, 0xfe, + 0x07, 0x00, 0xf9, 0x00, 0x01, 0xff, 0x01, 0x0e, 0x07, 0xfd, 0xff, 0x00, + 0xfa, 0xf9, 0xfa, 0xfd, 0x05, 0x05, 0x01, 0xfb, 0xff, 0x03, 0xfe, 0xfa, + 0xfd, 0xfb, 0x01, 0x03, 0x05, 0x03, 0x01, 0x06, 0x0e, 0x13, 0x10, 0x1d, + 0x21, 0x1b, 0x0d, 0x05, 0x05, 0x03, 0xff, 0x01, 0x0d, 0x0d, 0x09, 0x06, + 0x07, 0xff, 0xfa, 0xf9, 0xfb, 0xf7, 0xf3, 0xfb, 0xfe, 0xfb, 0xf9, 0xfe, + 0x03, 0x03, 0x00, 0x03, 0x0a, 0x06, 0x03, 0xfb, 0xf6, 0xf5, 0xfe, 0x0a, + 0x10, 0x14, 0x0f, 0x0b, 0x05, 0x02, 0x00, 0x00, 0x05, 0x0b, 0x10, 0x14, + 0x0f, 0x0d, 0x06, 0x07, 0x0d, 0x0b, 0x06, 0x09, 0x16, 0x14, 0x07, 0xfa, + 0xf5, 0xfa, 0xfa, 0xfe, 0x03, 0x00, 0xfd, 0xf0, 0xf0, 0xf0, 0xf1, 0xec, + 0xf5, 0xfd, 0x00, 0x0b, 0x0d, 0x0b, 0x05, 0x02, 0x01, 0x09, 0x14, 0x0a, + 0x0a, 0x16, 0x0f, 0x03, 0x00, 0x01, 0x05, 0x07, 0x14, 0x17, 0x10, 0x0d, + 0x10, 0x0d, 0x0f, 0x0e, 0x0a, 0x09, 0x05, 0x05, 0x01, 0x01, 0xfd, 0xed, + 0xe8, 0xee, 0xfb, 0x05, 0xff, 0x00, 0x00, 0xfb, 0xfa, 0xfb, 0x01, 0x05, + 0x07, 0x07, 0x03, 0x00, 0x03, 0x06, 0x03, 0x02, 0xfe, 0xfd, 0x00, 0x07, + 0x05, 0x06, 0x05, 0x05, 0x05, 0x09, 0x0b, 0x0e, 0x12, 0x10, 0x16, 0x09, + 0x01, 0xfd, 0xfa, 0xfd, 0x0a, 0x17, 0x12, 0x0b, 0x0f, 0x0d, 0x06, 0xfd, + 0x00, 0xfe, 0xfd, 0xfd, 0xfe, 0xfe, 0x00, 0x00, 0xfb, 0xfe, 0x02, 0x03, + 0xff, 0x01, 0x0a, 0x07, 0x01, 0x01, 0xfd, 0xfe, 0x02, 0x05, 0x01, 0xff, + 0xff, 0xfa, 0xf5, 0xf7, 0xf5, 0xfb, 0x06, 0x16, 0x12, 0x10, 0x1a, 0x14, + 0x10, 0x13, 0x16, 0x17, 0x0d, 0x09, 0x0d, 0x14, 0x0d, 0x05, 0xf9, 0xfb, + 0x05, 0x07, 0x03, 0xfa, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfa, 0xfd, 0xf6, + 0xf9, 0xf9, 0xf5, 0xea, 0xed, 0xf1, 0xf6, 0xfe, 0x05, 0x0f, 0x16, 0x18, + 0x1a, 0x13, 0x17, 0x10, 0x0e, 0x14, 0x12, 0x0f, 0x10, 0x10, 0x0a, 0x06, + 0x07, 0x0e, 0x0d, 0x05, 0x02, 0x03, 0x05, 0x06, 0x00, 0xfe, 0xfb, 0xf9, + 0xf7, 0xf0, 0xea, 0xea, 0xf9, 0xf1, 0xed, 0xee, 0xf1, 0x00, 0x0d, 0x0e, + 0x0b, 0x0b, 0x0a, 0x0e, 0x13, 0x12, 0x06, 0x03, 0x06, 0x09, 0x07, 0x05, + 0x03, 0x05, 0x0a, 0x0d, 0x07, 0x06, 0x07, 0x07, 0x0f, 0x0f, 0x09, 0x0e, + 0x0a, 0x0a, 0x09, 0x02, 0xff, 0x00, 0xfd, 0xf3, 0xf2, 0xff, 0xfa, 0xf6, + 0xf5, 0x01, 0xff, 0x07, 0x0f, 0x07, 0x01, 0x02, 0x02, 0x05, 0x03, 0x05, + 0x0a, 0x0b, 0x00, 0x00, 0x03, 0x05, 0x03, 0x06, 0x05, 0x05, 0x02, 0xff, + 0x02, 0x07, 0x02, 0xfe, 0xfe, 0x00, 0xff, 0x00, 0x01, 0x06, 0x0d, 0x0e, + 0x0d, 0x0e, 0x09, 0x14, 0x17, 0x27, 0x20, 0x13, 0x0d, 0x0b, 0xfb, 0xfa, + 0xfd, 0xfd, 0xfd, 0xfe, 0x01, 0xfd, 0xf9, 0xf6, 0xf6, 0xfb, 0xfd, 0xfb, + 0xf2, 0xf1, 0xf6, 0xfd, 0xfd, 0xfd, 0xfe, 0xff, 0x00, 0x0a, 0x0d, 0x05, + 0x07, 0x0d, 0x13, 0x0f, 0x0d, 0x1d, 0x21, 0x1d, 0x1c, 0x18, 0x12, 0x0d, + 0x09, 0x06, 0x03, 0x06, 0x02, 0xfe, 0x00, 0x00, 0xff, 0xf6, 0xe8, 0xf6, + 0xfd, 0xf9, 0xfe, 0xfe, 0xfe, 0x00, 0xfe, 0x00, 0x02, 0x06, 0x00, 0xf6, + 0xfb, 0xf9, 0xfa, 0xfb, 0x01, 0x00, 0x05, 0x1c, 0x17, 0x12, 0x0d, 0x0a, + 0x0d, 0x0d, 0x0b, 0x0a, 0x07, 0x05, 0x0b, 0x10, 0x0d, 0x0f, 0x09, 0x07, + 0x07, 0x01, 0x00, 0x05, 0x03, 0x01, 0x01, 0x00, 0xfd, 0xf9, 0xf1, 0xf3, + 0xf5, 0xf3, 0xf3, 0xf6, 0xf7, 0xfb, 0xf7, 0xff, 0x0b, 0x18, 0x12, 0x0f, + 0x0a, 0x0a, 0x0a, 0x07, 0x0b, 0x0b, 0x07, 0x06, 0x0a, 0x02, 0x02, 0x00, + 0xfe, 0x00, 0x03, 0x03, 0x01, 0x01, 0x02, 0x0a, 0x0a, 0x14, 0x0e, 0x07, + 0x06, 0x05, 0x02, 0x05, 0x09, 0x05, 0x06, 0x00, 0xfd, 0xfd, 0xfb, 0x14, + 0x14, 0x09, 0x01, 0xfd, 0xfd, 0xfb, 0xfb, 0xfb, 0xfb, 0xf9, 0xf7, 0xf6, + 0xf3, 0xf3, 0xf9, 0xff, 0x05, 0x0f, 0x0b, 0x06, 0x13, 0x16, 0x13, 0x16, + 0x14, 0x0e, 0x09, 0x09, 0x03, 0x00, 0x03, 0x06, 0x0a, 0x02, 0x05, 0x09, + 0x0e, 0x12, 0x0a, 0x09, 0x03, 0x00, 0xfa, 0xf9, 0xfd, 0xf9, 0xf2, 0xf6, + 0xfe, 0x02, 0x00, 0xff, 0x01, 0x01, 0x01, 0x07, 0x0a, 0x07, 0xff, 0x00, + 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x00, 0x03, 0x09, + 0x13, 0x17, 0x16, 0x16, 0x14, 0x1a, 0x16, 0x12, 0x0f, 0x0a, 0x01, 0xff, + 0x01, 0x00, 0x00, 0xff, 0xfe, 0xf9, 0xf9, 0xfb, 0xff, 0xfb, 0x01, 0x07, + 0x05, 0xff, 0xfb, 0xff, 0x01, 0x02, 0xfe, 0xf6, 0xf6, 0x00, 0x07, 0x03, + 0xfe, 0x01, 0x03, 0x0f, 0x14, 0x12, 0x0b, 0x05, 0x00, 0xfe, 0x03, 0x03, + 0x00, 0x01, 0x00, 0x06, 0x0b, 0x07, 0x07, 0x0f, 0x18, 0x17, 0x13, 0x10, + 0x0f, 0x17, 0x14, 0x0a, 0x01, 0x01, 0x00, 0x02, 0xfa, 0xf0, 0xf5, 0xf5, + 0xf6, 0xf0, 0xf6, 0xf9, 0xf7, 0xf7, 0xfe, 0x05, 0xff, 0xf9, 0xf7, 0xfd, + 0xff, 0x00, 0x09, 0x0d, 0x0b, 0x13, 0x23, 0x1d, 0x1b, 0x16, 0x13, 0x18, + 0x1a, 0x12, 0x0b, 0x07, 0x00, 0xfd, 0xfe, 0x00, 0xf9, 0xf6, 0xf6, 0xf7, + 0xf9, 0xfa, 0xf5, 0xf7, 0xff, 0xff, 0x00, 0x02, 0x02, 0x07, 0x0e, 0x0e, + 0x05, 0x02, 0x09, 0x0a, 0x02, 0x01, 0x02, 0x12, 0x09, 0x00, 0xfe, 0xff, + 0x01, 0x06, 0x0a, 0x06, 0x03, 0x01, 0x00, 0x01, 0x02, 0x01, 0x01, 0x05, + 0x02, 0x06, 0x0d, 0x0a, 0x07, 0x06, 0x0d, 0x0a, 0x06, 0x09, 0x0f, 0x0a, + 0x01, 0xfb, 0xf3, 0xf9, 0xfd, 0xff, 0x09, 0x12, 0x05, 0x02, 0x03, 0x00, + 0xff, 0x02, 0x03, 0x01, 0x00, 0x05, 0x07, 0x06, 0x01, 0x00, 0xff, 0x02, + 0xfe, 0x00, 0xff, 0xfe, 0xff, 0xfd, 0x00, 0x01, 0xfe, 0x01, 0x03, 0x09, + 0x12, 0x09, 0x06, 0x09, 0x0e, 0x0d, 0x09, 0x0f, 0x17, 0x1d, 0x17, 0x1b, + 0x0a, 0x00, 0x05, 0x0b, 0x07, 0x06, 0x05, 0xfb, 0xf1, 0xf0, 0xf2, 0xf6, + 0xf6, 0xf6, 0xf2, 0xed, 0xea, 0xf3, 0xf5, 0xf3, 0xfb, 0xf9, 0xfa, 0x01, + 0x01, 0x0b, 0x10, 0x1b, 0x23, 0x20, 0x23, 0x1d, 0x14, 0x18, 0x21, 0x1a, + 0x10, 0x05, 0x00, 0xfd, 0xfd, 0xfe, 0x00, 0x0a, 0x0b, 0x06, 0x00, 0xf9, + 0xf2, 0xf1, 0xf2, 0xf3, 0xfa, 0xfa, 0xff, 0xfd, 0x00, 0x03, 0x06, 0x03, + 0xff, 0x00, 0xff, 0x07, 0x0a, 0x07, 0x06, 0x06, 0x01, 0x01, 0x05, 0x0b, + 0x0d, 0x12, 0x12, 0x0b, 0x05, 0x03, 0x03, 0x03, 0x0a, 0x0a, 0x0a, 0x09, + 0x0b, 0x05, 0x02, 0xfe, 0xf2, 0xf3, 0xf9, 0x00, 0x00, 0xf7, 0xf7, 0xf2, + 0xf3, 0xfb, 0x00, 0x06, 0x0a, 0x1c, 0x17, 0x05, 0x05, 0x07, 0x07, 0x0b, + 0x17, 0x14, 0x0d, 0x07, 0x09, 0x03, 0x05, 0x06, 0x00, 0x01, 0x02, 0x03, + 0xff, 0xf6, 0xf2, 0xf1, 0xf2, 0xfa, 0xf9, 0xfb, 0x00, 0x09, 0x05, 0x03, + 0x05, 0xff, 0xfd, 0x01, 0x0b, 0x1b, 0x1d, 0x25, 0x1f, 0x1d, 0x16, 0x0f, + 0x0b, 0x0d, 0x0b, 0x09, 0x06, 0xfe, 0xee, 0xe8, 0xf1, 0xf6, 0xf7, 0xfb, + 0xfe, 0xfd, 0xf7, 0xf5, 0xf0, 0xf0, 0xf0, 0xf1, 0xfd, 0xff, 0xff, 0x03, + 0x0d, 0x1f, 0x25, 0x21, 0x18, 0x1c, 0x17, 0x10, 0x12, 0x16, 0x0d, 0x07, + 0x02, 0x02, 0x02, 0x03, 0x06, 0x09, 0x05, 0xff, 0xfe, 0xfa, 0xf7, 0xf9, + 0x00, 0x02, 0xfe, 0xfe, 0x00, 0x02, 0xf9, 0xfb, 0xfd, 0xfe, 0xfe, 0x01, + 0x00, 0xff, 0x01, 0xff, 0x00, 0x00, 0xfd, 0x01, 0x09, 0x06, 0x0d, 0x0f, + 0x0a, 0x06, 0x0a, 0x0d, 0x0f, 0x10, 0x0d, 0x0d, 0x0b, 0x16, 0x0e, 0x09, + 0x05, 0xff, 0xfd, 0xff, 0x00, 0x00, 0xfd, 0xfa, 0xf6, 0xf2, 0xf2, 0xf6, + 0xff, 0x05, 0x06, 0x0b, 0x17, 0x0a, 0xfe, 0xff, 0x01, 0x05, 0x06, 0x06, + 0x0d, 0x14, 0x16, 0x0b, 0x09, 0x02, 0x05, 0x05, 0x03, 0xfb, 0xf7, 0xf9, + 0x01, 0x05, 0x02, 0x02, 0x02, 0x01, 0x01, 0xff, 0xfd, 0xf5, 0xf1, 0xf9, + 0x00, 0xff, 0x03, 0x0b, 0x13, 0x17, 0x20, 0x1a, 0x10, 0x0a, 0x0b, 0x03, + 0x00, 0x05, 0x09, 0x01, 0xfe, 0xfa, 0xff, 0x06, 0x07, 0x03, 0x02, 0x00, + 0xfe, 0xfd, 0xfa, 0xf7, 0xf9, 0xfa, 0x00, 0x02, 0x00, 0x02, 0x0b, 0x0b, + 0x0b, 0x07, 0x07, 0x10, 0x14, 0x10, 0x0a, 0x09, 0x06, 0x02, 0xff, 0xfe, + 0xfe, 0xfb, 0xff, 0x0b, 0x10, 0x0a, 0x07, 0x09, 0x06, 0x07, 0x05, 0xff, + 0xfd, 0xfd, 0x06, 0x09, 0x06, 0xfe, 0xfd, 0xf9, 0xfb, 0xfb, 0xff, 0xff, + 0xfa, 0xfb, 0xfe, 0x03, 0x02, 0x05, 0x07, 0x07, 0x0a, 0x0d, 0x0e, 0x09, + 0x0d, 0x0d, 0x06, 0x03, 0x0a, 0x12, 0x14, 0x0e, 0x0e, 0x0d, 0x06, 0x06, + 0x05, 0xfe, 0xf7, 0xf9, 0xfa, 0xff, 0x02, 0xfe, 0xfd, 0x00, 0x01, 0xfe, + 0xfe, 0x02, 0x05, 0x05, 0xff, 0xfd, 0x05, 0x12, 0x0a, 0x05, 0x0d, 0x16, + 0x12, 0x06, 0xfa, 0xf3, 0xf5, 0xf9, 0x00, 0x07, 0x02, 0x00, 0x01, 0x07, + 0x09, 0x07, 0x02, 0x02, 0x05, 0x06, 0x00, 0xff, 0x06, 0x0a, 0x00, 0x00, + 0x01, 0x07, 0x13, 0x1a, 0x16, 0x14, 0x0b, 0x03, 0x09, 0x06, 0x01, 0xfe, + 0xfe, 0x02, 0x01, 0xfd, 0xf3, 0xf2, 0xf3, 0xfa, 0x02, 0x06, 0x05, 0x02, + 0x07, 0x07, 0xfd, 0xfb, 0xfd, 0xfa, 0x01, 0x0a, 0x0f, 0x17, 0x13, 0x0b, + 0x0d, 0x14, 0x13, 0x0b, 0x03, 0xfb, 0xfa, 0xf9, 0xfa, 0xff, 0x03, 0xff, + 0xfa, 0xfb, 0x03, 0x09, 0x06, 0x07, 0xfe, 0xf9, 0xff, 0xff, 0x07, 0x12, + 0x10, 0x0d, 0x05, 0xff, 0x06, 0x07, 0x01, 0x00, 0x03, 0x05, 0x0a, 0x0b, + 0x0d, 0x0a, 0x05, 0x05, 0x00, 0x01, 0x03, 0x00, 0x01, 0x05, 0x02, 0x03, + 0x05, 0x02, 0x02, 0x06, 0x07, 0x07, 0x01, 0xfa, 0xf5, 0xfa, 0xfb, 0x01, + 0xff, 0x09, 0x0f, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0xfe, 0xfd, 0x01, 0x07, + 0x16, 0x14, 0x06, 0xfe, 0x01, 0x00, 0xfd, 0x05, 0x0a, 0x09, 0x06, 0x03, + 0x06, 0x02, 0xff, 0xfd, 0xf9, 0xfb, 0x07, 0x0b, 0x01, 0xfb, 0xfd, 0x01, + 0x03, 0x0a, 0x03, 0x02, 0x05, 0x0b, 0x0b, 0x06, 0x01, 0xff, 0x01, 0x0d, + 0x1c, 0x1c, 0x1b, 0x16, 0x10, 0x07, 0x00, 0xfd, 0xf9, 0xf6, 0xfa, 0xf9, + 0xf7, 0xf6, 0xf5, 0xf7, 0x00, 0x01, 0xff, 0x00, 0x09, 0x0a, 0xff, 0xf5, + 0xf2, 0xf0, 0xfa, 0x06, 0x13, 0x0f, 0x10, 0x10, 0x0d, 0x0f, 0x0f, 0x16, + 0x16, 0x10, 0x14, 0x0e, 0x06, 0x01, 0xfe, 0xfb, 0xfb, 0xf7, 0xfb, 0xfe, + 0x05, 0x0b, 0x02, 0x05, 0x06, 0x00, 0xfa, 0xfb, 0x03, 0x00, 0x05, 0x03, + 0xfb, 0xf1, 0xf3, 0xff, 0x0a, 0x0b, 0x0a, 0x0a, 0x07, 0x06, 0x10, 0x12, + 0x07, 0x01, 0x03, 0x03, 0x0d, 0x10, 0x0a, 0x06, 0x05, 0x03, 0x00, 0x01, + 0x05, 0xfd, 0xf9, 0xf9, 0xff, 0xff, 0xf7, 0xfb, 0xf9, 0xf6, 0xfd, 0x00, + 0x02, 0xfd, 0xfe, 0x06, 0x09, 0x07, 0x0a, 0x0a, 0x0e, 0x18, 0x18, 0x0d, + 0x05, 0x0d, 0x0b, 0x0f, 0x1a, 0x0f, 0x0d, 0x0a, 0x0e, 0x07, 0x03, 0xff, + 0xf7, 0xf2, 0xf5, 0xfd, 0xfd, 0xf9, 0x00, 0xfe, 0xfb, 0xfb, 0xfa, 0xfa, + 0xf9, 0xfa, 0xfd, 0x01, 0x00, 0xf7, 0xf9, 0x05, 0x12, 0x18, 0x1b, 0x1c, + 0x20, 0x1c, 0x17, 0x12, 0x0b, 0x02, 0x03, 0x06, 0x02, 0x01, 0xfe, 0xf6, + 0xf5, 0xf5, 0xf5, 0xf9, 0x00, 0x05, 0x01, 0xfe, 0x00, 0x00, 0xff, 0xf7, + 0xfe, 0xfb, 0xff, 0x06, 0x0f, 0x0d, 0x09, 0x07, 0x16, 0x1c, 0x1a, 0x18, + 0x0e, 0x0a, 0x0b, 0x07, 0xff, 0xfe, 0xfe, 0x03, 0x09, 0x0e, 0x0b, 0x03, + 0xff, 0xfe, 0xfb, 0xfb, 0xfa, 0xf5, 0xf6, 0xf6, 0xf5, 0xfd, 0xf7, 0xf1, + 0xf5, 0xf9, 0x03, 0x0b, 0x03, 0x06, 0x0b, 0x09, 0x0b, 0x0b, 0x0f, 0x0e, + 0x0e, 0x12, 0x0d, 0x09, 0x0a, 0x05, 0x03, 0x09, 0x18, 0x13, 0x09, 0x02, + 0x00, 0xff, 0x01, 0xf9, 0xf3, 0xf3, 0xf1, 0xfa, 0xfb, 0xfd, 0x00, 0x00, + 0xff, 0x00, 0x07, 0x0b, 0x05, 0x05, 0x07, 0x0b, 0x0f, 0x0b, 0x01, 0x05, + 0x12, 0x14, 0x10, 0x0e, 0x09, 0x03, 0x07, 0x09, 0x06, 0x03, 0xfe, 0x00, + 0xfe, 0xfa, 0xfb, 0xfd, 0xfb, 0xfb, 0xf9, 0xfa, 0xfb, 0xfd, 0xf6, 0xf2, + 0xf9, 0xfe, 0x02, 0xff, 0x03, 0x03, 0x09, 0x12, 0x0f, 0x0d, 0x12, 0x17, + 0x14, 0x1a, 0x16, 0x14, 0x0d, 0x05, 0x06, 0x07, 0x03, 0xfe, 0xff, 0x02, + 0x05, 0x0d, 0x0e, 0x05, 0x01, 0x00, 0xfd, 0xf9, 0xff, 0xf7, 0xf5, 0xfb, + 0xf5, 0xf9, 0x02, 0x06, 0x07, 0x09, 0x0f, 0x0f, 0x0a, 0x06, 0xff, 0x00, + 0x03, 0x03, 0x07, 0x00, 0x00, 0x01, 0x0a, 0x0b, 0x0d, 0x09, 0x03, 0x00, + 0x0b, 0x10, 0x0d, 0x06, 0xfe, 0xf6, 0xf3, 0xf9, 0xf5, 0xee, 0xf1, 0xf3, + 0x00, 0x03, 0x03, 0x06, 0x0d, 0x14, 0x17, 0x0a, 0x05, 0x07, 0x10, 0x09, + 0x03, 0x06, 0x09, 0x09, 0x12, 0x17, 0x0f, 0x0d, 0x07, 0x01, 0xfd, 0x00, + 0x03, 0x03, 0xfd, 0xfd, 0xfe, 0xfd, 0xfe, 0xfd, 0xfd, 0xff, 0xfd, 0xf7, + 0xfb, 0xff, 0x07, 0x05, 0x05, 0x0b, 0x0b, 0x02, 0x06, 0x06, 0x09, 0x0f, + 0x09, 0x02, 0xff, 0xfe, 0x03, 0x14, 0x0f, 0x05, 0x01, 0x02, 0x00, 0x00, + 0xff, 0x02, 0xff, 0xfe, 0x00, 0x01, 0x06, 0x06, 0x01, 0xf9, 0xf7, 0xfb, + 0x03, 0xff, 0x02, 0x0b, 0x0f, 0x0d, 0x07, 0x0d, 0x0f, 0x10, 0x12, 0x10, + 0x0f, 0x0b, 0x09, 0x03, 0x00, 0x01, 0x03, 0x01, 0xfd, 0xff, 0x03, 0x07, + 0x02, 0x03, 0x00, 0xfd, 0x00, 0x01, 0xff, 0xfd, 0xfb, 0xf9, 0xf9, 0xfb, + 0xfb, 0xff, 0x0d, 0x0a, 0x07, 0x0b, 0x09, 0x01, 0x05, 0x0e, 0x0a, 0x06, + 0x03, 0xfe, 0x00, 0x05, 0x05, 0x02, 0x00, 0x03, 0x13, 0x14, 0x0f, 0x0f, + 0x06, 0x00, 0x00, 0xfe, 0xf9, 0xfa, 0xfd, 0x00, 0xfe, 0x06, 0x06, 0x07, + 0x0d, 0x0e, 0x12, 0x0d, 0x07, 0x05, 0x01, 0x06, 0x06, 0x06, 0x07, 0x07, + 0x0a, 0x09, 0x05, 0x07, 0x03, 0xfa, 0xf9, 0xf7, 0xf3, 0xff, 0xff, 0x01, + 0xf7, 0xf6, 0xfa, 0xfb, 0x01, 0x05, 0x01, 0xff, 0xfd, 0x00, 0x02, 0x0e, + 0x17, 0x18, 0x18, 0x0f, 0x0e, 0x05, 0x05, 0x03, 0x01, 0x01, 0x00, 0x03, + 0x07, 0x0a, 0x0b, 0x09, 0x00, 0xfb, 0xfe, 0xfd, 0xff, 0xfe, 0xff, 0x00, + 0xfe, 0xfd, 0xfe, 0x01, 0x06, 0x06, 0x03, 0xff, 0x05, 0x07, 0x0e, 0x12, + 0x0b, 0x0f, 0x0a, 0x0b, 0x0f, 0x0b, 0x06, 0x02, 0x05, 0x02, 0x03, 0x05, + 0x05, 0x06, 0x09, 0x00, 0xf7, 0xf7, 0xf7, 0xfb, 0x03, 0xfe, 0xf6, 0xf9, + 0x09, 0x03, 0xfe, 0xfe, 0x00, 0xff, 0xfb, 0xf9, 0xfb, 0x02, 0x0d, 0x06, + 0x09, 0x0a, 0x12, 0x1f, 0x1b, 0x12, 0x0d, 0x03, 0x02, 0xff, 0xfd, 0xfa, + 0x00, 0x02, 0x05, 0x09, 0x18, 0x13, 0x0b, 0x09, 0x02, 0xfe, 0xfb, 0xf9, + 0xfa, 0x00, 0x00, 0xf2, 0xf6, 0xfa, 0xfd, 0x06, 0x06, 0x09, 0x0d, 0x0d, + 0x0d, 0x09, 0x06, 0x07, 0x0e, 0x0a, 0x06, 0x07, 0x0e, 0x0b, 0x06, 0x00, + 0xf7, 0xfb, 0xf9, 0xf9, 0xfa, 0x01, 0x03, 0xfe, 0xfe, 0xfe, 0xf7, 0xf9, + 0xfe, 0xfd, 0xfd, 0xfd, 0xfa, 0xfa, 0xff, 0x06, 0x16, 0x1b, 0x1b, 0x18, + 0x1b, 0x1b, 0x17, 0x13, 0x0b, 0x09, 0x09, 0x0b, 0x09, 0x07, 0x07, 0x02, + 0xfe, 0xf9, 0xfe, 0x00, 0xfe, 0xfe, 0x00, 0x05, 0xfb, 0xf1, 0xf2, 0xf2, + 0xf2, 0xf7, 0xf7, 0xfa, 0x07, 0x07, 0x05, 0x03, 0x06, 0x0d, 0x0d, 0x02, + 0x0a, 0x12, 0x10, 0x0e, 0x0b, 0x07, 0x0d, 0x0b, 0x0e, 0x10, 0x0e, 0x0a, + 0x02, 0xfe, 0xfe, 0xf5, 0xf6, 0xfd, 0xfb, 0xfe, 0x0a, 0x0b, 0x0a, 0x03, + 0xfd, 0xf6, 0xf1, 0xec, 0xf2, 0xfd, 0x03, 0x00, 0x00, 0x0a, 0x17, 0x14, + 0x1a, 0x1b, 0x13, 0x10, 0x0f, 0x0b, 0x0a, 0x06, 0x07, 0x0a, 0x03, 0x09, + 0x13, 0x0b, 0x06, 0x02, 0xfe, 0xf6, 0xf5, 0xf3, 0xf5, 0xfb, 0xfd, 0xfa, + 0xf5, 0xf6, 0xf9, 0xf3, 0xfb, 0x03, 0x06, 0x09, 0x0e, 0x05, 0x01, 0x01, + 0x0b, 0x0d, 0x0f, 0x10, 0x1b, 0x1b, 0x13, 0x09, 0x07, 0x02, 0xff, 0x01, + 0xff, 0x02, 0x03, 0x01, 0x01, 0xfd, 0xfa, 0xf7, 0xf5, 0xf7, 0xfb, 0xfd, + 0xfd, 0xfd, 0xfd, 0x00, 0x06, 0x02, 0x06, 0x14, 0x2d, 0x29, 0x17, 0x0d, + 0x10, 0x10, 0x09, 0x03, 0x03, 0x06, 0x05, 0x06, 0x05, 0x01, 0x00, 0x02, + 0x02, 0x00, 0x00, 0xfe, 0xf9, 0xf5, 0xf2, 0xf3, 0xee, 0xec, 0xf3, 0xfb, + 0x05, 0x01, 0x02, 0x0a, 0x0a, 0x01, 0xff, 0x0a, 0x0f, 0x0b, 0x0b, 0x0b, + 0x07, 0x09, 0x0d, 0x10, 0x0e, 0x0d, 0x10, 0x12, 0x0f, 0x06, 0x01, 0x03, + 0x03, 0x01, 0xfe, 0x05, 0x0f, 0x0f, 0x0d, 0x03, 0xfb, 0xf5, 0xec, 0xe9, + 0xed, 0xf7, 0xf9, 0xfe, 0x02, 0x05, 0x07, 0x0a, 0x09, 0x06, 0x0e, 0x14, + 0x0d, 0x06, 0x03, 0x05, 0x05, 0x03, 0x01, 0x0d, 0x17, 0x14, 0x0e, 0x09, + 0x09, 0x06, 0x00, 0xfa, 0xf9, 0xf7, 0xfa, 0xfd, 0xf9, 0xf7, 0xfa, 0xfd, + 0xfa, 0xf3, 0xf9, 0x03, 0x03, 0x05, 0x0b, 0x0b, 0x02, 0x01, 0x03, 0x16, + 0x28, 0x1c, 0x0f, 0x09, 0x05, 0x05, 0x02, 0xfe, 0x00, 0x03, 0x0b, 0x09, + 0x03, 0x06, 0x09, 0x06, 0x06, 0xff, 0xff, 0x00, 0xfb, 0xf1, 0xf3, 0xf3, + 0xf0, 0xf1, 0xf7, 0x06, 0x20, 0x18, 0x13, 0x10, 0x0f, 0x0e, 0x0a, 0x07, + 0x06, 0x05, 0x09, 0x09, 0x05, 0x05, 0xfe, 0xfb, 0x05, 0x00, 0xfd, 0xfe, + 0x03, 0x03, 0x00, 0xfa, 0xf7, 0xf9, 0xf9, 0xff, 0x0b, 0x06, 0x01, 0xfd, + 0x00, 0x06, 0x03, 0x02, 0x02, 0x05, 0x0e, 0x0e, 0x05, 0x09, 0x12, 0x0e, + 0x0b, 0x0b, 0x12, 0x14, 0x12, 0x09, 0x02, 0xfd, 0x00, 0x01, 0x02, 0x09, + 0x0f, 0x0e, 0x09, 0x01, 0xfe, 0x00, 0xfd, 0xf6, 0xed, 0xea, 0xf1, 0xf5, + 0xf7, 0xfb, 0xfb, 0x05, 0x03, 0x00, 0x06, 0x0d, 0x0b, 0x0d, 0x07, 0x02, + 0x06, 0x09, 0x02, 0x0f, 0x24, 0x25, 0x1a, 0x10, 0x02, 0xfe, 0xfd, 0xfd, + 0xfb, 0xf7, 0xf7, 0x01, 0x02, 0x02, 0x00, 0x00, 0x02, 0x01, 0xfd, 0xfb, + 0xfd, 0x00, 0x05, 0xff, 0xff, 0x01, 0x06, 0x0e, 0x1b, 0x1d, 0x13, 0x0d, + 0x0a, 0x02, 0x01, 0x03, 0xff, 0x02, 0x02, 0x03, 0x03, 0x05, 0x01, 0xff, + 0x01, 0xff, 0xfd, 0xfe, 0xfe, 0xff, 0x02, 0xff, 0xf6, 0xf5, 0xf9, 0x05, + 0x0d, 0x14, 0x18, 0x0e, 0x05, 0x00, 0x07, 0x0f, 0x10, 0x0e, 0x09, 0x02, + 0x01, 0x01, 0x01, 0x03, 0x06, 0x01, 0x00, 0x02, 0x01, 0x02, 0x03, 0xff, + 0xf3, 0xed, 0xf5, 0x02, 0x09, 0x06, 0x0a, 0x06, 0x03, 0x03, 0x0a, 0x07, + 0x0b, 0x0b, 0x06, 0x06, 0x03, 0x09, 0x13, 0x12, 0x06, 0x07, 0x06, 0x06, + 0x03, 0x01, 0x03, 0x00, 0xf5, 0xfb, 0x05, 0x09, 0x14, 0x12, 0x0e, 0x0b, + 0x03, 0xfa, 0xf5, 0xf5, 0xf7, 0xf5, 0xf0, 0xf0, 0xf1, 0xfa, 0x03, 0x09, + 0x0d, 0x09, 0x06, 0x01, 0x03, 0x07, 0x0e, 0x0d, 0x06, 0x05, 0x06, 0x10, + 0x18, 0x18, 0x17, 0x12, 0x0a, 0x06, 0x02, 0x01, 0xfe, 0x00, 0xff, 0xfd, + 0x01, 0x03, 0x06, 0xfd, 0xfa, 0x00, 0xff, 0xfd, 0xfb, 0xfb, 0x00, 0x06, + 0x02, 0x02, 0x03, 0x09, 0x0d, 0x0f, 0x13, 0x0b, 0x0b, 0x07, 0xfd, 0xfd, + 0x02, 0x01, 0x00, 0xff, 0x00, 0xff, 0x00, 0xfd, 0xfb, 0x03, 0x06, 0x05, + 0x00, 0x02, 0x0a, 0x05, 0xff, 0xfe, 0xfe, 0x02, 0x01, 0x07, 0x0a, 0x0d, + 0x16, 0x10, 0x05, 0x07, 0x0d, 0x12, 0x0e, 0x07, 0x03, 0x02, 0x07, 0x05, + 0xfe, 0xff, 0x01, 0x01, 0x00, 0x00, 0xfb, 0xfa, 0xf3, 0xf3, 0xf5, 0xfe, + 0x0b, 0x0a, 0x05, 0x02, 0x07, 0x05, 0xfd, 0xf6, 0x00, 0x00, 0x03, 0x03, + 0x06, 0x06, 0x09, 0x0d, 0x13, 0x1f, 0x18, 0x0e, 0x02, 0x00, 0x01, 0x06, + 0x02, 0xfe, 0xfd, 0x06, 0x10, 0x14, 0x0b, 0xff, 0xff, 0x02, 0xf7, 0xf1, + 0xf2, 0xf6, 0xfe, 0xfa, 0xfb, 0xf7, 0xfa, 0xff, 0x01, 0x09, 0x02, 0xff, + 0x03, 0x03, 0x05, 0x07, 0x09, 0x0e, 0x16, 0x17, 0x18, 0x1c, 0x17, 0x0d, + 0x0b, 0x0e, 0x0b, 0x09, 0x06, 0x00, 0xfe, 0xfe, 0xfa, 0xf7, 0xf3, 0xfa, + 0xfb, 0xf7, 0xf7, 0xfd, 0x00, 0x00, 0xfe, 0x00, 0x06, 0x02, 0x03, 0x0e, + 0x0d, 0x09, 0x09, 0x09, 0x07, 0x0d, 0x0b, 0x06, 0x0d, 0x06, 0xff, 0xff, + 0xfe, 0xfe, 0x00, 0x03, 0x05, 0x01, 0xff, 0xff, 0x00, 0x07, 0x03, 0xff, + 0xfa, 0xfa, 0xfb, 0x00, 0x07, 0x0f, 0x12, 0x0d, 0x09, 0x09, 0x0e, 0x10, + 0x09, 0x07, 0x05, 0x05, 0x07, 0x07, 0x05, 0x0a, 0x0f, 0x07, 0x05, 0x01, + 0xfb, 0xfe, 0xfd, 0xfe, 0xfb, 0xf6, 0xf6, 0xfb, 0x03, 0x03, 0x03, 0x01, + 0xfe, 0xfa, 0xf7, 0xfe, 0xf9, 0xf5, 0xfb, 0x09, 0x0f, 0x0b, 0x0a, 0x0b, + 0x16, 0x17, 0x12, 0x0b, 0x09, 0x16, 0x0f, 0x06, 0x02, 0x05, 0x06, 0x0a, + 0x12, 0x17, 0x0d, 0x07, 0xff, 0xfd, 0xfe, 0x03, 0xfe, 0xf6, 0xf3, 0xec, + 0xf2, 0xf3, 0xf2, 0xf2, 0xf6, 0xf6, 0xfd, 0x01, 0x00, 0x09, 0x10, 0x0d, + 0x0a, 0x07, 0x0e, 0x12, 0x16, 0x1a, 0x16, 0x12, 0x0d, 0x06, 0x03, 0x09, + 0x0f, 0x0b, 0x0a, 0x03, 0xff, 0xfe, 0xff, 0xfe, 0x00, 0xfe, 0xfb, 0xf3, + 0xf7, 0xfb, 0xfe, 0xf7, 0xf3, 0xf6, 0x01, 0x05, 0x09, 0x0f, 0x0b, 0x0d, + 0x13, 0x0a, 0x06, 0x0a, 0x10, 0x10, 0x05, 0x00, 0xfd, 0xfe, 0x02, 0x05, + 0x05, 0x05, 0x03, 0x03, 0x01, 0x03, 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x06, 0x0b, 0x05, 0x02, 0x07, 0x05, 0x09, 0x03, 0x01, 0x03, 0x00, 0x02, + 0x00, 0x02, 0x09, 0x0d, 0x10, 0x1a, 0x0f, 0x03, 0x00, 0xff, 0x00, 0xff, + 0xfe, 0xff, 0xff, 0xff, 0x05, 0x0a, 0x06, 0x03, 0xfe, 0xfd, 0xf9, 0xfa, + 0xfa, 0xfb, 0xfb, 0xf5, 0xf2, 0x00, 0x0b, 0x0d, 0x09, 0x0a, 0x06, 0x02, + 0x07, 0x13, 0x10, 0x10, 0x18, 0x1b, 0x1b, 0x0e, 0x0b, 0x0e, 0x0a, 0x09, + 0x06, 0x05, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf0, 0xec, 0xf2, 0xfd, + 0xf9, 0xf7, 0xf5, 0xf2, 0xf9, 0x00, 0x02, 0x05, 0x07, 0x05, 0x02, 0x05, + 0x07, 0x0e, 0x14, 0x13, 0x13, 0x13, 0x13, 0x14, 0x10, 0x09, 0x06, 0x02, + 0x02, 0x03, 0x03, 0x09, 0x0a, 0x06, 0x03, 0xfd, 0xfe, 0xfb, 0xfd, 0xf9, + 0xfb, 0xfb, 0xf6, 0xfa, 0x05, 0x12, 0x0f, 0x07, 0x03, 0x02, 0x01, 0xff, + 0x00, 0xfd, 0xfa, 0xfd, 0x02, 0x07, 0x09, 0x0a, 0x0f, 0x0d, 0x0b, 0x09, + 0x03, 0x03, 0x03, 0x01, 0x03, 0x02, 0xff, 0xff, 0x02, 0x07, 0x0d, 0x07, + 0x05, 0x03, 0x00, 0x02, 0x07, 0x0b, 0x07, 0x05, 0xfe, 0xf5, 0xfa, 0x01, + 0x03, 0xff, 0xfe, 0x02, 0x0a, 0x07, 0x03, 0x00, 0x07, 0x0e, 0x10, 0x06, + 0x03, 0x0a, 0x0d, 0x07, 0x03, 0x00, 0xfd, 0xfe, 0xff, 0xfd, 0xf7, 0xf9, + 0xf9, 0xf5, 0xfa, 0x02, 0x0b, 0x0d, 0x06, 0x02, 0x05, 0x0a, 0x09, 0x07, + 0x09, 0x0b, 0x0e, 0x0a, 0x13, 0x16, 0x12, 0x0d, 0x06, 0x05, 0x07, 0x05, + 0x0b, 0x07, 0x01, 0xfa, 0xfb, 0xf3, 0xf6, 0xf9, 0xfb, 0xfa, 0xf7, 0xf7, + 0xf7, 0xf9, 0xf9, 0x00, 0x0a, 0x0d, 0x09, 0x05, 0x02, 0x07, 0x12, 0x12, + 0x09, 0x03, 0x02, 0x09, 0x12, 0x0a, 0x02, 0xfd, 0xfe, 0x0b, 0x0b, 0x0f, + 0x0e, 0x0d, 0x13, 0x0b, 0x06, 0x05, 0xfb, 0xf7, 0xf9, 0xfb, 0xfb, 0xf6, + 0xfb, 0x05, 0x0d, 0x12, 0x0b, 0x09, 0x03, 0x00, 0x01, 0x01, 0xfd, 0xf5, + 0xf7, 0x00, 0xfd, 0xfa, 0x01, 0x0a, 0x0d, 0x02, 0x00, 0x05, 0x02, 0x06, + 0x0d, 0x10, 0x0b, 0x05, 0x03, 0x05, 0x09, 0x06, 0x02, 0x02, 0x03, 0x07, + 0x05, 0x06, 0x0e, 0x0d, 0x0a, 0x0f, 0x02, 0xfb, 0xff, 0x02, 0x00, 0xfe, + 0xfa, 0xff, 0x01, 0x02, 0x02, 0x00, 0xff, 0x01, 0x07, 0x07, 0x03, 0x05, + 0x09, 0x0e, 0x01, 0xff, 0x02, 0x0d, 0x06, 0xfa, 0xf6, 0xfd, 0xff, 0xfd, + 0xff, 0x07, 0x09, 0x05, 0x02, 0x01, 0x00, 0x05, 0x12, 0x16, 0x10, 0x09, + 0x06, 0x07, 0x0e, 0x1f, 0x17, 0x0a, 0xfb, 0xf9, 0xff, 0xfe, 0xfa, 0xf9, + 0xfa, 0xf9, 0x02, 0xfd, 0xfa, 0xfb, 0xfa, 0x00, 0x05, 0xfe, 0xf9, 0x00, + 0x07, 0x0d, 0x0d, 0x07, 0x07, 0x0a, 0x0a, 0x0b, 0x0b, 0x09, 0x06, 0x02, + 0x01, 0x00, 0x00, 0x03, 0x03, 0x01, 0x06, 0x07, 0x06, 0x05, 0x03, 0x05, + 0x0d, 0x05, 0x02, 0x06, 0x0d, 0x01, 0xf3, 0xfd, 0xfb, 0x02, 0x00, 0x0a, + 0x12, 0x12, 0x0b, 0x03, 0x00, 0x00, 0x02, 0x03, 0x01, 0xf6, 0xfb, 0x00, + 0xff, 0xfd, 0x01, 0x06, 0x05, 0x03, 0x03, 0x05, 0x05, 0x03, 0x05, 0x07, + 0x05, 0xfd, 0xfe, 0x06, 0x0b, 0x0b, 0x0b, 0x03, 0xff, 0x03, 0x09, 0x10, + 0x10, 0x0a, 0x06, 0x0b, 0x09, 0xfe, 0xfd, 0x03, 0xff, 0xfb, 0xf9, 0xfa, + 0x06, 0x06, 0x0e, 0x07, 0x02, 0x02, 0x03, 0x06, 0x09, 0x03, 0xff, 0xfd, + 0xf9, 0xf7, 0xfb, 0xff, 0x03, 0x00, 0xfe, 0x01, 0x05, 0x06, 0x01, 0x00, + 0x05, 0x0b, 0x07, 0x02, 0x06, 0x13, 0x13, 0x0b, 0x09, 0x0a, 0x0b, 0x0b, + 0x12, 0x14, 0x1b, 0x16, 0x0a, 0xfa, 0x00, 0x00, 0xfa, 0xf9, 0xf6, 0xfb, + 0xf9, 0xf3, 0xf5, 0xf1, 0xf2, 0xf2, 0xfa, 0xff, 0x03, 0x09, 0x01, 0x00, + 0x07, 0x09, 0x0a, 0x13, 0x1b, 0x1b, 0x17, 0x0b, 0x02, 0x01, 0x03, 0x02, + 0x00, 0x00, 0x00, 0x07, 0x12, 0x0d, 0x07, 0x05, 0x07, 0x09, 0x02, 0x00, + 0xff, 0x02, 0x05, 0x02, 0xf9, 0xf1, 0xf6, 0xfe, 0x06, 0x05, 0x02, 0x05, + 0x00, 0xff, 0x00, 0x02, 0x10, 0x0b, 0x05, 0x05, 0x0d, 0x05, 0x01, 0xff, + 0x06, 0x10, 0x07, 0x02, 0x05, 0x07, 0x0b, 0x03, 0x05, 0x00, 0xfd, 0xfa, + 0xfb, 0x03, 0x01, 0x00, 0xff, 0xff, 0x03, 0x0b, 0x09, 0x05, 0x01, 0x03, + 0x0e, 0x0f, 0x0a, 0x05, 0xff, 0x03, 0x06, 0x01, 0xff, 0x01, 0x09, 0x0b, + 0x0b, 0x0f, 0x07, 0x03, 0x02, 0x00, 0x05, 0x02, 0x00, 0xfb, 0xff, 0xff, + 0xfd, 0xfa, 0xfa, 0xfa, 0xfe, 0x02, 0x05, 0x01, 0xff, 0xfd, 0xfb, 0xff, + 0x07, 0x07, 0x0a, 0x12, 0x12, 0x0b, 0x0b, 0x13, 0x16, 0x0e, 0x16, 0x14, + 0x14, 0x13, 0x12, 0x06, 0xfe, 0xf9, 0xf2, 0xf1, 0xf3, 0xff, 0xff, 0xfd, + 0xfe, 0xfd, 0xf5, 0xf7, 0xf7, 0xfa, 0x00, 0x06, 0x01, 0xfa, 0xfd, 0x02, + 0x0a, 0x0b, 0x10, 0x13, 0x12, 0x10, 0x07, 0xff, 0x02, 0x06, 0x03, 0x01, + 0x0b, 0x14, 0x0e, 0x0b, 0x09, 0x07, 0x03, 0x02, 0xfb, 0xfd, 0x03, 0x0a, + 0x0e, 0x0b, 0x0d, 0xff, 0xf7, 0xfa, 0xf9, 0xff, 0xfd, 0xfb, 0xfe, 0xfa, + 0xfd, 0x01, 0xff, 0xfa, 0x00, 0x06, 0x0a, 0x06, 0x01, 0x01, 0x01, 0x10, + 0x14, 0x12, 0x12, 0x0d, 0x10, 0x0d, 0x02, 0xfe, 0xf9, 0xfa, 0xfb, 0x01, + 0x05, 0x06, 0x09, 0x07, 0x05, 0x03, 0x03, 0x00, 0xfd, 0x01, 0x0a, 0x0b, + 0x09, 0x06, 0x01, 0xfa, 0xf9, 0xf6, 0xff, 0xff, 0x05, 0x07, 0x03, 0x0a, + 0x0b, 0x10, 0x0d, 0x0e, 0x0d, 0x0a, 0x07, 0x02, 0xfd, 0xff, 0xff, 0xff, + 0xfb, 0xff, 0x0a, 0x05, 0x00, 0xfb, 0xf6, 0xf2, 0xf7, 0xf9, 0x00, 0x01, + 0x05, 0x0d, 0x0a, 0x0e, 0x0d, 0x0e, 0x0b, 0x0b, 0x0d, 0x0d, 0x14, 0x18, + 0x0e, 0x09, 0x01, 0xff, 0xff, 0x00, 0x07, 0x02, 0xff, 0xfe, 0x02, 0xff, + 0xfe, 0xfd, 0xfd, 0xfd, 0x00, 0x02, 0x00, 0xfe, 0xfb, 0xfd, 0x05, 0x05, + 0x06, 0x0a, 0x0b, 0x09, 0x01, 0xff, 0xfe, 0x00, 0xfd, 0x00, 0x10, 0x13, + 0x13, 0x0a, 0x05, 0x03, 0x0a, 0x0b, 0x0d, 0x06, 0x01, 0x0d, 0x13, 0x10, + 0x0a, 0x01, 0xf7, 0xf6, 0xf9, 0xfe, 0xfd, 0xfd, 0xfa, 0x02, 0x01, 0xfe, + 0xfb, 0x01, 0x0d, 0x09, 0x03, 0x02, 0x02, 0x02, 0xff, 0x01, 0x0b, 0x0b, + 0x05, 0x0d, 0x16, 0x0e, 0x01, 0xf9, 0x02, 0x03, 0x07, 0x0a, 0x05, 0x05, + 0x06, 0x05, 0x03, 0x02, 0x00, 0x01, 0x05, 0x07, 0x02, 0x07, 0x07, 0x06, + 0x02, 0xff, 0x00, 0xfe, 0x00, 0x01, 0x05, 0x03, 0x00, 0x05, 0x09, 0x03, + 0x00, 0x05, 0x02, 0x05, 0x07, 0x00, 0xfa, 0xfd, 0x05, 0x07, 0x0a, 0x0b, + 0x0a, 0x0a, 0x09, 0x01, 0xf5, 0xf2, 0xfb, 0xfd, 0xff, 0x07, 0x0d, 0x06, + 0x03, 0x12, 0x10, 0x0a, 0x07, 0x0a, 0x0e, 0x07, 0x09, 0x13, 0x0e, 0x03, + 0xfb, 0xf3, 0xfb, 0x01, 0xfd, 0xff, 0x01, 0xf9, 0xfb, 0x05, 0x07, 0x03, + 0x03, 0x09, 0x12, 0x0a, 0x03, 0x02, 0x01, 0x01, 0xff, 0x03, 0x03, 0xff, + 0x00, 0x0a, 0x02, 0xfd, 0xf6, 0xfa, 0xfb, 0x07, 0x0b, 0x09, 0x09, 0x06, + 0x02, 0x02, 0x00, 0x06, 0x13, 0x0f, 0x0b, 0x0b, 0x0b, 0x07, 0x0a, 0x0e, + 0x00, 0x00, 0x00, 0xff, 0xfd, 0xff, 0x00, 0xfa, 0xfa, 0x03, 0x05, 0x06, + 0x0b, 0x0d, 0x06, 0x01, 0xfe, 0xff, 0xff, 0x00, 0x06, 0x0d, 0x0e, 0x07, + 0x05, 0x05, 0x02, 0xfb, 0xfd, 0xff, 0xff, 0xff, 0x02, 0x03, 0x05, 0x02, + 0x07, 0x0a, 0x05, 0x0b, 0x0f, 0x0d, 0x06, 0x01, 0x02, 0x05, 0x01, 0xfd, + 0x02, 0x06, 0x05, 0x00, 0xfd, 0xff, 0x05, 0x12, 0x0f, 0x05, 0x01, 0x00, + 0x02, 0x02, 0x07, 0x07, 0xfd, 0xf7, 0xfa, 0x02, 0x0a, 0x05, 0xff, 0xfb, + 0xfa, 0x02, 0x03, 0xff, 0x00, 0x05, 0x09, 0x09, 0x05, 0x07, 0x07, 0x0b, + 0x0f, 0x0b, 0x09, 0x02, 0x05, 0x01, 0x03, 0x14, 0x0f, 0x07, 0x01, 0xfd, + 0x05, 0x03, 0x02, 0x00, 0xf9, 0xf7, 0xfa, 0xff, 0x00, 0x05, 0x03, 0x03, + 0xff, 0x00, 0x02, 0x05, 0x06, 0x00, 0xff, 0xff, 0x05, 0x0b, 0x09, 0x0b, + 0x0f, 0x06, 0xfb, 0xfb, 0x03, 0x06, 0x0b, 0x07, 0x03, 0x03, 0x07, 0x06, + 0x07, 0x0e, 0x10, 0x10, 0x07, 0x07, 0x07, 0x09, 0x05, 0xfd, 0xf2, 0xf1, + 0xf3, 0xfe, 0xf9, 0xf1, 0xff, 0x06, 0x03, 0x02, 0x0b, 0x0f, 0x0f, 0x0e, + 0x0e, 0x0a, 0x09, 0x02, 0xff, 0x05, 0x0f, 0x0f, 0x05, 0x02, 0x02, 0x05, + 0x05, 0xfd, 0xf6, 0xf2, 0xf3, 0xf9, 0x02, 0xff, 0x01, 0x00, 0xfa, 0xff, + 0x10, 0x13, 0x0d, 0x06, 0x01, 0xfb, 0x03, 0x0f, 0x0f, 0x06, 0x0a, 0x12, + 0x0f, 0x0e, 0x02, 0x03, 0x0a, 0x0e, 0x03, 0x01, 0xff, 0x02, 0x09, 0x0a, + 0x03, 0x05, 0xff, 0xf6, 0xff, 0x05, 0x01, 0x01, 0xff, 0xf9, 0xf7, 0xfa, + 0xf9, 0xfe, 0x02, 0x07, 0x06, 0x03, 0xfd, 0xff, 0x14, 0x13, 0x0e, 0x0d, + 0x0d, 0x07, 0x09, 0x0a, 0x0d, 0x0d, 0x0a, 0x02, 0x01, 0x00, 0x01, 0x01, + 0x02, 0xfd, 0xf5, 0xfb, 0x03, 0x03, 0x09, 0x0e, 0x09, 0x05, 0x00, 0x05, + 0x05, 0x02, 0xfd, 0xfb, 0xf9, 0xf5, 0xf9, 0xff, 0x01, 0x03, 0x0e, 0x05, + 0x0b, 0x10, 0x0a, 0x0b, 0x0f, 0x07, 0x05, 0x05, 0x0a, 0x0a, 0x0e, 0x13, + 0x0f, 0x07, 0x03, 0x01, 0x05, 0x07, 0x02, 0xfd, 0xf1, 0xf1, 0xf6, 0xff, + 0x02, 0x00, 0xfb, 0xf9, 0x00, 0x03, 0x02, 0x02, 0x03, 0xfd, 0xfb, 0x03, + 0x0e, 0x0a, 0x0a, 0x1a, 0x14, 0x0d, 0x0e, 0x12, 0x0f, 0x0b, 0x01, 0xfb, + 0xfa, 0xf6, 0xf7, 0xfb, 0x00, 0x01, 0x02, 0x01, 0x02, 0x0d, 0x0a, 0x09, + 0x0a, 0x05, 0x00, 0xfe, 0xff, 0x05, 0x05, 0x06, 0x07, 0x03, 0xfd, 0xff, + 0x05, 0x09, 0x0a, 0x07, 0x05, 0x05, 0x02, 0x06, 0x0e, 0x0f, 0x09, 0x09, + 0x09, 0x0a, 0x00, 0xff, 0xff, 0xfe, 0xf7, 0xf3, 0xf9, 0xfa, 0xfb, 0x06, + 0x03, 0x00, 0xfd, 0xff, 0x00, 0xfe, 0xfe, 0x01, 0x03, 0x06, 0x06, 0x06, + 0x05, 0x0a, 0x16, 0x12, 0x18, 0x1b, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x01, + 0x01, 0x02, 0x02, 0x0d, 0x0a, 0x07, 0x01, 0xfd, 0xfb, 0xff, 0x00, 0xfe, + 0xfd, 0xf6, 0xf1, 0xf3, 0xfa, 0x00, 0xfe, 0xfd, 0x07, 0x05, 0x03, 0x07, + 0x07, 0x0a, 0x02, 0x07, 0x10, 0x0f, 0x10, 0x1a, 0x18, 0x13, 0x0e, 0x0a, + 0x09, 0x00, 0x00, 0x00, 0xfb, 0xf3, 0xec, 0xf0, 0xf5, 0xf6, 0xfb, 0x01, + 0x0b, 0x13, 0x0b, 0x05, 0x06, 0x05, 0x00, 0x00, 0x00, 0x03, 0x06, 0x0e, + 0x14, 0x10, 0x06, 0x01, 0x01, 0x0d, 0x0b, 0x02, 0xfb, 0xfe, 0x00, 0xfd, + 0xfb, 0xff, 0x06, 0x06, 0x0d, 0x0d, 0x07, 0x07, 0x05, 0x01, 0xfe, 0xfd, + 0xfe, 0x05, 0x0a, 0x10, 0x07, 0x00, 0xff, 0x03, 0x03, 0x00, 0x01, 0x07, + 0x0b, 0x05, 0xff, 0xfd, 0xfd, 0xfe, 0x05, 0x09, 0x0b, 0x0a, 0x0b, 0x06, + 0x01, 0xfe, 0xfe, 0x03, 0x09, 0x03, 0x03, 0x02, 0x06, 0x05, 0x02, 0x00, + 0xfb, 0xfb, 0x00, 0x00, 0xfb, 0xfd, 0x00, 0x03, 0x03, 0x05, 0x09, 0x16, + 0x1d, 0x1c, 0x12, 0x05, 0xff, 0x03, 0xff, 0xfd, 0x02, 0x00, 0x06, 0x0b, + 0x0a, 0x07, 0x05, 0x07, 0x07, 0x06, 0x01, 0x00, 0x00, 0xfd, 0xfe, 0xff, + 0xfa, 0xfa, 0xfa, 0xfe, 0x03, 0x02, 0xfe, 0x02, 0x01, 0x01, 0x03, 0x01, + 0x02, 0x06, 0x09, 0x0b, 0x0a, 0x09, 0x0d, 0x0f, 0x06, 0x0a, 0x0a, 0x05, + 0x00, 0xfe, 0xff, 0xfb, 0xff, 0xfe, 0x01, 0x03, 0x0d, 0x13, 0x0f, 0x0d, + 0x0d, 0x09, 0x01, 0xfa, 0xf7, 0xfa, 0x01, 0x05, 0x0a, 0x0f, 0x10, 0x0d, + 0x05, 0xfd, 0x00, 0x01, 0xf5, 0xf1, 0xf7, 0xf9, 0xfb, 0xf7, 0xff, 0x02, + 0x0a, 0x13, 0x09, 0x0b, 0x0d, 0x0b, 0x07, 0x06, 0x02, 0x07, 0x12, 0x0f, + 0x0d, 0x03, 0xf9, 0xfa, 0xf9, 0xf5, 0xf6, 0xfa, 0x05, 0x0e, 0x12, 0x0f, + 0x0d, 0x02, 0xff, 0x01, 0x0e, 0x16, 0x0a, 0x03, 0xfd, 0xfd, 0xfb, 0xfa, + 0xfd, 0xfb, 0x03, 0xfd, 0xfd, 0x02, 0x01, 0x05, 0x05, 0x01, 0x07, 0x0d, + 0x03, 0xfd, 0xfd, 0xfd, 0x00, 0xff, 0xff, 0x03, 0x1a, 0x25, 0x1c, 0x16, + 0x0d, 0x03, 0x01, 0xff, 0xff, 0x01, 0x02, 0x00, 0x05, 0x02, 0xfe, 0xff, + 0x00, 0x03, 0xfe, 0xfa, 0xf9, 0xf6, 0xf7, 0xfd, 0x00, 0x06, 0x02, 0x03, + 0x13, 0x20, 0x09, 0x01, 0x03, 0x02, 0x03, 0x09, 0x07, 0x07, 0x0b, 0x0a, + 0x09, 0x06, 0x05, 0x05, 0x07, 0x03, 0x00, 0x00, 0xfe, 0xfe, 0xfb, 0xf5, + 0xea, 0xf3, 0xff, 0x05, 0x05, 0x0b, 0x0f, 0x0d, 0x10, 0x13, 0x13, 0x0a, + 0x06, 0x0f, 0x09, 0x07, 0x05, 0x07, 0x13, 0x12, 0x0d, 0x07, 0x00, 0xff, + 0xf6, 0xf0, 0xf1, 0xf6, 0xf6, 0xf2, 0xf7, 0xf7, 0xfd, 0x09, 0x0b, 0x06, + 0xfe, 0xfd, 0xfe, 0x0a, 0x14, 0x0f, 0x0b, 0x14, 0x14, 0x13, 0x09, 0x00, + 0xff, 0x01, 0x02, 0x06, 0xfe, 0x07, 0x12, 0x0b, 0x07, 0x02, 0x03, 0x01, + 0x09, 0x0d, 0x0b, 0x06, 0xff, 0xff, 0xfa, 0xff, 0x03, 0xff, 0xf9, 0xf5, + 0xfb, 0xfa, 0xf7, 0xfa, 0xf9, 0x07, 0x0e, 0x06, 0x01, 0x00, 0x01, 0xff, + 0xfe, 0x00, 0x00, 0x06, 0x1a, 0x30, 0x30, 0x21, 0x10, 0x09, 0x00, 0xfe, + 0x03, 0x00, 0x00, 0xfd, 0xfa, 0xfe, 0x06, 0x07, 0x07, 0x07, 0x06, 0xfd, + 0xf7, 0xf5, 0xf6, 0xf2, 0xf6, 0xfa, 0x00, 0x0a, 0x0f, 0x03, 0x00, 0x02, + 0x02, 0x00, 0x02, 0x06, 0x16, 0x1d, 0x1d, 0x13, 0x10, 0x0d, 0x09, 0x05, + 0x00, 0xff, 0x02, 0x00, 0xfe, 0xfa, 0xfa, 0xfb, 0xf6, 0xf7, 0xfa, 0xfa, + 0x03, 0x05, 0x06, 0x09, 0x0b, 0x09, 0x03, 0x09, 0x13, 0x0b, 0x05, 0xfe, + 0xff, 0xff, 0x01, 0x0b, 0x10, 0x0e, 0x10, 0x0f, 0x00, 0x06, 0x06, 0x00, + 0xfb, 0xf7, 0xf6, 0xf6, 0x01, 0x06, 0x07, 0x05, 0x03, 0x01, 0x05, 0x09, + 0x02, 0xff, 0x01, 0x06, 0x07, 0x07, 0x01, 0xfe, 0xf1, 0x00, 0x05, 0x00, + 0xfa, 0xfa, 0x02, 0x0d, 0x0f, 0x12, 0x0e, 0x0a, 0x1b, 0x25, 0x21, 0x13, + 0x0b, 0x03, 0x00, 0x01, 0xff, 0xff, 0xfd, 0xf2, 0xf3, 0xf6, 0xf3, 0xfa, + 0xfa, 0xfd, 0xff, 0xfd, 0xf9, 0xf6, 0xf7, 0xf2, 0xf0, 0xf2, 0xfa, 0x06, + 0x16, 0x1f, 0x2a, 0x24, 0x23, 0x1d, 0x14, 0x0a, 0x0b, 0x0e, 0x13, 0x0d, + 0x09, 0x06, 0x00, 0xfd, 0xfd, 0xfd, 0xfe, 0xff, 0xff, 0xfa, 0xf3, 0xee, + 0xf9, 0x00, 0xfe, 0xfb, 0x06, 0x00, 0x00, 0x00, 0xfe, 0xfb, 0xfd, 0x02, + 0x0f, 0x18, 0x12, 0x0e, 0x10, 0x12, 0x0b, 0x0b, 0x0a, 0x03, 0x09, 0x0b, + 0x02, 0x02, 0xff, 0xfa, 0xfe, 0xf9, 0xed, 0xed, 0xfb, 0x06, 0x05, 0xff, + 0x02, 0x0b, 0x18, 0x14, 0x0d, 0x06, 0x02, 0x02, 0x02, 0x01, 0xfa, 0xfb, + 0x07, 0x12, 0x0f, 0x0e, 0x00, 0xf7, 0xfb, 0xfa, 0xf7, 0xf9, 0xfd, 0x00, + 0x0e, 0x12, 0x0b, 0x0b, 0x0b, 0x0e, 0x0e, 0x03, 0xfb, 0xfd, 0x03, 0x03, + 0x06, 0x07, 0x09, 0x0a, 0x02, 0xf3, 0xf3, 0xf5, 0xfa, 0xfd, 0xfa, 0x00, + 0x00, 0xfb, 0x07, 0x12, 0x18, 0x17, 0x16, 0x0f, 0x0f, 0x10, 0x0d, 0x00, + 0xfd, 0x01, 0x01, 0xfd, 0x00, 0x0a, 0x0a, 0xff, 0xfb, 0xfe, 0xfb, 0x00, + 0xfe, 0xf9, 0xfa, 0xfe, 0xfb, 0xf9, 0xfa, 0xfd, 0x05, 0x07, 0x0f, 0x14, + 0x10, 0x13, 0x13, 0x0e, 0x0b, 0x05, 0x03, 0x07, 0x0a, 0x07, 0x03, 0x01, + 0x00, 0x00, 0x05, 0x0f, 0x0d, 0x06, 0x01, 0xfe, 0xff, 0xf9, 0xf9, 0xfd, + 0x06, 0x02, 0xff, 0xf7, 0x00, 0x09, 0x02, 0xfe, 0x00, 0x01, 0x09, 0x07, + 0x06, 0x05, 0x05, 0x01, 0xfb, 0x03, 0x05, 0x06, 0x0f, 0x0b, 0x01, 0xff, + 0xff, 0xff, 0xfe, 0xfd, 0x0f, 0x13, 0x0f, 0x0b, 0x0f, 0x13, 0x0f, 0x06, + 0xff, 0xfe, 0xfb, 0xfa, 0x00, 0x03, 0x09, 0x06, 0x01, 0x0b, 0x07, 0x01, + 0xfa, 0xf9, 0xfa, 0xf7, 0xf2, 0xf0, 0xf6, 0x01, 0x10, 0x12, 0x0a, 0x02, + 0x06, 0x0f, 0x0a, 0x09, 0x09, 0x09, 0x0d, 0x0d, 0x0a, 0x07, 0x05, 0x06, + 0x03, 0xfd, 0xee, 0xf1, 0xf6, 0xf7, 0xf9, 0x01, 0x0a, 0x06, 0x00, 0x0b, + 0x21, 0x20, 0x10, 0x09, 0x0e, 0x13, 0x0b, 0x03, 0x06, 0x05, 0xfe, 0xf7, + 0xfb, 0xfb, 0xfb, 0xfd, 0xf7, 0xfb, 0x02, 0x01, 0x03, 0x02, 0x00, 0xfd, + 0xfb, 0xfa, 0xf7, 0xf9, 0x0b, 0x13, 0x0d, 0x13, 0x25, 0x1d, 0x14, 0x13, + 0x10, 0x05, 0x00, 0xfd, 0x00, 0x02, 0xfe, 0xfd, 0xfd, 0x00, 0x01, 0x01, + 0x01, 0xfe, 0xfd, 0xfe, 0xfe, 0xfe, 0xfa, 0xff, 0x13, 0x13, 0x01, 0xf9, + 0x01, 0x07, 0x0a, 0x05, 0x02, 0x03, 0x06, 0x10, 0x0e, 0x13, 0x12, 0x0d, + 0x09, 0x03, 0x02, 0x01, 0x02, 0x00, 0xf9, 0xf2, 0xee, 0xee, 0xf9, 0x06, + 0x09, 0x09, 0x05, 0x03, 0x10, 0x0b, 0x06, 0x0d, 0x0f, 0x0d, 0x07, 0x0a, + 0x0a, 0x03, 0x06, 0x06, 0x09, 0x06, 0x09, 0x0a, 0x01, 0xf7, 0xfb, 0x00, + 0xfb, 0xfb, 0xf7, 0xfe, 0x0a, 0x05, 0x02, 0xff, 0x00, 0x00, 0xfd, 0x00, + 0x06, 0x05, 0x01, 0x0b, 0x0b, 0x0a, 0x07, 0x09, 0x0a, 0x0a, 0x0a, 0xff, + 0x00, 0xff, 0xfe, 0x02, 0x01, 0x02, 0x0d, 0x0d, 0x16, 0x10, 0x0d, 0x0e, + 0x17, 0x12, 0x0d, 0x0e, 0x06, 0x00, 0xf7, 0xfa, 0xf3, 0xec, 0xf0, 0xf5, + 0xf6, 0xf6, 0x05, 0x00, 0xfe, 0xfd, 0xfd, 0xfb, 0xfa, 0xfd, 0xfe, 0x06, + 0x0f, 0x0d, 0x0f, 0x13, 0x1a, 0x1d, 0x13, 0x10, 0x0f, 0x0b, 0x07, 0xfe, + 0x01, 0x03, 0x06, 0x06, 0x02, 0xfe, 0xfe, 0x01, 0x05, 0x00, 0xfe, 0xfd, + 0xfb, 0xfb, 0xfe, 0x0e, 0x12, 0x03, 0x02, 0xfd, 0xff, 0xfe, 0xfe, 0x05, + 0x02, 0xff, 0x02, 0x03, 0x0b, 0x0e, 0x09, 0x07, 0x05, 0x03, 0x06, 0x03, + 0x03, 0x06, 0x09, 0x09, 0x02, 0x00, 0xff, 0x05, 0x0f, 0x07, 0xfa, 0xff, + 0x07, 0x03, 0xfa, 0xfe, 0x02, 0x06, 0x03, 0x02, 0xfe, 0xfb, 0xff, 0x03, + 0x03, 0x0a, 0x06, 0x06, 0x07, 0x09, 0x00, 0xf7, 0xfd, 0xfe, 0xfe, 0x03, + 0x12, 0x10, 0x09, 0x07, 0x13, 0x12, 0x06, 0x05, 0x05, 0x03, 0x00, 0x01, + 0x02, 0x00, 0xfd, 0xfd, 0xf6, 0xf6, 0x01, 0x00, 0xff, 0xf3, 0xf3, 0xf7, + 0x00, 0x06, 0x0a, 0x10, 0x1b, 0x1f, 0x16, 0x13, 0x1b, 0x17, 0x0a, 0x0d, + 0x10, 0x0a, 0x02, 0xfe, 0xf9, 0xf7, 0xf6, 0xf7, 0xf6, 0xf9, 0xfa, 0xfd, + 0xfe, 0xf7, 0xf9, 0xf5, 0xf2, 0xf0, 0xea, 0xf7, 0x0b, 0x0d, 0x0a, 0x0a, + 0x10, 0x10, 0x17, 0x24, 0x23, 0x18, 0x13, 0x14, 0x0b, 0x03, 0x07, 0x05, + 0x03, 0x02, 0x03, 0x01, 0x00, 0xfe, 0x00, 0x03, 0x02, 0xff, 0xff, 0x05, + 0x07, 0x07, 0xff, 0xf9, 0xfd, 0xf3, 0xec, 0xf2, 0xfa, 0x03, 0x05, 0x01, + 0xfe, 0xff, 0x0b, 0x0a, 0x0b, 0x09, 0x0a, 0x0b, 0x07, 0x05, 0x09, 0x0a, + 0x05, 0x01, 0x01, 0x01, 0x07, 0x10, 0x0a, 0x02, 0x00, 0x0b, 0x07, 0x09, + 0x09, 0x0a, 0x03, 0xfd, 0xfb, 0xfd, 0x01, 0x02, 0xfd, 0xfb, 0x01, 0x0b, + 0x03, 0x05, 0x05, 0x01, 0xfb, 0xfd, 0x06, 0x03, 0x03, 0x0d, 0x0a, 0x0a, + 0x09, 0x09, 0x02, 0x00, 0xfe, 0x02, 0x02, 0x01, 0xfa, 0xff, 0x0f, 0x12, + 0x09, 0x06, 0x06, 0x05, 0x02, 0xff, 0x01, 0xf7, 0xf6, 0xfa, 0xf7, 0xf3, + 0x01, 0x1b, 0x14, 0x0e, 0x0e, 0x12, 0x12, 0x16, 0x10, 0x0b, 0x06, 0x03, + 0x01, 0xfe, 0xfa, 0xf7, 0xf2, 0xf3, 0xf7, 0xf9, 0xfb, 0x05, 0x06, 0x06, + 0x0a, 0x06, 0x01, 0xfe, 0x01, 0x0e, 0x07, 0x05, 0x06, 0x0a, 0x07, 0x00, + 0x02, 0x07, 0x13, 0x10, 0x07, 0x0a, 0x05, 0xfb, 0x05, 0x02, 0x05, 0x02, + 0x01, 0x05, 0x09, 0x0a, 0x05, 0x02, 0x03, 0xfe, 0x01, 0x0b, 0x06, 0x06, + 0xff, 0x03, 0xff, 0xf6, 0xfe, 0xfd, 0xfb, 0x00, 0xfb, 0xf7, 0xf5, 0xf9, + 0x00, 0xfd, 0xff, 0x00, 0x0a, 0x0a, 0x0b, 0x0a, 0x07, 0x0a, 0x10, 0x0a, + 0x0f, 0x18, 0x1b, 0x17, 0x10, 0x0e, 0x03, 0xfe, 0x06, 0x07, 0x03, 0x00, + 0xff, 0xfe, 0x00, 0x02, 0x00, 0x03, 0x09, 0x02, 0xfa, 0xfa, 0xff, 0xfd, + 0xfb, 0xfa, 0xf1, 0xed, 0xf3, 0x09, 0x1a, 0x10, 0x07, 0x06, 0x0d, 0x0e, + 0x0b, 0x03, 0x03, 0x01, 0xff, 0x00, 0xfd, 0xff, 0x05, 0x05, 0x05, 0x02, + 0xfd, 0x00, 0x06, 0x03, 0x06, 0x06, 0x02, 0xff, 0xfe, 0x06, 0x0f, 0x10, + 0x0b, 0x06, 0x0a, 0x0f, 0x10, 0x07, 0x09, 0x0d, 0x07, 0x05, 0x02, 0x00, + 0x03, 0xfe, 0xf9, 0xf9, 0xf5, 0xfa, 0xff, 0x00, 0xff, 0xfe, 0xfe, 0xfa, + 0xfb, 0xfe, 0x03, 0x00, 0x05, 0x06, 0x0b, 0x10, 0x12, 0x13, 0x12, 0x18, + 0x13, 0x0d, 0x0b, 0x06, 0x03, 0xf6, 0xf5, 0xf3, 0xf9, 0x07, 0x0b, 0x06, + 0x00, 0x06, 0x09, 0x02, 0xfe, 0xfb, 0x05, 0x0b, 0x0d, 0x05, 0xfe, 0xfd, + 0x01, 0xf9, 0xf7, 0xf6, 0xfa, 0xfe, 0x02, 0x05, 0x0b, 0x0e, 0x12, 0x0f, + 0x0b, 0x0b, 0x09, 0x06, 0x03, 0x00, 0x01, 0xfd, 0xfa, 0xfd, 0x13, 0x1c, + 0x16, 0x12, 0x0e, 0x14, 0x03, 0xf7, 0xfe, 0x02, 0x00, 0x00, 0x01, 0x02, + 0x02, 0x03, 0x03, 0x06, 0xff, 0xfd, 0xff, 0x00, 0xfb, 0xfd, 0x0e, 0x09, + 0x00, 0xfa, 0x00, 0x0b, 0x07, 0x02, 0xfa, 0xfb, 0xfe, 0xf9, 0xfb, 0x00, + 0x0f, 0x0d, 0x02, 0x00, 0x05, 0x09, 0x0a, 0x09, 0x05, 0x05, 0x13, 0x14, + 0x0e, 0x07, 0x05, 0x02, 0xfa, 0xf7, 0xfb, 0x06, 0x09, 0x13, 0x0e, 0x0f, + 0x18, 0x10, 0x0e, 0x0a, 0x07, 0x05, 0x00, 0xfe, 0xf7, 0xf1, 0xf1, 0xf0, + 0xf1, 0xf3, 0x02, 0xff, 0xfe, 0x01, 0x0b, 0x05, 0xfe, 0xfd, 0x00, 0x09, + 0x09, 0x07, 0x03, 0x01, 0x06, 0x02, 0x03, 0x06, 0x07, 0x12, 0x0f, 0x10, + 0x10, 0x12, 0x18, 0x05, 0xfe, 0x01, 0x02, 0x05, 0xff, 0xfa, 0xfb, 0xfa, + 0xfa, 0xfe, 0xfe, 0x0d, 0x16, 0x0f, 0x0b, 0x05, 0x07, 0x02, 0x02, 0x02, + 0xfa, 0xfa, 0x00, 0x00, 0xfd, 0xf7, 0xf7, 0xfe, 0x06, 0x0b, 0x09, 0x02, + 0x00, 0x03, 0x0a, 0x0d, 0x05, 0x01, 0x07, 0x16, 0x1a, 0x16, 0x0d, 0x03, + 0x06, 0x03, 0xfa, 0xed, 0xf9, 0x0a, 0x0b, 0x05, 0x02, 0x03, 0x02, 0x01, + 0xfe, 0x00, 0x00, 0xfe, 0xfd, 0xfb, 0xfa, 0xfa, 0x02, 0x01, 0x02, 0x00, + 0x02, 0x06, 0x0b, 0x03, 0x03, 0x18, 0x14, 0x0f, 0x0d, 0x07, 0x06, 0x09, + 0x03, 0xfd, 0xf9, 0xf5, 0xf9, 0x00, 0x06, 0x10, 0x0e, 0x0b, 0x0b, 0x0f, + 0x0b, 0x06, 0xf9, 0xf1, 0x02, 0x05, 0x05, 0x02, 0x06, 0x0d, 0x0d, 0x12, + 0x10, 0x0f, 0x07, 0x05, 0x02, 0x02, 0x00, 0x02, 0xff, 0x00, 0x00, 0xfd, + 0xf5, 0xf2, 0xee, 0xec, 0xe9, 0xf0, 0xf6, 0xfa, 0x0b, 0x16, 0x0d, 0x09, + 0x09, 0x10, 0x09, 0x05, 0x05, 0x0b, 0x12, 0x1d, 0x20, 0x17, 0x12, 0x17, + 0x14, 0x07, 0xfa, 0xfe, 0x02, 0x00, 0xfe, 0xff, 0x01, 0x03, 0x00, 0x00, + 0x06, 0x09, 0x00, 0xfa, 0xf2, 0xfb, 0xfb, 0xfd, 0xfd, 0xfb, 0x05, 0x0a, + 0x03, 0xff, 0x00, 0x06, 0x02, 0x02, 0x01, 0x0b, 0x0a, 0x03, 0x01, 0x01, + 0x05, 0x03, 0xff, 0xfe, 0x02, 0x13, 0x0f, 0x0d, 0x07, 0x03, 0x12, 0x18, + 0x13, 0x00, 0xfb, 0x00, 0x01, 0x02, 0xf9, 0xf9, 0xfd, 0xf9, 0xf9, 0x02, + 0x12, 0x0e, 0x05, 0x03, 0x07, 0x00, 0x00, 0x0a, 0x07, 0x0d, 0x0f, 0x0a, + 0xfe, 0xf6, 0xfe, 0x09, 0x05, 0x01, 0x06, 0x0a, 0x03, 0x01, 0xfd, 0x00, + 0x05, 0x01, 0xfd, 0x00, 0x07, 0x0d, 0x09, 0x05, 0x00, 0xfe, 0xfd, 0x00, + 0xfe, 0xfa, 0x0f, 0x12, 0x09, 0x02, 0x0b, 0x1a, 0x14, 0x0e, 0x0e, 0x0e, + 0x02, 0xfd, 0xf9, 0x00, 0x05, 0xf9, 0xf6, 0xfe, 0x00, 0xfe, 0xfd, 0xf3, + 0xee, 0xf1, 0xf6, 0x01, 0x0b, 0x12, 0x18, 0x0d, 0x01, 0xf9, 0xf7, 0x05, + 0x09, 0x07, 0x0e, 0x14, 0x1b, 0x16, 0x1f, 0x1f, 0x1b, 0x18, 0x12, 0x0b, + 0x05, 0xf5, 0xf2, 0xf2, 0xf1, 0xf9, 0xfd, 0xf9, 0xfa, 0xfb, 0x05, 0x07, + 0x00, 0xf5, 0xf1, 0xfa, 0x0a, 0x16, 0x10, 0x0e, 0x02, 0xfe, 0xff, 0xf7, + 0xee, 0xf7, 0xf7, 0xf7, 0xf9, 0x02, 0x17, 0x0b, 0x07, 0x12, 0x0f, 0x0b, + 0x06, 0x06, 0x0a, 0x0f, 0x0a, 0x07, 0x05, 0x0e, 0x1a, 0x17, 0x13, 0x12, + 0x02, 0xf5, 0xf9, 0xfb, 0x00, 0x02, 0xff, 0x06, 0x01, 0xff, 0x00, 0xf7, + 0xf9, 0xf9, 0xfb, 0xf7, 0xf1, 0xfb, 0x09, 0x1b, 0x1a, 0x0e, 0x05, 0x05, + 0x02, 0x0b, 0x09, 0x0a, 0x07, 0x00, 0xfe, 0xff, 0x01, 0x02, 0x00, 0xfb, + 0x00, 0xfb, 0xf9, 0xf9, 0x00, 0x05, 0x05, 0x00, 0x00, 0x0b, 0x0f, 0x17, + 0x0d, 0xfd, 0xf6, 0xf7, 0x00, 0x0d, 0x13, 0x12, 0x10, 0x17, 0x12, 0x0f, + 0x10, 0x12, 0x0e, 0x02, 0xfe, 0xf9, 0xf7, 0xf2, 0xf6, 0xf7, 0x00, 0xfe, + 0xf0, 0xf1, 0xf5, 0x01, 0x0a, 0x02, 0xfb, 0xf7, 0xfe, 0x09, 0x13, 0x1c, + 0x18, 0x0f, 0x0f, 0x0b, 0x07, 0x13, 0x0f, 0x0e, 0x10, 0x0a, 0x07, 0x0e, + 0x02, 0xfb, 0x00, 0x06, 0x00, 0xf7, 0xf6, 0xfa, 0x01, 0xfe, 0xf2, 0xf5, + 0xfd, 0xff, 0x00, 0x09, 0x05, 0x03, 0xfe, 0xff, 0xff, 0x03, 0x06, 0x06, + 0xfd, 0x00, 0x05, 0x0a, 0x07, 0x10, 0x09, 0x09, 0x02, 0x00, 0x00, 0x03, + 0x0e, 0x1d, 0x17, 0x0e, 0x10, 0x13, 0x12, 0x17, 0x10, 0x09, 0x00, 0xfd, + 0xed, 0xf2, 0xf9, 0xf9, 0xf9, 0xfa, 0xf7, 0xf9, 0xf7, 0xf7, 0xf9, 0x01, + 0x03, 0x03, 0x01, 0x06, 0x0b, 0x1c, 0x0a, 0x05, 0x02, 0x00, 0x01, 0x05, + 0x03, 0x00, 0xfd, 0x09, 0x0a, 0x03, 0x05, 0x0a, 0x05, 0x00, 0xfd, 0xfd, + 0xfb, 0xfd, 0x00, 0x01, 0x07, 0x07, 0x0a, 0x0e, 0x0d, 0x14, 0x10, 0x03, + 0xf9, 0x01, 0x05, 0x07, 0x14, 0x23, 0x1c, 0x10, 0x09, 0x01, 0x00, 0xff, + 0xfb, 0xf7, 0xf9, 0xf3, 0xf1, 0xfd, 0x00, 0xff, 0x01, 0x03, 0x01, 0xf6, + 0xe6, 0xed, 0xfb, 0x00, 0x05, 0x0a, 0x07, 0x0a, 0x10, 0x16, 0x0e, 0x0d, + 0x0b, 0x07, 0x07, 0x0b, 0x13, 0x10, 0x0d, 0x0d, 0x0d, 0x0b, 0x0b, 0xfb, + 0xea, 0xf5, 0xf5, 0xf9, 0xf6, 0xf7, 0x00, 0x0e, 0x0a, 0x05, 0x07, 0x10, + 0x0b, 0x0b, 0x05, 0xff, 0xff, 0xfe, 0x01, 0x03, 0x02, 0x07, 0x07, 0xfe, + 0xf6, 0xfd, 0xff, 0xff, 0x07, 0x0b, 0x06, 0x02, 0x02, 0x09, 0x0d, 0x16, + 0x0d, 0x07, 0x07, 0x07, 0x01, 0x07, 0x0e, 0x10, 0x0e, 0x13, 0x0b, 0xf9, + 0xf2, 0xf9, 0xf6, 0xf0, 0xf7, 0xfd, 0xfa, 0xf9, 0xfd, 0x01, 0x03, 0x03, + 0x02, 0x02, 0xfe, 0x07, 0x0b, 0x09, 0x0a, 0x0f, 0x0f, 0x0a, 0x16, 0x0b, + 0x03, 0x01, 0x09, 0x0a, 0x02, 0xf7, 0xf5, 0xfa, 0xfe, 0x00, 0x00, 0x0a, + 0x05, 0x02, 0x0b, 0x0f, 0x0d, 0x02, 0xff, 0x03, 0x0f, 0x0d, 0x0b, 0x00, + 0x00, 0x03, 0x02, 0x09, 0x0e, 0x0a, 0x07, 0x07, 0x05, 0x00, 0xfe, 0x00, + 0x02, 0x0b, 0x06, 0xfe, 0xf6, 0xf2, 0xf6, 0xfa, 0xf2, 0xf2, 0xf2, 0xe9, + 0xf5, 0x07, 0x07, 0x0d, 0x13, 0x0e, 0x09, 0x10, 0x0e, 0x0f, 0x0d, 0x0e, + 0x10, 0x0b, 0x0a, 0x0a, 0x10, 0x0f, 0x10, 0x13, 0x0b, 0x05, 0x00, 0xfa, + 0xf7, 0xf6, 0xfa, 0x02, 0x05, 0x10, 0x0b, 0x05, 0xfe, 0xf7, 0xf3, 0x01, + 0x00, 0xfe, 0xfa, 0x0a, 0x02, 0x00, 0x00, 0xff, 0x02, 0x09, 0x02, 0xf7, + 0xf7, 0xfd, 0x01, 0x0b, 0x14, 0x06, 0x00, 0x03, 0x07, 0x18, 0x13, 0x0b, + 0x0d, 0x0e, 0x0b, 0x0e, 0x0e, 0x14, 0x0a, 0x07, 0x05, 0xfd, 0xf5, 0xe1, + 0xdf, 0xf0, 0xf9, 0x00, 0x00, 0x06, 0x05, 0x02, 0x02, 0x06, 0x0b, 0x0b, + 0x02, 0x05, 0x0d, 0x0f, 0x0e, 0x12, 0x12, 0x0f, 0x17, 0x0f, 0x03, 0xfb, + 0xff, 0x00, 0xf9, 0xf5, 0xf3, 0xfd, 0x02, 0x06, 0x01, 0x01, 0xf9, 0xf6, + 0xf5, 0xfb, 0xff, 0x01, 0x02, 0x02, 0x14, 0x21, 0x1a, 0x1c, 0x10, 0x00, + 0x01, 0x02, 0x00, 0x05, 0x0d, 0x0a, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0xf9, 0xf2, 0xec, 0xf2, 0xfa, 0xfb, 0x02, 0xff, 0xff, 0x07, + 0xff, 0x01, 0x0d, 0x0b, 0x09, 0x0d, 0x10, 0x09, 0x07, 0x18, 0x17, 0x0e, + 0x06, 0x09, 0x0b, 0x0f, 0x0e, 0x07, 0x03, 0x06, 0x02, 0x01, 0xff, 0xf3, + 0xf3, 0xf9, 0x00, 0x07, 0x02, 0x00, 0x05, 0x00, 0x00, 0x05, 0x0f, 0x0d, + 0x02, 0x01, 0x02, 0xf9, 0xf2, 0xf6, 0xfd, 0x00, 0x00, 0xfd, 0xf7, 0x00, + 0x02, 0xfb, 0xfa, 0x0b, 0x14, 0x0a, 0x05, 0x13, 0x1f, 0x14, 0x13, 0x13, + 0x10, 0x16, 0x10, 0x0d, 0x03, 0x00, 0x05, 0x05, 0xfe, 0xfd, 0xfd, 0xf1, + 0xfd, 0x05, 0x07, 0x02, 0x00, 0xf7, 0xf3, 0xf9, 0xfb, 0xfd, 0x00, 0x00, + 0x0e, 0x0d, 0x0a, 0x13, 0x10, 0x0f, 0x13, 0x0e, 0x07, 0x00, 0xfe, 0xfb, + 0xfb, 0x03, 0x01, 0xff, 0x01, 0xff, 0xfe, 0xfd, 0xfd, 0xfd, 0xf5, 0xf9, + 0x02, 0x10, 0x13, 0x0d, 0x16, 0x1b, 0x0f, 0x07, 0x05, 0x0f, 0x0a, 0xfb, + 0xfe, 0xfd, 0xfb, 0x0d, 0x0a, 0x0a, 0x07, 0x05, 0x05, 0x02, 0x05, 0x05, + 0x00, 0xf9, 0xf5, 0xf9, 0xfb, 0xff, 0x00, 0xff, 0xf7, 0x05, 0x01, 0xfe, + 0x05, 0x10, 0x12, 0x16, 0x0f, 0x0a, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x01, 0x09, 0x02, 0x0e, 0x10, 0x0a, 0x0a, 0x0b, 0x03, 0xf7, + 0xfb, 0x05, 0x0b, 0x00, 0x05, 0x0d, 0x0a, 0x03, 0x00, 0xff, 0xf9, 0xf9, + 0x00, 0xfb, 0xfb, 0xfe, 0x00, 0x09, 0x00, 0xf9, 0xf6, 0x00, 0xfe, 0xf6, + 0xf5, 0xfe, 0x0a, 0x16, 0x0d, 0x0d, 0x18, 0x1b, 0x23, 0x25, 0x1d, 0x12, + 0x10, 0x09, 0xfe, 0xf9, 0xfb, 0xfb, 0xfb, 0xff, 0x01, 0x01, 0xf7, 0xf3, + 0xf9, 0xfa, 0xf7, 0xfa, 0xfd, 0xfe, 0x05, 0x06, 0x0d, 0x10, 0x16, 0x0f, + 0x07, 0x07, 0x0d, 0x0e, 0x06, 0x07, 0x00, 0xf3, 0xf6, 0x03, 0x03, 0x01, + 0xfd, 0xff, 0xfe, 0xf9, 0xf7, 0xf6, 0xfe, 0x00, 0x00, 0x00, 0x07, 0x0d, + 0x0d, 0x07, 0x0d, 0x16, 0x0e, 0x14, 0x1b, 0x16, 0x1d, 0x1c, 0x0d, 0xfb, + 0xf9, 0xfb, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xf5, 0xf2, 0x01, + 0xfe, 0xf6, 0xf9, 0xfb, 0xf3, 0xf6, 0xf3, 0x07, 0x0a, 0x07, 0x16, 0x17, + 0x16, 0x0f, 0x07, 0x00, 0x00, 0xff, 0x01, 0x03, 0x09, 0x0f, 0x12, 0x0a, + 0x05, 0x01, 0x06, 0x0a, 0x05, 0x00, 0x00, 0x07, 0x0a, 0x09, 0xf7, 0xf9, + 0x02, 0x0d, 0x14, 0x05, 0x00, 0xff, 0xff, 0xfe, 0xf9, 0x00, 0x09, 0x05, + 0x00, 0x00, 0xfe, 0xfb, 0xf6, 0xf5, 0xf5, 0xff, 0x02, 0xfe, 0x00, 0x07, + 0x02, 0x05, 0x0f, 0x10, 0x1b, 0x20, 0x20, 0x1a, 0x12, 0x09, 0x02, 0xff, + 0xf9, 0xf7, 0xff, 0x09, 0x06, 0x01, 0x00, 0x02, 0x07, 0x05, 0xf6, 0xfe, + 0xfe, 0xfb, 0xfe, 0x00, 0xfd, 0xfe, 0x00, 0x02, 0x0f, 0x17, 0x12, 0x0a, + 0x0d, 0x0d, 0x14, 0x06, 0x00, 0xfb, 0x00, 0x01, 0x00, 0xf6, 0xf3, 0xf6, + 0xf6, 0xfb, 0xfe, 0xfd, 0xfd, 0x07, 0x06, 0x02, 0x0a, 0x07, 0x06, 0x0a, + 0x0d, 0x1f, 0x1c, 0x0a, 0x0a, 0x0d, 0x0e, 0x12, 0x0f, 0x00, 0xf1, 0xf1, + 0xf6, 0x06, 0x0a, 0x07, 0x09, 0x0d, 0x0a, 0x09, 0x05, 0xfe, 0xf9, 0xf3, + 0xf3, 0xf1, 0xee, 0xec, 0xf2, 0x0a, 0x14, 0x1a, 0x0f, 0x05, 0x02, 0x05, + 0x00, 0xfb, 0xfe, 0xfe, 0x02, 0x05, 0x07, 0x0a, 0x05, 0x00, 0x01, 0x01, + 0x01, 0x0f, 0x0f, 0x0f, 0x12, 0x1a, 0x1f, 0x1a, 0x0f, 0x0d, 0x10, 0x06, + 0xfe, 0xfe, 0xf9, 0xf7, 0xfb, 0xf7, 0xf9, 0xfb, 0xfb, 0x03, 0x00, 0xf7, + 0xf6, 0xf9, 0xf2, 0xec, 0xf3, 0x00, 0x05, 0x00, 0x01, 0x02, 0x00, 0x01, + 0x07, 0x1b, 0x30, 0x24, 0x21, 0x1f, 0x1f, 0x14, 0x0a, 0x02, 0x00, 0x00, + 0xfb, 0xf9, 0xf6, 0xf9, 0xf6, 0x00, 0x0a, 0x09, 0x02, 0xf5, 0xf3, 0xfe, + 0xf3, 0xf6, 0xfe, 0x00, 0x00, 0x05, 0x21, 0x1c, 0x0f, 0x09, 0x07, 0x05, + 0x03, 0x02, 0xf9, 0xfb, 0x00, 0x0d, 0x0b, 0x02, 0xfe, 0x00, 0x00, 0xfe, + 0xfe, 0xfe, 0xfe, 0xfb, 0xfe, 0x05, 0x00, 0x00, 0x01, 0x07, 0x1a, 0x1f, + 0x12, 0x0f, 0x07, 0x0d, 0x12, 0x14, 0x0d, 0x05, 0x00, 0xf6, 0xf9, 0xf9, + 0x00, 0x05, 0x02, 0x05, 0x02, 0x00, 0x05, 0x07, 0xff, 0x01, 0x00, 0xfb, + 0xf6, 0xf1, 0x00, 0x0d, 0x0d, 0x07, 0x02, 0x00, 0xfe, 0xfe, 0xfb, 0xf9, + 0xfb, 0x00, 0x05, 0x07, 0x02, 0x0d, 0x07, 0x05, 0x00, 0x00, 0x00, 0x05, + 0x14, 0x0d, 0x05, 0x0b, 0x16, 0x1d, 0x1c, 0x24, 0x1b, 0x02, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0xfb, 0xfe, 0x00, 0xfa, 0xf3, + 0xe6, 0xec, 0xf0, 0xf1, 0x07, 0x05, 0x00, 0x00, 0xfe, 0x05, 0x05, 0x16, + 0x25, 0x1a, 0x0d, 0x0e, 0x0d, 0x07, 0x05, 0x05, 0x05, 0x0d, 0x03, 0x00, + 0x02, 0x02, 0x07, 0x0d, 0x14, 0x0f, 0x0a, 0x05, 0xf7, 0xf6, 0xf3, 0xf1, + 0xf9, 0x02, 0x02, 0x01, 0x0d, 0x07, 0x07, 0x00, 0x05, 0x05, 0xfe, 0xf6, + 0xf9, 0xf9, 0xfb, 0x02, 0x05, 0x05, 0x05, 0x02, 0x00, 0x00, 0x02, 0x03, + 0x00, 0x0d, 0x0f, 0x0a, 0x07, 0x10, 0x0f, 0x0d, 0x1a, 0x12, 0x06, 0x02, + 0x02, 0x00, 0x02, 0x05, 0x02, 0xfe, 0xfd, 0xfb, 0xf7, 0xff, 0x02, 0x0a, + 0x03, 0x00, 0xfe, 0xfb, 0xfe, 0x05, 0x00, 0xff, 0x07, 0x0d, 0xfb, 0xfb, + 0x0d, 0x13, 0x0d, 0x07, 0x03, 0x02, 0x02, 0x00, 0x00, 0xfe, 0xfe, 0xfe, + 0xff, 0x00, 0x05, 0x00, 0xfe, 0xfb, 0xfd, 0x00, 0x00, 0x0d, 0x17, 0x1a, + 0x14, 0x1a, 0x14, 0x12, 0x1a, 0x21, 0x1a, 0x00, 0xf6, 0xf7, 0xfa, 0xfe, + 0x0a, 0x0d, 0x00, 0xfb, 0xfe, 0x05, 0x07, 0x00, 0xf6, 0xee, 0xee, 0xf1, + 0xf0, 0xfb, 0xfb, 0xfb, 0x00, 0x01, 0xfe, 0xf9, 0xfb, 0x07, 0x0f, 0x1f, + 0x1a, 0x12, 0x0f, 0x0a, 0x05, 0x02, 0x03, 0x01, 0x01, 0x01, 0x09, 0x0e, + 0x0b, 0x10, 0x13, 0x0e, 0x0b, 0x13, 0x06, 0xf5, 0x03, 0x09, 0x06, 0x03, + 0x03, 0x0b, 0x06, 0x06, 0xfd, 0xf7, 0xfb, 0xf6, 0xf0, 0xf0, 0xfa, 0xf2, + 0xf2, 0x0a, 0x13, 0x0e, 0x03, 0x00, 0xfd, 0xfd, 0xf7, 0xfd, 0x03, 0x03, + 0x0d, 0x0b, 0x0d, 0x13, 0x0b, 0x17, 0x1c, 0x1b, 0x10, 0x06, 0x06, 0x09, + 0x09, 0x03, 0x06, 0x0d, 0x09, 0x06, 0xfa, 0xf2, 0xf5, 0xfb, 0xfd, 0xf7, + 0xf1, 0xf2, 0x01, 0x18, 0x1d, 0x0b, 0xf2, 0xf2, 0xf2, 0x03, 0x09, 0x09, + 0x03, 0x00 +}; diff --git a/examples/PlayMODFromPROGMEMToPWM/PlayMODFromPROGMEMToPWM.ino b/examples/PlayMODFromPROGMEMToPWM/PlayMODFromPROGMEMToPWM.ino new file mode 100644 index 00000000..7bab25d6 --- /dev/null +++ b/examples/PlayMODFromPROGMEMToPWM/PlayMODFromPROGMEMToPWM.ino @@ -0,0 +1,47 @@ +#include +#include "AudioFileSourcePROGMEM.h" +#include "AudioGeneratorMOD.h" +#include "AudioOutputPWM.h" + +#if !defined(ARDUINO_ARCH_RP2040) +void setup() { + Serial.begin(115200); + Serial.printf("Only for the RP2040/Raspberry Pi Pico\n"); +} + +void loop() { +} +#else + +// 5_steps.mod sample from the mod archive: https://modarchive.org/ +#include "5steps.h" + +AudioGeneratorMOD *mod; +AudioFileSourcePROGMEM *file; +AudioOutputPWM *out; + +void setup() +{ + Serial.begin(115200); + delay(1000); + + audioLogger = &Serial; + file = new AudioFileSourcePROGMEM(steps_mod, sizeof(steps_mod)); + out = new AudioOutputPWM(); + mod = new AudioGeneratorMOD(); + mod->SetBufferSize(3*1024); + mod->SetSampleRate(44100); + mod->SetStereoSeparation(32); + mod->begin(file, out); +} + +void loop() +{ + if (mod->isRunning()) { + if (!mod->loop()) mod->stop(); + } else { + Serial.printf("MOD done\n"); + delay(1000); + } +} +#endif diff --git a/keywords.txt b/keywords.txt index 75b11139..a718a06d 100644 --- a/keywords.txt +++ b/keywords.txt @@ -23,6 +23,7 @@ AudioOutput KEYWORD1 AudioOutputI2S KEYWORD1 AudioOutputI2SNoDAC KEYWORD1 AudioOutputI2SClass KEYWORD1 +AudioOutputPWM KEYWORD1 AudioOutputNull KEYWORD1 AudioOutputBuffer KEYWORD1 AudioOutputSerialWAV KEYWORD1 diff --git a/src/AudioGeneratorWAV.cpp b/src/AudioGeneratorWAV.cpp index 6c8f7a24..fead809c 100644 --- a/src/AudioGeneratorWAV.cpp +++ b/src/AudioGeneratorWAV.cpp @@ -127,7 +127,7 @@ bool AudioGeneratorWAV::ReadWAVInfo() return false; }; if (u32 != 0x46464952) { - Serial.printf_P(PSTR("AudioGeneratorWAV::ReadWAVInfo: cannot read WAV, invalid RIFF header, got: %08X \n"), (uint32_t) u32); + Serial.printf_P(PSTR("AudioGeneratorWAV::ReadWAVInfo: cannot read WAV, invalid RIFF header\n")); return false; } @@ -143,7 +143,7 @@ bool AudioGeneratorWAV::ReadWAVInfo() return false; }; if (u32 != 0x45564157) { - Serial.printf_P(PSTR("AudioGeneratorWAV::ReadWAVInfo: cannot read WAV, invalid WAVE header, got: %08X \n"), (uint32_t) u32); + Serial.printf_P(PSTR("AudioGeneratorWAV::ReadWAVInfo: cannot read WAV, invalid WAVE header\n")); return false; } diff --git a/src/AudioOutputPWM.cpp b/src/AudioOutputPWM.cpp new file mode 100644 index 00000000..6d907540 --- /dev/null +++ b/src/AudioOutputPWM.cpp @@ -0,0 +1,114 @@ +/* + AudioOutputPWM + Base class for the RP2040 PWM audio + + Copyright (C) 2023 Earle F. Philhower, III + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#if defined(ARDUINO_ARCH_RP2040) +#include +#include "AudioOutputPWM.h" + +AudioOutputPWM::AudioOutputPWM(long sampleRate, pin_size_t data) { + pwmOn = false; + mono = false; + bps = 16; + channels = 2; + hertz = sampleRate; + doutPin = data; + SetGain(1.0); + pwm.setStereo(true); +} + +AudioOutputPWM::~AudioOutputPWM() { + stop(); +} + +bool AudioOutputPWM::SetRate(int hz) { + this->hertz = hz; + if (pwmOn) { + pwm.setFrequency(hz); + } + return true; +} + +bool AudioOutputPWM::SetBitsPerSample(int bits) { + if ( (bits != 16) && (bits != 8) ) return false; + this->bps = bits; + return true; +} + +bool AudioOutputPWM::SetChannels(int channels) { + if ( (channels < 1) || (channels > 2) ) return false; + this->channels = channels; + return true; +} + +bool AudioOutputPWM::SetOutputModeMono(bool mono) { + this->mono = mono; + return true; +} + +bool AudioOutputPWM::begin() { + if (!pwmOn) { + pwm.setPin(doutPin); + pwm.begin(hertz); + } + pwmOn = true; + SetRate(hertz); // Default + return true; +} + +bool AudioOutputPWM::ConsumeSample(int16_t sample[2]) { + + if (!pwmOn) + return false; + + int16_t ms[2]; + + ms[0] = sample[0]; + ms[1] = sample[1]; + MakeSampleStereo16( ms ); + + if (this->mono) { + // Average the two samples and overwrite + int32_t ttl = ms[LEFTCHANNEL] + ms[RIGHTCHANNEL]; + ms[LEFTCHANNEL] = ms[RIGHTCHANNEL] = (ttl>>1) & 0xffff; + } + + if (pwm.available()) { + pwm.write((int16_t) ms[0]); + pwm.write((int16_t) ms[1]); + return true; + } else { + return false; + } +} + +void AudioOutputPWM::flush() { + pwm.flush(); +} + +bool AudioOutputPWM::stop() { + if (!pwmOn) + return false; + + pwm.end(); + pwmOn = false; + return true; +} + +#endif diff --git a/src/AudioOutputPWM.h b/src/AudioOutputPWM.h new file mode 100644 index 00000000..000255b2 --- /dev/null +++ b/src/AudioOutputPWM.h @@ -0,0 +1,57 @@ +/* + AudioOutputPWM + Base class for the RP2040 PWM audio output + + Copyright (C) 2023 Earle F. Philhower, III + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#pragma once + +#include "AudioOutput.h" + +#if defined(ARDUINO_ARCH_RP2040) +#include +#include + +class AudioOutputPWM : public AudioOutput +{ + public: + AudioOutputPWM(long sampleRate = 44100, pin_size_t data = 0); + virtual ~AudioOutputPWM() override; + virtual bool SetRate(int hz) override; + virtual bool SetBitsPerSample(int bits) override; + virtual bool SetChannels(int channels) override; + virtual bool begin() override; + virtual bool ConsumeSample(int16_t sample[2]) override; + virtual void flush() override; + virtual bool stop() override; + + bool SetOutputModeMono(bool mono); // Force mono output no matter the input + + protected: + bool SetPinout(); + virtual int AdjustI2SRate(int hz) { return hz; } + uint8_t portNo; + int output_mode; + bool mono; + bool pwmOn; + + uint8_t doutPin; + + PWMAudio pwm; +}; + +#endif diff --git a/src/ESP8266Audio.h b/src/ESP8266Audio.h index eb0acc52..9fdeb912 100644 --- a/src/ESP8266Audio.h +++ b/src/ESP8266Audio.h @@ -41,6 +41,7 @@ #include "AudioOutput.h" #include "AudioOutputI2S.h" #include "AudioOutputI2SNoDAC.h" +#include "AudioOutputPWM.h" #include "AudioOutputMixer.h" #include "AudioOutputNull.h" #include "AudioOutputSerialWAV.h" diff --git a/tests/common.sh b/tests/common.sh index dfd9c4b0..29ea675b 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -109,7 +109,11 @@ if [ "$BUILD_TYPE" = "build" ]; then install_arduino install_esp8266 "$HOME/arduino_ide" source "$HOME/arduino_ide/hardware/esp8266com/esp8266/tests/common.sh" - build_sketches "$HOME/arduino_ide" "$TRAVIS_BUILD_DIR" "-l $HOME/Arduino/libraries" "$BUILD_MOD" "$BUILD_REM" "lm2f" + export ESP8266_ARDUINO_SKETCHES=$(find $HOME/Arduino/libraries/ESP8266Audio -name *.ino | sort) + # ESP8266 scripts now expect tools in wrong spot. Use simple and dumb fix + mkdir -p "$HOME/work/ESP8266Audio/ESP8266Audio" + ln -s "$HOME/arduino_ide/hardware/esp8266com/esp8266/tools" "$HOME/work/ESP8266Audio/ESP8266Audio/tools" + build_sketches "$TRAVIS_BUILD_DIR" "$HOME/arduino_ide" "$HOME/arduino_ide/hardware" "$HOME/Arduino/libraries" "$BUILD_MOD" "$BUILD_REM" "lm2f" elif [ "$BUILD_TYPE" = "build_esp32" ]; then install_arduino install_esp32 "$HOME/arduino_ide" From 4ba7df1928dafc7cac72290931b213bcabe7d2d9 Mon Sep 17 00:00:00 2001 From: Sylwester <6614616+DatanoiseTV@users.noreply.github.com> Date: Wed, 4 Jan 2023 18:46:05 +0100 Subject: [PATCH 116/150] Add support for I2S MCLK. (#594) --- src/AudioOutputI2S.cpp | 38 +++++++++++++++++++++++++++++++++++--- src/AudioOutputI2S.h | 4 ++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 919679d2..c2b8aec5 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -49,6 +49,7 @@ AudioOutputI2S::AudioOutputI2S(int port, int output_mode, int dma_buf_count, int bclkPin = 26; wclkPin = 25; doutPin = 22; + mclkPin = 0; SetGain(1.0); } @@ -61,6 +62,8 @@ AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) hertz = sampleRate; bclkPin = sck; doutPin = data; + mclkPin = 0; + use_mclk = false; SetGain(1.0); } #endif @@ -78,7 +81,7 @@ bool AudioOutputI2S::SetPinout() i2s_pin_config_t pins = { #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) - .mck_io_num = 0, // Unused + .mck_io_num = mclkPin, #endif .bck_io_num = bclkPin, .ws_io_num = wclkPin, @@ -90,6 +93,8 @@ bool AudioOutputI2S::SetPinout() (void)bclkPin; (void)wclkPin; (void)doutPin; + (void)mclkPin; + (void)use_mclk; return false; #endif } @@ -104,6 +109,22 @@ bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout) return true; } + +bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout, int mclk) +{ + bclkPin = bclk; + wclkPin = wclk; + doutPin = dout; + #ifdef ESP32 + mclkPin = mclk; + if (i2sOn) + return SetPinout(); + #else + (void)mclk; + #endif + return true; +} + bool AudioOutputI2S::SetRate(int hz) { // TODO - have a list of allowable rates from constructor, check them @@ -147,6 +168,17 @@ bool AudioOutputI2S::SetLsbJustified(bool lsbJustified) return true; } +bool AudioOutputI2S::SetMclk(bool enabled){ + (void)enabled; + #ifdef ESP32 + if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) + return false; // Not allowed + + use_mclk = enabled; + #endif + return true; +} + bool AudioOutputI2S::begin(bool txDAC) { #ifdef ESP32 @@ -219,9 +251,9 @@ bool AudioOutputI2S::begin(bool txDAC) .dma_buf_len = 128, .use_apll = use_apll, // Use audio PLL .tx_desc_auto_clear = true, // Silence on underflow - .fixed_mclk = 0, // Unused + .fixed_mclk = use_mclk, // Unused #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) - .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, // Unused + .mclk_multiple = I2S_MCLK_MULTIPLE_256, // Unused .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample #endif }; diff --git a/src/AudioOutputI2S.h b/src/AudioOutputI2S.h index 33e784bd..da61b74c 100644 --- a/src/AudioOutputI2S.h +++ b/src/AudioOutputI2S.h @@ -38,6 +38,7 @@ class AudioOutputI2S : public AudioOutput AudioOutputI2S(long sampleRate = 44100, pin_size_t sck = 26, pin_size_t data = 28); #endif bool SetPinout(int bclkPin, int wclkPin, int doutPin); + bool SetPinout(int bclkPin, int wclkPin, int doutPin, int mclkPin); virtual ~AudioOutputI2S() override; virtual bool SetRate(int hz) override; virtual bool SetBitsPerSample(int bits) override; @@ -50,6 +51,7 @@ class AudioOutputI2S : public AudioOutput bool begin(bool txDAC); bool SetOutputModeMono(bool mono); // Force mono output no matter the input bool SetLsbJustified(bool lsbJustified); // Allow supporting non-I2S chips, e.g. PT8211 + bool SetMclk(bool enabled); // Enable MCLK output (if supported) protected: bool SetPinout(); @@ -61,6 +63,7 @@ class AudioOutputI2S : public AudioOutput bool i2sOn; int dma_buf_count; int use_apll; + bool use_mclk; // We can restore the old values and free up these pins when in NoDAC mode uint32_t orig_bck; uint32_t orig_ws; @@ -68,6 +71,7 @@ class AudioOutputI2S : public AudioOutput uint8_t bclkPin; uint8_t wclkPin; uint8_t doutPin; + uint8_t mclkPin; #if defined(ARDUINO_ARCH_RP2040) I2S i2s; From 12131e9826283ec19cc728476c1dc1479bb7c09d Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 28 Jan 2023 14:32:54 -0800 Subject: [PATCH 117/150] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fb3085d4..a20f53f4 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi RP2040 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +# ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi Pico RP2040 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTTL files and playing them on an I2S DAC or even using a software-simulated delta-sigma DAC with dynamic 32x-128x oversampling. ESP8266 is fully supported and most mature, but ESP32 is also mostly there with built-in DAC as well as external ones. From 0abcf71012f6128d52a6bcd155ed1404d6cc6dcd Mon Sep 17 00:00:00 2001 From: Nils Trubkin <32000568+nils-trubkin@users.noreply.github.com> Date: Fri, 30 Jun 2023 20:02:49 +0200 Subject: [PATCH 118/150] Add ability to SwapClocks(bool) on I2S. rp2040 only. (#639) Fixes #638 --- src/AudioOutputI2S.cpp | 13 +++++++++++++ src/AudioOutputI2S.h | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index c2b8aec5..8fd17775 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -64,6 +64,7 @@ AudioOutputI2S::AudioOutputI2S(long sampleRate, pin_size_t sck, pin_size_t data) doutPin = data; mclkPin = 0; use_mclk = false; + swap_clocks = false; SetGain(1.0); } #endif @@ -168,6 +169,15 @@ bool AudioOutputI2S::SetLsbJustified(bool lsbJustified) return true; } +bool AudioOutputI2S::SwapClocks(bool swap_clocks) +{ + if (i2sOn) { + return false; // Not allowed + } + this->swap_clocks = swap_clocks; + return true; +} + bool AudioOutputI2S::SetMclk(bool enabled){ (void)enabled; #ifdef ESP32 @@ -302,6 +312,9 @@ bool AudioOutputI2S::begin(bool txDAC) if (!i2sOn) { i2s.setBCLK(bclkPin); i2s.setDATA(doutPin); + if (swap_clocks) { + i2s.swapClocks(); + } i2s.begin(hertz); } #endif diff --git a/src/AudioOutputI2S.h b/src/AudioOutputI2S.h index da61b74c..015a91b0 100644 --- a/src/AudioOutputI2S.h +++ b/src/AudioOutputI2S.h @@ -52,6 +52,7 @@ class AudioOutputI2S : public AudioOutput bool SetOutputModeMono(bool mono); // Force mono output no matter the input bool SetLsbJustified(bool lsbJustified); // Allow supporting non-I2S chips, e.g. PT8211 bool SetMclk(bool enabled); // Enable MCLK output (if supported) + bool SwapClocks(bool swap_clocks); // Swap BCLK and WCLK protected: bool SetPinout(); @@ -64,6 +65,7 @@ class AudioOutputI2S : public AudioOutput int dma_buf_count; int use_apll; bool use_mclk; + bool swap_clocks; // We can restore the old values and free up these pins when in NoDAC mode uint32_t orig_bck; uint32_t orig_ws; From 60b93433d88d08509ae80e7991e8c9791df1a9bc Mon Sep 17 00:00:00 2001 From: KDM Date: Tue, 16 Apr 2024 22:55:52 +0100 Subject: [PATCH 119/150] Update README.md (#675) Corrected format to formant. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a20f53f4..c94c7946 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTT ESP8266 is fully supported and most mature, but ESP32 is also mostly there with built-in DAC as well as external ones. -For real-time, autonomous speech synthesis, check out [ESP8266SAM](https://github.com/earlephilhower/ESP8266SAM), a library which uses this one and a port of an ancient format-based synthesis program to allow your ESP8266 to talk with low memory and no network required. +For real-time, autonomous speech synthesis, check out [ESP8266SAM](https://github.com/earlephilhower/ESP8266SAM), a library which uses this one and a port of an ancient formant-based synthesis program to allow your ESP8266 to talk with low memory and no network required. ## Disclaimer All this code is released under the GPL, and all of it is to be used at your own risk. If you find any bugs, please let me know via the GitHub issue tracker or drop me an email. From f6c0d562f8ff3cf81988660e8544751b6d2e0164 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 16 Apr 2024 15:10:24 -0700 Subject: [PATCH 120/150] Update AudioOutputSPDIF.cpp (#677) --- src/AudioOutputSPDIF.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index 1823b5d8..6837d472 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -7,7 +7,7 @@ See: https://www.epanorama.net/documents/audio/spdif.html Original idea and sources: - Forum thread dicussing implementation + Forum thread discussing implementation https://forum.pjrc.com/threads/28639-S-pdif Teensy Audio Library https://github.com/PaulStoffregen/Audio/blob/master/output_spdif2.cpp From e306df208cda7d5ce01ff7956f71796746f0e701 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 16 Apr 2024 15:10:49 -0700 Subject: [PATCH 121/150] Update AudioOutputSPDIF.h --- src/AudioOutputSPDIF.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AudioOutputSPDIF.h b/src/AudioOutputSPDIF.h index 7cb194db..ed77e086 100644 --- a/src/AudioOutputSPDIF.h +++ b/src/AudioOutputSPDIF.h @@ -7,7 +7,7 @@ See: https://www.epanorama.net/documents/audio/spdif.html Original idea and sources: - Forum thread dicussing implementation + Forum thread discussing implementation https://forum.pjrc.com/threads/28639-S-pdif Teensy Audio Library https://github.com/PaulStoffregen/Audio/blob/master/output_spdif2.cpp From b7d89058ddf9f4754f6f1de686f3f7bfdfb550e5 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 16 Apr 2024 15:11:31 -0700 Subject: [PATCH 122/150] Update polyphase.c --- src/libhelix-mp3/polyphase.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libhelix-mp3/polyphase.c b/src/libhelix-mp3/polyphase.c index bd331dfe..2f3ea061 100644 --- a/src/libhelix-mp3/polyphase.c +++ b/src/libhelix-mp3/polyphase.c @@ -54,7 +54,7 @@ * (see comment on Dequantize() for more info) */ #define DEF_NFRACBITS (DQ_FRACBITS_OUT - 2 - 2 - 15) -#define CSHIFT 12 /* coefficients have 12 leading sign bits for early-terminating mulitplies */ +#define CSHIFT 12 /* coefficients have 12 leading sign bits for early-terminating multiplies */ static __inline short ClipToShort(int x, int fracBits) { From 139fba4116ddf3eca601304a9f183a9dbcb50196 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 16 Apr 2024 15:14:14 -0700 Subject: [PATCH 123/150] Update opusfile.c (#678) --- src/opusfile/opusfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/opusfile/opusfile.c b/src/opusfile/opusfile.c index 95aab481..1f63cc60 100644 --- a/src/opusfile/opusfile.c +++ b/src/opusfile/opusfile.c @@ -1481,7 +1481,7 @@ static int op_open_seekable2(OggOpusFile *_of){ /*Clear out the current logical bitstream decoder.*/ static void op_decode_clear(OggOpusFile *_of){ /*We don't actually free the decoder. - We might be able to re-use it for the next link.*/ + We might be able to reuse it for the next link.*/ _of->op_count=0; _of->od_buffer_size=0; _of->prev_packet_gp=-1; From b3c41668a263d8e46a08e23b85326a552683b0eb Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 16 Apr 2024 16:32:16 -0700 Subject: [PATCH 124/150] Fix GCC12.3 new warnings for RP2040 (#679) * Fix GCC12.3 new warnings for RP2040 * Remove OPUS encoder, not supported on embedded --- src/AudioGeneratorFLAC.cpp | 2 +- src/libmad/layer3.c | 141 +++++++++++----------- src/libopus/opus_encoder.c | 3 +- src/libopus/opus_multistream_encoder.c | 3 +- src/libopus/opus_projection_encoder.c | 4 +- src/libopus/silk/NLSF2A.c | 4 +- src/libopus/silk/enc_API.c | 2 + src/libopus/silk/fixed/encode_frame_FIX.c | 2 + src/opusfile/opusfile.c | 2 +- 9 files changed, 84 insertions(+), 79 deletions(-) diff --git a/src/AudioGeneratorFLAC.cpp b/src/AudioGeneratorFLAC.cpp index f315133c..5118bf55 100644 --- a/src/AudioGeneratorFLAC.cpp +++ b/src/AudioGeneratorFLAC.cpp @@ -196,7 +196,7 @@ char AudioGeneratorFLAC::error_cb_str[64]; void AudioGeneratorFLAC::error_cb(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status) { (void) decoder; - strncpy_P(error_cb_str, FLAC__StreamDecoderErrorStatusString[status], 64); + strncpy_P(error_cb_str, FLAC__StreamDecoderErrorStatusString[status], sizeof(AudioGeneratorFLAC::error_cb_str) - 1); cb.st((int)status, error_cb_str); } diff --git a/src/libmad/layer3.c b/src/libmad/layer3.c index bc964334..95d5f4f4 100644 --- a/src/libmad/layer3.c +++ b/src/libmad/layer3.c @@ -352,19 +352,18 @@ struct fixedfloat { root_table[3 + x] = 2^(x/4) */ +static mad_fixed_t const root_table_val[7] PROGMEM = { + MAD_F(0x09837f05) /* 2^(-3/4) == 0.59460355750136 */, + MAD_F(0x0b504f33) /* 2^(-2/4) == 0.70710678118655 */, + MAD_F(0x0d744fcd) /* 2^(-1/4) == 0.84089641525371 */, + MAD_F(0x10000000) /* 2^( 0/4) == 1.00000000000000 */, + MAD_F(0x1306fe0a) /* 2^(+1/4) == 1.18920711500272 */, + MAD_F(0x16a09e66) /* 2^(+2/4) == 1.41421356237310 */, + MAD_F(0x1ae89f99) /* 2^(+3/4) == 1.68179283050743 */ +}; static inline mad_fixed_t root_table(int i) { - static mad_fixed_t const root_table_val[7] PROGMEM = { - MAD_F(0x09837f05) /* 2^(-3/4) == 0.59460355750136 */, - MAD_F(0x0b504f33) /* 2^(-2/4) == 0.70710678118655 */, - MAD_F(0x0d744fcd) /* 2^(-1/4) == 0.84089641525371 */, - MAD_F(0x10000000) /* 2^( 0/4) == 1.00000000000000 */, - MAD_F(0x1306fe0a) /* 2^(+1/4) == 1.18920711500272 */, - MAD_F(0x16a09e66) /* 2^(+2/4) == 1.41421356237310 */, - MAD_F(0x1ae89f99) /* 2^(+3/4) == 1.68179283050743 */ - }; - volatile uint32_t a = *(uint32_t*)&root_table_val[i]; - return *(mad_fixed_t*)&a; + return root_table_val[i]; } /* coefficients for aliasing reduction @@ -374,28 +373,26 @@ static inline mad_fixed_t root_table(int i) cs[i] = 1 / sqrt(1 + c[i]^2) ca[i] = c[i] / sqrt(1 + c[i]^2) */ +static mad_fixed_t const cs_val[8] PROGMEM = { + +MAD_F(0x0db84a81) /* +0.857492926 */, +MAD_F(0x0e1b9d7f) /* +0.881741997 */, + +MAD_F(0x0f31adcf) /* +0.949628649 */, +MAD_F(0x0fbba815) /* +0.983314592 */, + +MAD_F(0x0feda417) /* +0.995517816 */, +MAD_F(0x0ffc8fc8) /* +0.999160558 */, + +MAD_F(0x0fff964c) /* +0.999899195 */, +MAD_F(0x0ffff8d3) /* +0.999993155 */ +}; static inline mad_fixed_t cs(int i) { - static mad_fixed_t const cs_val[8] PROGMEM = { - +MAD_F(0x0db84a81) /* +0.857492926 */, +MAD_F(0x0e1b9d7f) /* +0.881741997 */, - +MAD_F(0x0f31adcf) /* +0.949628649 */, +MAD_F(0x0fbba815) /* +0.983314592 */, - +MAD_F(0x0feda417) /* +0.995517816 */, +MAD_F(0x0ffc8fc8) /* +0.999160558 */, - +MAD_F(0x0fff964c) /* +0.999899195 */, +MAD_F(0x0ffff8d3) /* +0.999993155 */ - }; - volatile uint32_t a = *(uint32_t*)&cs_val[i]; - return *(mad_fixed_t*)&a; + return cs_val[i]; } +static mad_fixed_t const ca_val[8] PROGMEM = { + -MAD_F(0x083b5fe7) /* -0.514495755 */, -MAD_F(0x078c36d2) /* -0.471731969 */, + -MAD_F(0x05039814) /* -0.313377454 */, -MAD_F(0x02e91dd1) /* -0.181913200 */, + -MAD_F(0x0183603a) /* -0.094574193 */, -MAD_F(0x00a7cb87) /* -0.040965583 */, + -MAD_F(0x003a2847) /* -0.014198569 */, -MAD_F(0x000f27b4) /* -0.003699975 */ +}; static inline mad_fixed_t ca(int i) { - static mad_fixed_t const ca_val[8] PROGMEM = { - -MAD_F(0x083b5fe7) /* -0.514495755 */, -MAD_F(0x078c36d2) /* -0.471731969 */, - -MAD_F(0x05039814) /* -0.313377454 */, -MAD_F(0x02e91dd1) /* -0.181913200 */, - -MAD_F(0x0183603a) /* -0.094574193 */, -MAD_F(0x00a7cb87) /* -0.040965583 */, - -MAD_F(0x003a2847) /* -0.014198569 */, -MAD_F(0x000f27b4) /* -0.003699975 */ - }; - volatile uint32_t a = *(uint32_t*)&ca_val[i]; - return *(mad_fixed_t*)&a; + return ca_val[i]; } /* @@ -417,32 +414,31 @@ mad_fixed_t const imdct_s[6][6] PROGMEM = { window_l[i] = sin((PI / 36) * (i + 1/2)) */ +static mad_fixed_t const window_l_val[36] PROGMEM = { + MAD_F(0x00b2aa3e) /* 0.043619387 */, MAD_F(0x0216a2a2) /* 0.130526192 */, + MAD_F(0x03768962) /* 0.216439614 */, MAD_F(0x04cfb0e2) /* 0.300705800 */, + MAD_F(0x061f78aa) /* 0.382683432 */, MAD_F(0x07635284) /* 0.461748613 */, + MAD_F(0x0898c779) /* 0.537299608 */, MAD_F(0x09bd7ca0) /* 0.608761429 */, + MAD_F(0x0acf37ad) /* 0.675590208 */, MAD_F(0x0bcbe352) /* 0.737277337 */, + MAD_F(0x0cb19346) /* 0.793353340 */, MAD_F(0x0d7e8807) /* 0.843391446 */, + + MAD_F(0x0e313245) /* 0.887010833 */, MAD_F(0x0ec835e8) /* 0.923879533 */, + MAD_F(0x0f426cb5) /* 0.953716951 */, MAD_F(0x0f9ee890) /* 0.976296007 */, + MAD_F(0x0fdcf549) /* 0.991444861 */, MAD_F(0x0ffc19fd) /* 0.999048222 */, + MAD_F(0x0ffc19fd) /* 0.999048222 */, MAD_F(0x0fdcf549) /* 0.991444861 */, + MAD_F(0x0f9ee890) /* 0.976296007 */, MAD_F(0x0f426cb5) /* 0.953716951 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, MAD_F(0x0e313245) /* 0.887010833 */, + + MAD_F(0x0d7e8807) /* 0.843391446 */, MAD_F(0x0cb19346) /* 0.793353340 */, + MAD_F(0x0bcbe352) /* 0.737277337 */, MAD_F(0x0acf37ad) /* 0.675590208 */, + MAD_F(0x09bd7ca0) /* 0.608761429 */, MAD_F(0x0898c779) /* 0.537299608 */, + MAD_F(0x07635284) /* 0.461748613 */, MAD_F(0x061f78aa) /* 0.382683432 */, + MAD_F(0x04cfb0e2) /* 0.300705800 */, MAD_F(0x03768962) /* 0.216439614 */, + MAD_F(0x0216a2a2) /* 0.130526192 */, MAD_F(0x00b2aa3e) /* 0.043619387 */, +}; static inline mad_fixed_t window_l(int i) { - static mad_fixed_t const window_l_val[36] PROGMEM = { - MAD_F(0x00b2aa3e) /* 0.043619387 */, MAD_F(0x0216a2a2) /* 0.130526192 */, - MAD_F(0x03768962) /* 0.216439614 */, MAD_F(0x04cfb0e2) /* 0.300705800 */, - MAD_F(0x061f78aa) /* 0.382683432 */, MAD_F(0x07635284) /* 0.461748613 */, - MAD_F(0x0898c779) /* 0.537299608 */, MAD_F(0x09bd7ca0) /* 0.608761429 */, - MAD_F(0x0acf37ad) /* 0.675590208 */, MAD_F(0x0bcbe352) /* 0.737277337 */, - MAD_F(0x0cb19346) /* 0.793353340 */, MAD_F(0x0d7e8807) /* 0.843391446 */, - - MAD_F(0x0e313245) /* 0.887010833 */, MAD_F(0x0ec835e8) /* 0.923879533 */, - MAD_F(0x0f426cb5) /* 0.953716951 */, MAD_F(0x0f9ee890) /* 0.976296007 */, - MAD_F(0x0fdcf549) /* 0.991444861 */, MAD_F(0x0ffc19fd) /* 0.999048222 */, - MAD_F(0x0ffc19fd) /* 0.999048222 */, MAD_F(0x0fdcf549) /* 0.991444861 */, - MAD_F(0x0f9ee890) /* 0.976296007 */, MAD_F(0x0f426cb5) /* 0.953716951 */, - MAD_F(0x0ec835e8) /* 0.923879533 */, MAD_F(0x0e313245) /* 0.887010833 */, - - MAD_F(0x0d7e8807) /* 0.843391446 */, MAD_F(0x0cb19346) /* 0.793353340 */, - MAD_F(0x0bcbe352) /* 0.737277337 */, MAD_F(0x0acf37ad) /* 0.675590208 */, - MAD_F(0x09bd7ca0) /* 0.608761429 */, MAD_F(0x0898c779) /* 0.537299608 */, - MAD_F(0x07635284) /* 0.461748613 */, MAD_F(0x061f78aa) /* 0.382683432 */, - MAD_F(0x04cfb0e2) /* 0.300705800 */, MAD_F(0x03768962) /* 0.216439614 */, - MAD_F(0x0216a2a2) /* 0.130526192 */, MAD_F(0x00b2aa3e) /* 0.043619387 */, - }; - volatile uint32_t a = *(uint32_t*)&window_l_val[i]; - return *(mad_fixed_t*)&a; + return window_l_val[i]; } # endif /* ASO_IMDCT */ @@ -452,18 +448,17 @@ static inline mad_fixed_t window_l(int i) window_s[i] = sin((PI / 12) * (i + 1/2)) */ +static mad_fixed_t const window_s_val[12] PROGMEM = { + MAD_F(0x0216a2a2) /* 0.130526192 */, MAD_F(0x061f78aa) /* 0.382683432 */, + MAD_F(0x09bd7ca0) /* 0.608761429 */, MAD_F(0x0cb19346) /* 0.793353340 */, + MAD_F(0x0ec835e8) /* 0.923879533 */, MAD_F(0x0fdcf549) /* 0.991444861 */, + MAD_F(0x0fdcf549) /* 0.991444861 */, MAD_F(0x0ec835e8) /* 0.923879533 */, + MAD_F(0x0cb19346) /* 0.793353340 */, MAD_F(0x09bd7ca0) /* 0.608761429 */, + MAD_F(0x061f78aa) /* 0.382683432 */, MAD_F(0x0216a2a2) /* 0.130526192 */, +}; static inline mad_fixed_t window_s(int i) { - static mad_fixed_t const window_s_val[12] PROGMEM = { - MAD_F(0x0216a2a2) /* 0.130526192 */, MAD_F(0x061f78aa) /* 0.382683432 */, - MAD_F(0x09bd7ca0) /* 0.608761429 */, MAD_F(0x0cb19346) /* 0.793353340 */, - MAD_F(0x0ec835e8) /* 0.923879533 */, MAD_F(0x0fdcf549) /* 0.991444861 */, - MAD_F(0x0fdcf549) /* 0.991444861 */, MAD_F(0x0ec835e8) /* 0.923879533 */, - MAD_F(0x0cb19346) /* 0.793353340 */, MAD_F(0x09bd7ca0) /* 0.608761429 */, - MAD_F(0x061f78aa) /* 0.382683432 */, MAD_F(0x0216a2a2) /* 0.130526192 */, - }; - volatile uint32_t a = *(uint32_t*)&window_s_val[i]; - return *(mad_fixed_t*)&a; + return window_s_val[i]; } /* @@ -473,19 +468,18 @@ static inline mad_fixed_t window_s(int i) is_ratio[i] = tan(i * (PI / 12)) is_table[i] = is_ratio[i] / (1 + is_ratio[i]) */ +static mad_fixed_t const is_table_val[7] PROGMEM = { + MAD_F(0x00000000) /* 0.000000000 */, + MAD_F(0x0361962f) /* 0.211324865 */, + MAD_F(0x05db3d74) /* 0.366025404 */, + MAD_F(0x08000000) /* 0.500000000 */, + MAD_F(0x0a24c28c) /* 0.633974596 */, + MAD_F(0x0c9e69d1) /* 0.788675135 */, + MAD_F(0x10000000) /* 1.000000000 */ +}; static inline mad_fixed_t is_table(int i) { - static mad_fixed_t const is_table_val[7] PROGMEM = { - MAD_F(0x00000000) /* 0.000000000 */, - MAD_F(0x0361962f) /* 0.211324865 */, - MAD_F(0x05db3d74) /* 0.366025404 */, - MAD_F(0x08000000) /* 0.500000000 */, - MAD_F(0x0a24c28c) /* 0.633974596 */, - MAD_F(0x0c9e69d1) /* 0.788675135 */, - MAD_F(0x10000000) /* 1.000000000 */ - }; - volatile uint32_t a = *(uint32_t*)&is_table_val[i]; - return *(mad_fixed_t*)&a; + return is_table_val[i]; } /* @@ -1739,7 +1733,10 @@ void sdctII(mad_fixed_t const x[18], mad_fixed_t X[18]) s = *(volatile mad_fixed_t*)(volatile uint32_t*)&scale[i + 2]; tmp[i + 2] = mad_f_mul(x[i + 2] - x[18 - (i + 2) - 1], s); //scale[i + 2]); } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-overflow" fastsdct(tmp, &X[1]); +#pragma GCC diagnostic pop /* output accumulation */ diff --git a/src/libopus/opus_encoder.c b/src/libopus/opus_encoder.c index fda4fd15..adf05eb1 100644 --- a/src/libopus/opus_encoder.c +++ b/src/libopus/opus_encoder.c @@ -24,7 +24,7 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - +#if 0 //#ifdef HAVE_CONFIG_H #include "config.h" //#endif @@ -2781,3 +2781,4 @@ void opus_encoder_destroy(OpusEncoder *st) { opus_free(st); } +#endif diff --git a/src/libopus/opus_multistream_encoder.c b/src/libopus/opus_multistream_encoder.c index 5b6576a9..69b605aa 100644 --- a/src/libopus/opus_multistream_encoder.c +++ b/src/libopus/opus_multistream_encoder.c @@ -24,7 +24,7 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - +#if 0 //#ifdef HAVE_CONFIG_H #include "config.h" //#endif @@ -1326,3 +1326,4 @@ void opus_multistream_encoder_destroy(OpusMSEncoder *st) { opus_free(st); } +#endif diff --git a/src/libopus/opus_projection_encoder.c b/src/libopus/opus_projection_encoder.c index a3a9762a..cf5e40cf 100644 --- a/src/libopus/opus_projection_encoder.c +++ b/src/libopus/opus_projection_encoder.c @@ -24,7 +24,7 @@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - +#if 0 //#ifdef HAVE_CONFIG_H #include "config.h" //#endif @@ -465,4 +465,4 @@ int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) va_end(ap); return OPUS_BAD_ARG; } - +#endif diff --git a/src/libopus/silk/NLSF2A.c b/src/libopus/silk/NLSF2A.c index 2b3e3340..315511c9 100644 --- a/src/libopus/silk/NLSF2A.c +++ b/src/libopus/silk/NLSF2A.c @@ -62,6 +62,8 @@ static OPUS_INLINE void silk_NLSF2A_find_poly( } } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" /* compute whitening filter coefficients from normalized line spectral frequencies */ void silk_NLSF2A( opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */ @@ -143,4 +145,4 @@ void silk_NLSF2A( free(Q); free(a32_QA1); } - +#pragma GCC diagnostic pop diff --git a/src/libopus/silk/enc_API.c b/src/libopus/silk/enc_API.c index 97f37935..3e93d217 100644 --- a/src/libopus/silk/enc_API.c +++ b/src/libopus/silk/enc_API.c @@ -24,6 +24,7 @@ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************/ +#if 0 //#ifdef HAVE_CONFIG_H #include "../config.h" @@ -574,3 +575,4 @@ opus_int silk_Encode( /* O Returns error co return ret; } +#endif diff --git a/src/libopus/silk/fixed/encode_frame_FIX.c b/src/libopus/silk/fixed/encode_frame_FIX.c index a121d0a1..640b9357 100644 --- a/src/libopus/silk/fixed/encode_frame_FIX.c +++ b/src/libopus/silk/fixed/encode_frame_FIX.c @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "../../celt/stack_alloc.h" #include "../tuning_parameters.h" +#if 0 /* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */ static OPUS_INLINE void silk_LBRR_encode_FIX( silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */ @@ -446,3 +447,4 @@ static OPUS_INLINE void silk_LBRR_encode_FIX( silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) ); } } +#endif diff --git a/src/opusfile/opusfile.c b/src/opusfile/opusfile.c index 1f63cc60..007f4763 100644 --- a/src/opusfile/opusfile.c +++ b/src/opusfile/opusfile.c @@ -1749,7 +1749,7 @@ opus_int64 op_raw_total(const OggOpusFile *_of,int _li){ ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){ OggOpusLink *links; ogg_int64_t pcm_total; - ogg_int64_t diff; + ogg_int64_t diff = 0; int nlinks; nlinks=_of->nlinks; if(OP_UNLIKELY(_of->ready_state Date: Wed, 17 Apr 2024 10:11:03 -0700 Subject: [PATCH 125/150] Get ESP32 CI builds working again (#680) --- tests/common.sh | 52 ++++++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/tests/common.sh b/tests/common.sh index 29ea675b..97c09de9 100755 --- a/tests/common.sh +++ b/tests/common.sh @@ -70,23 +70,13 @@ function install_esp32() local ide_path=$1 pip install pyserial pip3 install pyserial - cd $ide_path/hardware - mkdir espressif - cd espressif - git clone https://github.com/espressif/arduino-esp32.git esp32 - pushd esp32 - # Set custom warnings for all builds - - echo "compiler.c.extra_flags=-Wall -Wextra -Werror $debug_flags" > platform.local.txt - echo "compiler.cpp.extra_flags=-Wall -Wextra -Werror $debug_flags" >> platform.local.txt - echo -e "\n----platform.local.txt----" - cat platform.local.txt - git submodule update --init - cd tools - python3 get.py - export PATH="$ide_path/hardware/espressif/esp32/tools/xtensa-esp32-elf/bin/:$PATH" + mkdir -p ~/bin + pushd ~/bin + wget -q https://downloads.arduino.cc/arduino-cli/arduino-cli_latest_Linux_64bit.tar.gz + tar xvf arduino-cli_latest_Linux_64bit.tar.gz + export PATH=$PATH:$PWD popd - cd esp32 + arduino-cli core install --additional-urls https://espressif.github.io/arduino-esp32/package_esp32_index.json esp32:esp32 } function install_arduino() @@ -99,6 +89,20 @@ function install_arduino() install_libraries } +function skip_esp32() +{ + local ino=$1 + local skiplist="" + # Add items to the following list with "\n" netween them to skip running. No spaces, tabs, etc. allowed + read -d '' skiplist << EOL || true +/MixerSample/ +EOL + echo $ino | grep -q -F "$skiplist" + echo $(( 1 - $? )) +} + + + if [ "$BUILD_MOD" == "" ]; then export BUILD_MOD=1 export BUILD_REM=0 @@ -117,10 +121,18 @@ if [ "$BUILD_TYPE" = "build" ]; then elif [ "$BUILD_TYPE" = "build_esp32" ]; then install_arduino install_esp32 "$HOME/arduino_ide" - export FQBN="espressif:esp32:esp32:PSRAM=enabled,PartitionScheme=huge_app" - mkdir -p "$GITHUB_WORKSPACE/hardware" - ln -s "$GITHUB_WORKSPACE/../" "$GITHUB_WORKSPACE/libraries" - source "$HOME/arduino_ide/hardware/espressif/esp32/.github/scripts/sketch_utils.sh" chunk_build -ai "$HOME/arduino_ide" -au "$GITHUB_WORKSPACE" -fqbn "$FQBN" -t esp32 -p "$GITHUB_WORKSPACE" -i $BUILD_REM -m $BUILD_MOD + export testcnt=0 + for i in $(find ~/Arduino/libraries/ESP8266Audio -name "*.ino"); do + testcnt=$(( ($testcnt + 1) % $BUILD_MOD )) + if [ $testcnt -ne $BUILD_REM ]; then + continue # Not ours to do + fi + if [[ $(skip_esp32 $i) = 1 ]]; then + echo -e "\n ------------ Skipping $i ------------ \n"; + continue + fi + arduino-cli compile --fqbn esp32:esp32:esp32 --warnings all $i + done elif [ "$BUILD_TYPE" = "build_rp2040" ]; then install_arduino install_rp2040 "$HOME/arduino_ide" From 492a5beba4e2aaf5f480ae57c8f0a0ba72271319 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 17 Apr 2024 10:22:17 -0700 Subject: [PATCH 126/150] Update GH CI actions to latest (#681) --- .github/workflows/pr-or-master-push.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index db7453b8..1502fb36 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -20,10 +20,10 @@ jobs: matrix: chunk: [0, 1, 2, 3, 4] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 with: python-version: '3.x' - name: Build Sketches @@ -43,10 +43,10 @@ jobs: matrix: chunk: [0, 1, 2, 3, 4] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 with: python-version: '3.x' - name: Build Sketches @@ -66,10 +66,10 @@ jobs: matrix: chunk: [0, 1, 2, 3, 4] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 with: python-version: '3.x' - name: Build Sketches @@ -87,10 +87,10 @@ jobs: name: Host tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v5 with: python-version: '3.x' - name: Run host tests @@ -115,7 +115,7 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: arduino/arduino-lint-action@v1 with: library-manager: 'update' @@ -128,7 +128,7 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: submodules: true - name: Run codespell From 51a584c2b79d3d6b9bd0a52a196ec97de369ff87 Mon Sep 17 00:00:00 2001 From: Infinity <573679956@qq.com> Date: Fri, 26 Apr 2024 08:51:42 +0800 Subject: [PATCH 127/150] Update AudioGeneratorRTTTL.cpp for dotted length (#668) --- src/AudioGeneratorRTTTL.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/AudioGeneratorRTTTL.cpp b/src/AudioGeneratorRTTTL.cpp index 5eb18486..91d07e6d 100644 --- a/src/AudioGeneratorRTTTL.cpp +++ b/src/AudioGeneratorRTTTL.cpp @@ -236,13 +236,13 @@ bool AudioGeneratorRTTTL::GetNextNote() ptr++; note++; } + if (!ReadInt(&scale)) { + scale = defaultOctave; + } if ((ptr < len) && (buff[ptr] == '.')) { ptr++; dur += dur / 2; } - if (!ReadInt(&scale)) { - scale = defaultOctave; - } // Eat any trailing whitespace and comma SkipWhitespace(); if ((ptr < len) && (buff[ptr]==',')) { From b837e7d36a0859ad57339a7470c294d9d3cdabfd Mon Sep 17 00:00:00 2001 From: ChuckMash <86080247+ChuckMash@users.noreply.github.com> Date: Thu, 25 Apr 2024 17:53:07 -0700 Subject: [PATCH 128/150] Stop output on OOM in MP3 (#658) --- src/AudioGeneratorMP3.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/AudioGeneratorMP3.cpp b/src/AudioGeneratorMP3.cpp index 8045d902..36c93ba5 100644 --- a/src/AudioGeneratorMP3.cpp +++ b/src/AudioGeneratorMP3.cpp @@ -1,7 +1,7 @@ /* AudioGeneratorMP3 Wrap libmad MP3 library to play audio - + Copyright (C) 2017 Earle F. Philhower, III This program is free software: you can redistribute it and/or modify @@ -62,7 +62,7 @@ AudioGeneratorMP3::~AudioGeneratorMP3() free(synth); free(frame); free(stream); - } + } } @@ -182,7 +182,7 @@ bool AudioGeneratorMP3::GetOneSample(int16_t sample[2]) output->SetChannels(synth->pcm.channels); lastChannels = synth->pcm.channels; } - + // If we're here, we have one decoded frame and sent 0 or more samples out if (samplePtr < synth->pcm.length) { sample[AudioOutput::LEFTCHANNEL ] = synth->pcm.samples[0][samplePtr]; @@ -190,7 +190,7 @@ bool AudioGeneratorMP3::GetOneSample(int16_t sample[2]) samplePtr++; } else { samplePtr = 0; - + switch ( mad_synth_frame_onens(synth, frame, nsCount++) ) { case MAD_FLOW_STOP: case MAD_FLOW_BREAK: audioLogger->printf_P(PSTR("msf1ns failed\n")); @@ -302,6 +302,7 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output) synth = reinterpret_cast(preallocateSynthSpace); } else { + output->stop(); audioLogger->printf_P("OOM error in MP3: Want %d/%d/%d/%d bytes, have %d/%d/%d/%d bytes preallocated.\n", preAllocBuffSize(), preAllocStreamSize(), preAllocFrameSize(), preAllocSynthSize(), preallocateSize, preallocateStreamSize, preallocateFrameSize, preallocateSynthSize); @@ -319,6 +320,7 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output) p += preAllocSynthSize(); int neededBytes = p - reinterpret_cast(preallocateSpace); if (neededBytes > preallocateSize) { + output->stop(); audioLogger->printf_P("OOM error in MP3: Want %d bytes, have %d bytes preallocated.\n", neededBytes, preallocateSize); return false; } @@ -336,17 +338,20 @@ bool AudioGeneratorMP3::begin(AudioFileSource *source, AudioOutput *output) stream = NULL; frame = NULL; synth = NULL; + + output->stop(); + audioLogger->printf_P("OOM error in MP3\n"); return false; } } - + mad_stream_init(stream); mad_frame_init(frame); mad_synth_init(synth); synth->pcm.length = 0; mad_stream_options(stream, 0); // TODO - add options support madInitted = true; - + running = true; return true; } @@ -413,4 +418,3 @@ extern "C" { } #endif } - From a6141473fbcb6f56cc5e7691877d7a4d9647a163 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 6 Jun 2024 14:43:45 -0700 Subject: [PATCH 129/150] Update for ESP32 Arduino 3.x (#685) Implement the renamed network client and other API changes when built under the 3.x branch of the Arduino ESP32 core. Disable building TSF on the ESP32, the Xtensa G++ backend bug is still there. Minimal changes to get I2S to build under new IDF. Deprecated but not removed, so warnings are expected but should not be fatal in use. Fixes #683 --- examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino | 4 ++-- src/AudioFileSourceHTTPStream.cpp | 4 ++++ src/AudioFileSourceHTTPStream.h | 4 ++++ src/AudioFileSourceICYStream.cpp | 4 ++++ src/AudioGeneratorMIDI.cpp | 4 ++-- src/AudioGeneratorMIDI.h | 4 ++-- src/AudioOutputI2S.cpp | 6 +++--- src/AudioOutputSPDIF.cpp | 7 ++++++- src/libhelix-mp3/mpadecobjfixpt.h | 2 +- src/libtinysoundfont/tsf.h | 12 ++++++++++++ 10 files changed, 40 insertions(+), 11 deletions(-) diff --git a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino index aefb26b1..b0a5204b 100644 --- a/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino +++ b/examples/PlayMIDIFromSPIFFS/PlayMIDIFromSPIFFS.ino @@ -1,8 +1,8 @@ #include -// Do not build on GCC8, GCC8 has a compiler bug +// Do not build on Espressif GCC8+, compiler bug -#if defined(ARDUINO_ARCH_RP2040) || ((__GNUC__ == 8) && (__XTENSA__)) +#if defined(ARDUINO_ARCH_RP2040) || (defined(ESP32) && (__GNUC__ >= 8) && (__XTENSA__)) void setup() {} void loop() {} #else diff --git a/src/AudioFileSourceHTTPStream.cpp b/src/AudioFileSourceHTTPStream.cpp index c5d0b833..8df166dd 100644 --- a/src/AudioFileSourceHTTPStream.cpp +++ b/src/AudioFileSourceHTTPStream.cpp @@ -102,7 +102,11 @@ uint32_t AudioFileSourceHTTPStream::readInternal(void *data, uint32_t len, bool } if ((size > 0) && (pos >= size)) return 0; +#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3 + NetworkClient *stream = http.getStreamPtr(); +#else WiFiClient *stream = http.getStreamPtr(); +#endif // Can't read past EOF... if ( (size > 0) && (len > (uint32_t)(pos - size)) ) len = pos - size; diff --git a/src/AudioFileSourceHTTPStream.h b/src/AudioFileSourceHTTPStream.h index 34e54663..bd21386e 100644 --- a/src/AudioFileSourceHTTPStream.h +++ b/src/AudioFileSourceHTTPStream.h @@ -53,7 +53,11 @@ class AudioFileSourceHTTPStream : public AudioFileSource private: virtual uint32_t readInternal(void *data, uint32_t len, bool nonBlock); +#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3 + NetworkClient client; +#else WiFiClient client; +#endif HTTPClient http; int pos; int size; diff --git a/src/AudioFileSourceICYStream.cpp b/src/AudioFileSourceICYStream.cpp index 5b1601b4..3f89af84 100644 --- a/src/AudioFileSourceICYStream.cpp +++ b/src/AudioFileSourceICYStream.cpp @@ -115,7 +115,11 @@ uint32_t AudioFileSourceICYStream::readInternal(void *data, uint32_t len, bool n } if ((size > 0) && (pos >= size)) return 0; +#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3 + NetworkClient *stream = http.getStreamPtr(); +#else WiFiClient *stream = http.getStreamPtr(); +#endif // Can't read past EOF... if ( (size > 0) && (len > (uint32_t)(pos - size)) ) len = pos - size; diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index 63dca2f4..df7ae6f1 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -58,8 +58,8 @@ #include "AudioGeneratorMIDI.h" -#if (__GNUC__ == 8) && (__XTENSA__) -// Do not build, GCC8 has a compiler bug +#if defined(ESP32) && (__GNUC__ >= 8) && (__XTENSA__) +// Do not build, Espressif's GCC8+ has a compiler bug #else // __GNUC__ == 8 #pragma GCC optimize ("O3") diff --git a/src/AudioGeneratorMIDI.h b/src/AudioGeneratorMIDI.h index 62ede5e7..b89dcdfc 100644 --- a/src/AudioGeneratorMIDI.h +++ b/src/AudioGeneratorMIDI.h @@ -21,8 +21,8 @@ #ifndef _AUDIOGENERATORMIDI_H #define _AUDIOGENERATORMIDI_H -#if (__GNUC__ == 8) && (__XTENSA__) -// Do not build, GCC8 has a compiler bug +#if defined(ESP32) && (__GNUC__ >= 8) && (__XTENSA__) +// Do not build, Espressif's GCC8+ has a compiler bug #else // __GNUC__ == 8 #include "AudioGenerator.h" diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 8fd17775..6811b382 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -198,9 +198,9 @@ bool AudioOutputI2S::begin(bool txDAC) { // don't use audio pll on buggy rev0 chips use_apll = APLL_DISABLE; - esp_chip_info_t out_info; - esp_chip_info(&out_info); - if (out_info.revision > 0) + //esp_chip_info_t out_info; + //esp_chip_info(&out_info); + //if (out_info.revision > 0) { use_apll = APLL_ENABLE; } diff --git a/src/AudioOutputSPDIF.cpp b/src/AudioOutputSPDIF.cpp index 6837d472..6cd8cc37 100644 --- a/src/AudioOutputSPDIF.cpp +++ b/src/AudioOutputSPDIF.cpp @@ -105,7 +105,10 @@ AudioOutputSPDIF::AudioOutputSPDIF(int dout_pin, int port, int dma_buf_count) .use_apll = true, // Audio PLL is needed for low clock jitter .tx_desc_auto_clear = true, // Silence on underflow .fixed_mclk = 0, // Unused -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) +#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR >= 3 + .mclk_multiple = I2S_MCLK_MULTIPLE_512, // Unused + .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample +#elif ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 0) .mclk_multiple = I2S_MCLK_MULTIPLE_DEFAULT, // Unused .bits_per_chan = I2S_BITS_PER_CHAN_DEFAULT // Use bits per sample #endif @@ -183,12 +186,14 @@ bool AudioOutputSPDIF::SetRate(int hz) int adjustedHz = AdjustI2SRate(hz); #if defined(ESP32) if (i2s_set_sample_rates((i2s_port_t)portNo, adjustedHz) == ESP_OK) { +#if defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR < 3) if (adjustedHz == 88200) { // Manually fix the APLL rate for 44100. // See: https://github.com/espressif/esp-idf/issues/2634 // sdm0 = 28, sdm1 = 8, sdm2 = 5, odir = 0 -> 88199.977 rtc_clk_apll_enable(1, 28, 8, 5, 0); } +#endif } else { audioLogger->println("ERROR changing S/PDIF sample rate"); } diff --git a/src/libhelix-mp3/mpadecobjfixpt.h b/src/libhelix-mp3/mpadecobjfixpt.h index a8a5c40f..e295bf9e 100644 --- a/src/libhelix-mp3/mpadecobjfixpt.h +++ b/src/libhelix-mp3/mpadecobjfixpt.h @@ -70,7 +70,7 @@ class CMpaDecObj // return. // pPCM pointer to a buffer to decode into // pulPCMSize size of the PCM buffer. It will contain the - // number of PCM bytes prodced upon return. + // number of PCM bytes produced upon return. /////////////////////////////////////////////////////////////////////////// void DecodeFrame_v(unsigned char *pSource, unsigned long *pulSize, diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index ac38e610..b6635812 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -42,6 +42,16 @@ */ +// ESP32 as of 3.x has a compiler bug in this section, with the G++ generated assembly +// being illegal. There's nothing wrong with the code here, it just looks like an +// Xtensa backend issue. Until that's fixed, no MIDI for you! +///home/earle/Arduino/libraries/ESP8266Audio/src/libtinysoundfont/tsf.h: In function 'void tsf_channel_midi_control(tsf*, int, int, int)': +// /home/earle/Arduino/libraries/ESP8266Audio/src/libtinysoundfont/tsf.h:2101:1: error: insn does not satisfy its constraints: +// 2101 | } +// | ^ + +#if !defined(ESP32) + #ifndef TSF_INCLUDE_TSF_INL #define TSF_INCLUDE_TSF_INL @@ -2145,3 +2155,5 @@ TSFDEF float tsf_channel_get_tuning(tsf* f, int channel) #endif #endif //TSF_IMPLEMENTATION + +#endif // ! ESP32 From c93201483fa2a15a36ccb6296b2b9382ddfa3000 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 6 Jun 2024 14:59:31 -0700 Subject: [PATCH 130/150] Update pr-or-master-push.yml (#687) --- .github/workflows/pr-or-master-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index 1502fb36..899a918b 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -69,7 +69,7 @@ jobs: - uses: actions/checkout@v4 with: submodules: true - - uses: actions/setup-python@v4 + - uses: actions/setup-python@v5 with: python-version: '3.x' - name: Build Sketches From a0a4a007576e0a26a51f74d2d9fc2d698b3f9ba8 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sat, 21 Sep 2024 09:26:24 -0700 Subject: [PATCH 131/150] Fix release numbering --- library.json | 2 +- library.properties | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index c02e634a..ac419f22 100644 --- a/library.json +++ b/library.json @@ -14,7 +14,7 @@ "type": "git", "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.7", + "version": "1.9.9", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ diff --git a/library.properties b/library.properties index d594ee11..845f69c1 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.7 +version=1.9.9 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From 79208f670113e7612b10d2ea6205037d67811fc2 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Sun, 6 Oct 2024 16:53:22 -0700 Subject: [PATCH 132/150] Fix GCC14-detected warnings (#711) * Fix pedantic GCC14 warnings on calloc order * Ensure AAC read-in doesn't overflow internal structures when the file is corrupted/illegal. --- src/AudioOutputMixer.cpp | 4 ++-- src/libhelix-aac/decelmnt.c | 4 ++-- src/libhelix-aac/noiseless.c | 2 +- src/libhelix-aac/sbrside.c | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/AudioOutputMixer.cpp b/src/AudioOutputMixer.cpp index 57a1c06a..f0d722e7 100644 --- a/src/AudioOutputMixer.cpp +++ b/src/AudioOutputMixer.cpp @@ -71,8 +71,8 @@ bool AudioOutputMixerStub::stop() AudioOutputMixer::AudioOutputMixer(int buffSizeSamples, AudioOutput *dest) : AudioOutput() { buffSize = buffSizeSamples; - leftAccum = (int32_t*)calloc(sizeof(int32_t), buffSize); - rightAccum = (int32_t*)calloc(sizeof(int32_t), buffSize); + leftAccum = (int32_t*)calloc(buffSize, sizeof(int32_t)); + rightAccum = (int32_t*)calloc(buffSize, sizeof(int32_t)); for (int i=0; ibce[i] |= GetBits(bsi, 4); /* tag select */ } - for (i = 0; i < pce->numLCE; i++) + for (i = 0; i < pce->numLCE && i < MAX_NUM_LCE; i++) pce->lce[i] = GetBits(bsi, 4); /* tag select */ - for (i = 0; i < pce->numADE; i++) + for (i = 0; i < pce->numADE && i < MAX_NUM_ADE; i++) pce->ade[i] = GetBits(bsi, 4); /* tag select */ for (i = 0; i < pce->numCCE; i++) { diff --git a/src/libhelix-aac/noiseless.c b/src/libhelix-aac/noiseless.c index 5d3a65df..587ae276 100644 --- a/src/libhelix-aac/noiseless.c +++ b/src/libhelix-aac/noiseless.c @@ -253,7 +253,7 @@ static int DecodeOneScaleFactor(BitStreamInfo *bsi) pi->numPulse = GetBits(bsi, 2) + 1; /* add 1 here */ pi->startSFB = GetBits(bsi, 6); - for (i = 0; i < pi->numPulse; i++) { + for (i = 0; i < pi->numPulse && i < MAX_PULSES; i++) { pi->offset[i] = GetBits(bsi, 5); pi->amp[i] = GetBits(bsi, 4); } diff --git a/src/libhelix-aac/sbrside.c b/src/libhelix-aac/sbrside.c index 6bb49f31..50958efe 100644 --- a/src/libhelix-aac/sbrside.c +++ b/src/libhelix-aac/sbrside.c @@ -195,7 +195,7 @@ static void UnpackSBRGrid(BitStreamInfo *bsi, SBRHeader *sbrHdr, SBRGrid *sbrGri absBorder = GetBits(bsi, 2) + NUM_TIME_SLOTS; numRelBorder = GetBits(bsi, 2); sbrGrid->numEnv = numRelBorder + 1; - for (rel = 0; rel < numRelBorder; rel++) + for (rel = 0; rel < numRelBorder && rel < 3; rel++) relBorder[rel] = 2*GetBits(bsi, 2) + 2; pBits = cLog2[sbrGrid->numEnv + 1]; @@ -221,13 +221,13 @@ static void UnpackSBRGrid(BitStreamInfo *bsi, SBRHeader *sbrHdr, SBRGrid *sbrGri absBorder = GetBits(bsi, 2); numRelBorder = GetBits(bsi, 2); sbrGrid->numEnv = numRelBorder + 1; - for (rel = 0; rel < numRelBorder; rel++) + for (rel = 0; rel < numRelBorder && rel < 3; rel++) relBorder[rel] = 2*GetBits(bsi, 2) + 2; pBits = cLog2[sbrGrid->numEnv + 1]; sbrGrid->pointer = GetBits(bsi, pBits); - for (env = 0; env < sbrGrid->numEnv; env++) + for (env = 0; env < sbrGrid->numEnv && env < MAX_NUM_ENV; env++) sbrGrid->freqRes[env] = GetBits(bsi, 1); absBordLead = absBorder; @@ -253,16 +253,16 @@ static void UnpackSBRGrid(BitStreamInfo *bsi, SBRHeader *sbrHdr, SBRGrid *sbrGri sbrGrid->numEnv = numRelBorder0 + numRelBorder1 + 1; ASSERT(sbrGrid->numEnv <= 5); - for (rel = 0; rel < numRelBorder0; rel++) + for (rel = 0; rel < numRelBorder0 && rel < 3; rel++) relBorder0[rel] = 2*GetBits(bsi, 2) + 2; - for (rel = 0; rel < numRelBorder1; rel++) + for (rel = 0; rel < numRelBorder1 && rel < 3; rel++) relBorder1[rel] = 2*GetBits(bsi, 2) + 2; pBits = cLog2[numRelBorder0 + numRelBorder1 + 2]; sbrGrid->pointer = GetBits(bsi, pBits); - for (env = 0; env < sbrGrid->numEnv; env++) + for (env = 0; env < sbrGrid->numEnv && env < MAX_NUM_ENV; env++) sbrGrid->freqRes[env] = GetBits(bsi, 1); numRelLead = numRelBorder0; From 50bc3f72793af9d3d4c8cb06bbe207b90c1bf155 Mon Sep 17 00:00:00 2001 From: Piotr Gaczkowski Date: Mon, 7 Oct 2024 01:54:01 +0200 Subject: [PATCH 133/150] Add MCLK support for RP2040 (#707) --- src/AudioOutputI2S.cpp | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/AudioOutputI2S.cpp b/src/AudioOutputI2S.cpp index 6811b382..2e85c8be 100644 --- a/src/AudioOutputI2S.cpp +++ b/src/AudioOutputI2S.cpp @@ -116,7 +116,7 @@ bool AudioOutputI2S::SetPinout(int bclk, int wclk, int dout, int mclk) bclkPin = bclk; wclkPin = wclk; doutPin = dout; - #ifdef ESP32 + #if defined(ESP32) || defined(ARDUINO_ARCH_RP2040) mclkPin = mclk; if (i2sOn) return SetPinout(); @@ -184,6 +184,8 @@ bool AudioOutputI2S::SetMclk(bool enabled){ if (output_mode == INTERNAL_DAC || output_mode == INTERNAL_PDM) return false; // Not allowed + use_mclk = enabled; + #elif defined(ARDUINO_ARCH_RP2040) use_mclk = enabled; #endif return true; @@ -310,12 +312,16 @@ bool AudioOutputI2S::begin(bool txDAC) #elif defined(ARDUINO_ARCH_RP2040) (void)txDAC; if (!i2sOn) { - i2s.setBCLK(bclkPin); - i2s.setDATA(doutPin); - if (swap_clocks) { - i2s.swapClocks(); - } - i2s.begin(hertz); + i2s.setSysClk(hertz); + i2s.setBCLK(bclkPin); + i2s.setDATA(doutPin); + i2s.setMCLK(mclkPin); + i2s.setMCLKmult(256); + if (swap_clocks) { + i2s.swapClocks(); + } + i2s.setBitsPerSample(bps); + i2s.begin(hertz); } #endif i2sOn = true; From 96dc79c9fa9a82a2884c20c91f56b261596d22ae Mon Sep 17 00:00:00 2001 From: jmr-es <126886609+jmr-es@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:50:43 +0200 Subject: [PATCH 134/150] AudioOutputPWM: added amplification (#605) Co-authored-by: RASMUSSEN Joern --- src/AudioOutputPWM.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/AudioOutputPWM.cpp b/src/AudioOutputPWM.cpp index 6d907540..284bff92 100644 --- a/src/AudioOutputPWM.cpp +++ b/src/AudioOutputPWM.cpp @@ -89,6 +89,9 @@ bool AudioOutputPWM::ConsumeSample(int16_t sample[2]) { ms[LEFTCHANNEL] = ms[RIGHTCHANNEL] = (ttl>>1) & 0xffff; } + ms[LEFTCHANNEL] = Amplify(ms[LEFTCHANNEL]); + ms[RIGHTCHANNEL] = Amplify(ms[RIGHTCHANNEL]); + if (pwm.available()) { pwm.write((int16_t) ms[0]); pwm.write((int16_t) ms[1]); From a4a974363db76d207d54de6319916a25d96d8e09 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 8 Oct 2024 13:56:03 -0700 Subject: [PATCH 135/150] Update Arduino Lint GH Action --- .github/workflows/pr-or-master-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-or-master-push.yml b/.github/workflows/pr-or-master-push.yml index 899a918b..a209933e 100644 --- a/.github/workflows/pr-or-master-push.yml +++ b/.github/workflows/pr-or-master-push.yml @@ -116,7 +116,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: arduino/arduino-lint-action@v1 + - uses: arduino/arduino-lint-action@v2 with: library-manager: 'update' From 235bcb12de6387f8a150911576330d3d83eda959 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 8 Oct 2024 13:59:49 -0700 Subject: [PATCH 136/150] Fix UTF-8 warning in RCSL doc --- src/libhelix-mp3/RCSL.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libhelix-mp3/RCSL.txt b/src/libhelix-mp3/RCSL.txt index a809759a..4947e535 100644 --- a/src/libhelix-mp3/RCSL.txt +++ b/src/libhelix-mp3/RCSL.txt @@ -801,7 +801,7 @@ REQUIRED IN ALL CASES Notice to be included in header file of all Error Corrections and Shared Modifications: -Portions Copyright 1994-2003 © RealNetworks, Inc. All rights reserved. +Portions Copyright 1994-2003 (c) RealNetworks, Inc. All rights reserved. The contents of this file, and the files included with this file, are subject to the current version of RealNetworks Community Source License From d32d8b4cc8bf9221e7f0454e6f07997ef7d1f722 Mon Sep 17 00:00:00 2001 From: Torrentero Date: Tue, 8 Oct 2024 20:45:57 -0400 Subject: [PATCH 137/150] Performance improvement: ~13% faster on ESP32 and ~21% faster on ESP8266 (empirically tested) (#554) * Performance improvement - new tsf_note_on_fast returning playIndex and removing lowpass filter setup since it is not being processed in tsf_voice_render_fast anyway but is consuming a lot of cpu - new tsf_note_off_fast using playIndex to stop voices faster - Removing lowpass filter setup from tsf_voice_render_fast since it is not being processed - Math tweaks trying to avoid complex math operations (specially conversions) at voice render stage - Precalculating *F32P32 values to avoid doing them at voice render stage * Fixing data type * Initializing play indexes --------- Co-authored-by: Edgar --- src/AudioGeneratorMIDI.cpp | 5 +- src/AudioGeneratorMIDI.h | 5 +- src/libtinysoundfont/tsf.h | 200 ++++++++++++++++++++++++++----------- 3 files changed, 150 insertions(+), 60 deletions(-) diff --git a/src/AudioGeneratorMIDI.cpp b/src/AudioGeneratorMIDI.cpp index df7ae6f1..57d54121 100644 --- a/src/AudioGeneratorMIDI.cpp +++ b/src/AudioGeneratorMIDI.cpp @@ -443,8 +443,9 @@ int AudioGeneratorMIDI::PlayMIDI() for (tgnum = 0; tgnum < num_tonegens; ++tgnum) { /* find which generator is playing it */ tg = &tonegen[tgnum]; if (tg->playing && tg->track == tracknum && tg->note == trk->note) { - tsf_note_off (g_tsf, tg->instrument, tg->note); + tsf_note_off_fast (g_tsf, tg->instrument, tg->note, tg->playIndex); tg->playing = false; + tg->playIndex = -1; trk->tonegens[tgnum] = false; } } @@ -476,7 +477,7 @@ int AudioGeneratorMIDI::PlayMIDI() if (tg->instrument != midi_chan_instrument[trk->chan]) { /* new instrument for this generator */ tg->instrument = midi_chan_instrument[trk->chan]; } - tsf_note_on (g_tsf, tg->instrument, tg->note, trk->velocity / 127.0); // velocity = 0...127 + tg->playIndex = tsf_note_on_fast (g_tsf, tg->instrument, tg->note, trk->velocity / 127.0); // velocity = 0...127 } else { ++notes_skipped; } diff --git a/src/AudioGeneratorMIDI.h b/src/AudioGeneratorMIDI.h index b89dcdfc..9c2fc2fe 100644 --- a/src/AudioGeneratorMIDI.h +++ b/src/AudioGeneratorMIDI.h @@ -94,10 +94,13 @@ class AudioGeneratorMIDI : public AudioGenerator unsigned long earliest_time = 0; struct tonegen_status { /* current status of a tone generator */ - bool playing; /* is it playing? */ + bool playing; /* is it playing? */ char track; /* if so, which track is the note from? */ char note; /* what note is playing? */ char instrument; /* what instrument? */ + int playIndex; /* is index provided? + Unique identifier generated when note starts playing. + This help us to turn the note off faster */ } tonegen[MAX_TONEGENS]; struct track_status { /* current processing point of a MIDI track */ diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index b6635812..e40be989 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -612,11 +612,11 @@ struct tsf_voice { int playingPreset, playingKey, playingChannel; struct tsf_region* region; - double pitchInputTimecents, pitchOutputFactor; + double pitchRatio; double sourceSamplePosition; - fixed32p32 sourceSamplePositionF32P32; - float noteGainDB, panFactorLeft, panFactorRight; - unsigned int playIndex, loopStart, loopEnd; + fixed32p32 sourceSamplePositionF32P32, loopStartF32P32, loopEndF32P32, loopSizeF32P32, pitchRatioF32P32; + float noteGain, panFactorLeft, panFactorRight; + int playIndex, loopStart, loopEnd; struct tsf_voice_envelope ampenv, modenv; struct tsf_voice_lowpass lowpass; struct tsf_voice_lfo modlfo, viblfo; @@ -635,6 +635,14 @@ struct tsf_channels int channelNum, activeChannel; }; +// Math properties of tsf_timecents2Secs* (tc2s): +// # tc2s(a + b) = tc2s(a) * tc2s(b) +// # tc2s(a - b) = tc2s(a) / tc2s(b) +// # 1 / tc2s(a) = tc2s(-a) +// # The same applies to tsf_cents2Hertz and tsf_decibelsToGain +// Path properties of tsf_decibelsToGain (db2g) and tsf_gainToDecibels (g2db) +// # db2g(g2db(a)) = a +// # g2db(db2g(a)) = a static double tsf_timecents2Secsd(double timecents) { return TSF_POW(2.0, timecents / 1200.0); } static float tsf_timecents2Secsf(float timecents) { return TSF_POWF(2.0f, timecents / 1200.0f); } static float tsf_cents2Hertz(float cents) { return 8.176f * TSF_POWF(2.0f, cents / 1200.0f); } @@ -1230,6 +1238,7 @@ static void tsf_voice_end(struct tsf_voice* v, float outSampleRate) { // Continue playing, but stop looping. v->loopEnd = v->loopStart; + v->loopSizeF32P32 = 0; } } @@ -1242,10 +1251,9 @@ static void tsf_voice_endquick(struct tsf_voice* v, float outSampleRate) static void tsf_voice_calcpitchratio(struct tsf_voice* v, float pitchShift, float outSampleRate) { double note = v->playingKey + v->region->transpose + v->region->tune / 100.0; - double adjustedPitch = v->region->pitch_keycenter + (note - v->region->pitch_keycenter) * (v->region->pitch_keytrack / 100.0); - if (pitchShift) adjustedPitch += pitchShift; - v->pitchInputTimecents = adjustedPitch * 100.0; - v->pitchOutputFactor = v->region->sample_rate / (tsf_timecents2Secsd(v->region->pitch_keycenter * 100.0) * outSampleRate); + double adjustedPitch = (note - v->region->pitch_keycenter) * v->region->pitch_keytrack; + if (pitchShift) adjustedPitch += adjustedPitch * 100.0f; + v->pitchRatio = v->region->sample_rate * tsf_timecents2Secsd(adjustedPitch) / outSampleRate; } short tsf_read_short_cached(tsf *f, int pos) @@ -1313,10 +1321,10 @@ static void tsf_voice_render(tsf* f, struct tsf_voice* v, float* outputBuffer, i else tmpInitialFilterFc = 0, tmpModLfoToFilterFc = 0, tmpModEnvToFilterFc = 0; if (dynamicPitchRatio) pitchRatio = 0, tmpModLfoToPitch = (float)region->modLfoToPitch, tmpVibLfoToPitch = (float)region->vibLfoToPitch, tmpModEnvToPitch = (float)region->modEnvToPitch; - else pitchRatio = tsf_timecents2Secsd(v->pitchInputTimecents) * v->pitchOutputFactor, tmpModLfoToPitch = 0, tmpVibLfoToPitch = 0, tmpModEnvToPitch = 0; + else pitchRatio = v->pitchRatio, tmpModLfoToPitch = 0, tmpVibLfoToPitch = 0, tmpModEnvToPitch = 0; if (dynamicGain) tmpModLfoToVolume = (float)region->modLfoToVolume * 0.1f; - else noteGain = tsf_decibelsToGain(v->noteGainDB), tmpModLfoToVolume = 0; + else noteGain = v->noteGain, tmpModLfoToVolume = 0; while (numSamples) { @@ -1333,10 +1341,10 @@ static void tsf_voice_render(tsf* f, struct tsf_voice* v, float* outputBuffer, i } if (dynamicPitchRatio) - pitchRatio = tsf_timecents2Secsd(v->pitchInputTimecents + (v->modlfo.level * tmpModLfoToPitch + v->viblfo.level * tmpVibLfoToPitch + v->modenv.level * tmpModEnvToPitch)) * v->pitchOutputFactor; + pitchRatio = v->pitchRatio * tsf_timecents2Secsd(v->modlfo.level * tmpModLfoToPitch + v->viblfo.level * tmpVibLfoToPitch + v->modenv.level * tmpModEnvToPitch); if (dynamicGain) - noteGain = tsf_decibelsToGain(v->noteGainDB + (v->modlfo.level * tmpModLfoToVolume)); + noteGain = v->noteGain * tsf_decibelsToGain(v->modlfo.level * tmpModLfoToVolume); gainMono = noteGain * v->ampenv.level; @@ -1445,40 +1453,22 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff TSF_BOOL updateModEnv = (region->modEnvToPitch || region->modEnvToFilterFc); TSF_BOOL updateModLFO = (v->modlfo.delta && (region->modLfoToPitch || region->modLfoToFilterFc || region->modLfoToVolume)); TSF_BOOL updateVibLFO = (v->viblfo.delta && (region->vibLfoToPitch)); - TSF_BOOL isLooping = (v->loopStart < v->loopEnd); - unsigned int tmpLoopStart = v->loopStart, tmpLoopEnd = v->loopEnd; - //double tmpSampleEndDbl = (double)v->sampleEnd, tmpLoopEndDbl = (double)tmpLoopEnd + 1.0; - //double tmpSourceSamplePosition = v->sourceSamplePosition; - fixed32p32 tmpSampleEndF32P32 = ((fixed32p32)(region->end)) << 32; - fixed32p32 tmpLoopStartF32P32 = ((fixed32p32)(tmpLoopStart + 1)) << 32; - fixed32p32 tmpLoopEndF32P32 = ((fixed32p32)(tmpLoopEnd + 1)) << 32; + TSF_BOOL isLooping = (v->loopSizeF32P32 > 0); + fixed32p32 tmpSampleEndF32P32 = (fixed32p32)(region->end) << 32; fixed32p32 tmpSourceSamplePositionF32P32 = v->sourceSamplePositionF32P32; - struct tsf_voice_lowpass tmpLowpass = v->lowpass; - - TSF_BOOL dynamicLowpass = (region->modLfoToFilterFc || region->modEnvToFilterFc); - float tmpSampleRate = f->outSampleRate, tmpInitialFilterFc, tmpModLfoToFilterFc, tmpModEnvToFilterFc; TSF_BOOL dynamicPitchRatio = (region->modLfoToPitch || region->modEnvToPitch || region->vibLfoToPitch); - //double pitchRatio; - fixed32p32 pitchRatioF32P32; + fixed32p32 pitchRatioF32P32, tmpPitchRatioF32P32; float tmpModLfoToPitch, tmpVibLfoToPitch, tmpModEnvToPitch; TSF_BOOL dynamicGain = (region->modLfoToVolume != 0); - float noteGain, tmpModLfoToVolume; + float noteGain, tmpNoteGain, tmpModLfoToVolume; - if (dynamicLowpass) tmpInitialFilterFc = (float)region->initialFilterFc, tmpModLfoToFilterFc = (float)region->modLfoToFilterFc, tmpModEnvToFilterFc = (float)region->modEnvToFilterFc; - else tmpInitialFilterFc = 0, tmpModLfoToFilterFc = 0, tmpModEnvToFilterFc = 0; + if (dynamicPitchRatio) tmpPitchRatioF32P32 = v->pitchRatioF32P32, pitchRatioF32P32 = 0, tmpModLfoToPitch = (float)region->modLfoToPitch, tmpVibLfoToPitch = (float)region->vibLfoToPitch, tmpModEnvToPitch = (float)region->modEnvToPitch; + else pitchRatioF32P32 = v->pitchRatioF32P32, tmpModLfoToPitch = 0, tmpVibLfoToPitch = 0, tmpModEnvToPitch = 0; - if (dynamicPitchRatio) pitchRatioF32P32 = 0, tmpModLfoToPitch = (float)region->modLfoToPitch, tmpVibLfoToPitch = (float)region->vibLfoToPitch, tmpModEnvToPitch = (float)region->modEnvToPitch; - else { - double pr = tsf_timecents2Secsd(v->pitchInputTimecents) * v->pitchOutputFactor; - fixed32p32 adj = 1LL<<32; - pr *= adj; - pitchRatioF32P32 = (int64_t)pr, tmpModLfoToPitch = 0, tmpVibLfoToPitch = 0, tmpModEnvToPitch = 0; - } - - if (dynamicGain) noteGain = 0, tmpModLfoToVolume = (float)region->modLfoToVolume * 0.1f; - else noteGain = tsf_decibelsToGain(v->noteGainDB), tmpModLfoToVolume = 0; + if (dynamicGain) noteGain = 0, tmpNoteGain = v->noteGain, tmpModLfoToVolume = (float)region->modLfoToVolume * 0.1f; + else noteGain = v->noteGain, tmpModLfoToVolume = 0; while (numSamples) { @@ -1486,19 +1476,17 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff int blockSamples = (numSamples > TSF_RENDER_EFFECTSAMPLEBLOCK ? TSF_RENDER_EFFECTSAMPLEBLOCK : numSamples); numSamples -= blockSamples; - if (dynamicLowpass) - { - float fres = tmpInitialFilterFc + v->modlfo.level * tmpModLfoToFilterFc + v->modenv.level * tmpModEnvToFilterFc; - tmpLowpass.active = (fres <= 13500.0f); - if (tmpLowpass.active) tsf_voice_lowpass_setup(&tmpLowpass, tsf_cents2Hertz(fres) / tmpSampleRate); - } - if (dynamicPitchRatio) { - pitchRatioF32P32 = tsf_timecents2Secsd(v->pitchInputTimecents + (v->modlfo.level * tmpModLfoToPitch + v->viblfo.level * tmpVibLfoToPitch + v->modenv.level * tmpModEnvToPitch)) * v->pitchOutputFactor * (1LL<<32); - } + if (v->modlfo.level || v->viblfo.level || v->modenv.level) + pitchRatioF32P32 = tmpPitchRatioF32P32 * tsf_timecents2Secsd(v->modlfo.level * tmpModLfoToPitch + v->viblfo.level * tmpVibLfoToPitch + v->modenv.level * tmpModEnvToPitch); + else + pitchRatioF32P32 = tmpPitchRatioF32P32; // If all levels are 0, just bypass conversion function + } - if (dynamicGain) - noteGain = tsf_decibelsToGain(v->noteGainDB + (v->modlfo.level * tmpModLfoToVolume)); + if (dynamicGain) { + if (v->modlfo.level) noteGain = tmpNoteGain * tsf_decibelsToGain(v->modlfo.level * tmpModLfoToVolume); + else noteGain = tmpNoteGain; // If level is 0, just bypass conversion function + } gainMono = noteGain * v->ampenv.level; short gainMonoFP = gainMono * 32767; @@ -1511,7 +1499,7 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff if (updateModLFO) tsf_voice_lfo_process(&v->modlfo, blockSamples); if (updateVibLFO) tsf_voice_lfo_process(&v->viblfo, blockSamples); - while (blockSamples-- && tmpSourceSamplePositionF32P32 < tmpSampleEndF32P32) + while (blockSamples--) { unsigned int pos = (unsigned int)(tmpSourceSamplePositionF32P32>>32); if (pos == 0xffffffff) pos = 0; @@ -1523,8 +1511,14 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff // Next sample. tmpSourceSamplePositionF32P32 += pitchRatioF32P32; - if (tmpSourceSamplePositionF32P32 >= tmpLoopEndF32P32 && isLooping) - tmpSourceSamplePositionF32P32 -= (tmpLoopEndF32P32 - tmpLoopStartF32P32 + (1LL<<32)); + + if (tmpSourceSamplePositionF32P32 >= v->loopEndF32P32) + { + if (isLooping) + tmpSourceSamplePositionF32P32 -= v->loopSizeF32P32; + else if (tmpSourceSamplePositionF32P32 >= tmpSampleEndF32P32) + break; + } } if (tmpSourceSamplePositionF32P32 >= tmpSampleEndF32P32 || v->ampenv.segment == TSF_SEGMENT_DONE) @@ -1535,7 +1529,6 @@ static void tsf_voice_render_fast(tsf* f, struct tsf_voice* v, short* outputBuff } v->sourceSamplePositionF32P32 = tmpSourceSamplePositionF32P32; - if (tmpLowpass.active || dynamicLowpass) v->lowpass = tmpLowpass; } @@ -1730,13 +1723,14 @@ TSFDEF void tsf_note_on(tsf* f, int preset_index, int key, float vel) } voice = &f->voices[f->voiceNum - 4]; voice[1].playingPreset = voice[2].playingPreset = voice[3].playingPreset = -1; + voice[1].playIndex = voice[2].playIndex = voice[3].playIndex = -1; } voice->region = region; voice->playingPreset = preset_index; voice->playingKey = key; voice->playIndex = voicePlayIndex; - voice->noteGainDB = f->globalGainDB - region->attenuation - tsf_gainToDecibels(1.0f / vel); + voice->noteGain = vel * tsf_decibelsToGain(f->globalGainDB - region->attenuation); if (f->channels) { @@ -1752,7 +1746,6 @@ TSFDEF void tsf_note_on(tsf* f, int preset_index, int key, float vel) // Offset/end. voice->sourceSamplePosition = region->offset; - voice->sourceSamplePositionF32P32 = ((int64_t)region->offset)<< 32; // Loop. doLoop = (region->loop_mode != TSF_LOOPMODE_NONE && region->loop_start < region->loop_end); @@ -1777,6 +1770,86 @@ TSFDEF void tsf_note_on(tsf* f, int preset_index, int key, float vel) } } +/** + * Returns the generated playing index that can be used to identify all voices related to this note. + */ +TSFDEF int tsf_note_on_fast(tsf* f, int preset_index, int key, float vel) +{ + if (preset_index < 0 || preset_index >= f->presetNum) return -1; + if (!vel) { tsf_note_off(f, preset_index, key); return -1; } + if (f->presets[preset_index].regions == NULL) tsf_load_preset(f, f->hydra, preset_index); + + short midiVelocity = (short)(vel * 127); + struct tsf_region *region, *regionEnd; + + // Play all matching regions. + int voicePlayIndex = f->voicePlayIndex++; + for (region = f->presets[preset_index].regions, regionEnd = region + f->presets[preset_index].regionNum; region != regionEnd; region++) + { + if (key < region->lokey || key > region->hikey || midiVelocity < region->lovel || midiVelocity > region->hivel) continue; + + struct tsf_voice *voice, *v, *vEnd; TSF_BOOL doLoop; + voice = TSF_NULL, v = f->voices, vEnd = v + f->voiceNum; + if (region->group) + { + for (; v != vEnd; v++) + if (v->playingPreset == preset_index && v->region->group == region->group) tsf_voice_endquick(v, f->outSampleRate); + else if (v->playingPreset == -1 && !voice) voice = v; + } + else for (; v != vEnd; v++) if (v->playingPreset == -1) { voice = v; break; } + + if (!voice) + { + f->voiceNum += 4; + struct tsf_voice *saveVoice = f->voices; + f->voices = (struct tsf_voice*)TSF_REALLOC(f->voices, f->voiceNum * sizeof(struct tsf_voice)); + if (!f->voices) { + f->voices = saveVoice; + printf("OOM, no room for new voice. Ignoring note_on\n"); + return -1; + } + voice = &f->voices[f->voiceNum - 4]; + voice[1].playingPreset = voice[2].playingPreset = voice[3].playingPreset = -1; + voice[1].playIndex = voice[2].playIndex = voice[3].playIndex = -1; + } + + voice->region = region; + voice->playingPreset = preset_index; + voice->playingKey = key; + voice->playIndex = voicePlayIndex; + voice->noteGain = vel * tsf_decibelsToGain(f->globalGainDB - region->attenuation); + + if (f->channels) + { + f->channels->setupVoice(f, voice); + } + else + { + tsf_voice_calcpitchratio(voice, 0, f->outSampleRate); + voice->pitchRatioF32P32 = voice->pitchRatio * (1LL << 32); + } + + // Offset/end. + voice->sourceSamplePositionF32P32 = ((int64_t)region->offset)<< 32; + + // Loop. + doLoop = (region->loop_mode != TSF_LOOPMODE_NONE && region->loop_start < region->loop_end); + voice->loopStartF32P32 = doLoop ? ((int64_t)region->loop_start + 1) << 32 : 0; + voice->loopEndF32P32 = doLoop ? ((int64_t)region->loop_end + 1) << 32 : 0; + voice->loopSizeF32P32 = doLoop ? voice->loopEndF32P32 - voice->loopStartF32P32 + (1LL << 32) : 0; + + // Setup envelopes. + tsf_voice_envelope_setup(&voice->ampenv, ®ion->ampenv, key, midiVelocity, TSF_TRUE, f->outSampleRate); + tsf_voice_envelope_setup(&voice->modenv, ®ion->modenv, key, midiVelocity, TSF_FALSE, f->outSampleRate); + + // Setup LFO filters. + tsf_voice_lfo_setup(&voice->modlfo, region->delayModLFO, region->freqModLFO, f->outSampleRate); + tsf_voice_lfo_setup(&voice->viblfo, region->delayVibLFO, region->freqVibLFO, f->outSampleRate); + } + + return voicePlayIndex; +} + TSFDEF int tsf_bank_note_on(tsf* f, int bank, int preset_number, int key, float vel) { int preset_index = tsf_get_presetindex(f, bank, preset_number); @@ -1805,6 +1878,19 @@ TSFDEF void tsf_note_off(tsf* f, int preset_index, int key) } } +/** + * Stops all voices with the given playing index. If no key provided or if -1, fallbacks to tsf_note_off + */ +TSFDEF void tsf_note_off_fast(tsf* f, int preset_index, int key, int playIndex = -1) +{ + if (playIndex < 0) + tsf_note_off(f, preset_index, key); + else + for (struct tsf_voice *v = f->voices, *vEnd = v + f->voiceNum; v != vEnd; v++) + if (v->playIndex == playIndex && v->playingPreset == preset_index && v->playingKey == key && v->ampenv.segment < TSF_SEGMENT_RELEASE) + tsf_voice_end(v, f->outSampleRate); +} + TSFDEF int tsf_bank_note_off(tsf* f, int bank, int preset_number, int key) { int preset_index = tsf_get_presetindex(f, bank, preset_number); @@ -1884,7 +1970,7 @@ static void tsf_channel_setup_voice(tsf* f, struct tsf_voice* v) struct tsf_channel* c = &f->channels->channels[f->channels->activeChannel]; float newpan = v->region->pan + c->panOffset; v->playingChannel = f->channels->activeChannel; - v->noteGainDB += c->gainDB; + v->noteGain *= tsf_decibelsToGain(c->gainDB); tsf_voice_calcpitchratio(v, (c->pitchWheel == 8192 ? c->tuning : ((c->pitchWheel / 16383.0f * c->pitchRange * 2.0f) - c->pitchRange + c->tuning)), f->outSampleRate); if (newpan <= -0.5f) { v->panFactorLeft = 1.0f; v->panFactorRight = 0.0f; } else if (newpan >= 0.5f) { v->panFactorLeft = 0.0f; v->panFactorRight = 1.0f; } @@ -1994,7 +2080,7 @@ TSFDEF void tsf_channel_set_volume(tsf* f, int channel, float volume) if (gainDBChange == 0) return; for (v = f->voices, vEnd = v + f->voiceNum; v != vEnd; v++) if (v->playingChannel == channel && v->playingPreset != -1) - v->noteGainDB += gainDBChange; + v->noteGain *= tsf_decibelsToGain(gainDBChange); c->gainDB = gainDB; } From 52c49afbc0a9494a035a0fb3d13fb5e11c37f0b4 Mon Sep 17 00:00:00 2001 From: Roman Lut <11955117+RomanLut@users.noreply.github.com> Date: Wed, 9 Oct 2024 02:49:03 +0200 Subject: [PATCH 138/150] NoDAC and PDM documentation update for ESP32 (#519) --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c94c7946..a4e9c1b3 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ AudioGeneratorRTTTL: Enjoy the pleasures of monophonic, 4-octave ringtones on y ## AudioOutput classes AudioOutput: Base class for all output drivers. Takes a sample at a time and returns true/false if there is buffer space for it. If it returns false, it is the calling object's (AudioGenerator's) job to keep the data that didn't fit and try again later. -AudioOutputI2S: Interface for any I2S 16-bit DAC. Sends stereo or mono signals out at whatever frequency set. Tested with Adafruit's I2SDAC and a Beyond9032 DAC from eBay. Tested up to 44.1KHz. To use the internal DAC on ESP32, instantiate this class as `AudioOutputI2S(0,1)`, see example `PlayMODFromPROGMEMToDAC` and code in [AudioOutputI2S.cpp](src/AudioOutputI2S.cpp#L29) for details. +AudioOutputI2S: Interface for any I2S 16-bit DAC. Sends stereo or mono signals out at whatever frequency set. Tested with Adafruit's I2SDAC and a Beyond9032 DAC from eBay. Tested up to 44.1KHz. To use the internal DAC on ESP32, instantiate this class as `AudioOutputI2S(0,AudioOutputI2S::INTERNAL_DAC)`, see example `PlayMODFromPROGMEMToDAC` and code in [AudioOutputI2S.cpp](src/AudioOutputI2S.cpp#L29) for details. To use the hardware Pulse Density Modulation (PDM) on ESP32, instantiate this class as `AudioOutputI2S(0,AudioOutputI2S::INTERNAL_PDM)`. For both later cases, default output pins are GPIO25 and GPIO26. AudioOutputI2SNoDAC: Abuses the I2S interface to play music without a DAC. Turns it into a 32x (or higher) oversampling delta-sigma DAC. Use the schematic below to drive a speaker or headphone from the I2STx pin (i.e. Rx). Note that with this interface, depending on the transistor used, you may need to disconnect the Rx pin from the driver to perform serial uploads. Mono-only output, of course. @@ -190,7 +190,8 @@ Use the `AudioOutputI2S*No*DAC` object instead of the `AudioOutputI2S` in your c ESP8266-GND ------------------+ | +------+ K| | | | E| ESP8266-I2SOUT (Rx) -----/\/\/\--+ | \ R| - | +-| +or ESP32 DOUT pin | +-| + | USB 5V -----------------------------+ You may also want to add a 220uF cap from USB5V to GND just to help filter out any voltage droop during high volume playback. @@ -203,12 +204,19 @@ ESP8266-RX(I2S tx) -- Resistor (~1K ohm, not critical) -- 2N3904 Base ESP8266-GND -- 2N3904 Emitter USB-5V -- Speaker + Terminal 2N3904-Collector -- Speaker - Terminal + +*For ESP32, default output pin is GPIO22. Note that GPIO25 ang GPIO26 are occupied by wclk/bclk and can not be used. ``` *NOTE*: A prior version of this schematic had a direct connection from the ESP8266 to the base of the transistor. While this does provide the maximum amplitude, it also can draw more current from the 8266 than is safe, and can also cause the transistor to overheat. As of the latest ESP8266Audio release, with the software delta-sigma DAC the LRCLK and BCLK pins *can* be used by an application. Simply use normal `pinMode` and `digitalWrite` or `digitalRead` as desired. +### Hardware PDM on ESP32 + +Hardware PDM outputs 128 * 48Khz pulses regardles of samplerate. +It seems that currently hardware PDM either does not output constant One at maximum sample level, or does not output 3.3V voltage at pulse ( unfortunatelly I not have oscilloscope to test currently) - sound is not as loud as desired. You may consider using software delta-sigma DAC instead. + ### High pitched buzzing with the 1-T circuit The 1-T amp can _NOT_ drive any sort of amplified speaker. If there is a power or USB input to the speaker, or it has lights or Bluetooth or a battery, it can _NOT_ be used with this circuit. From 1278b107174a2c48c9f63b676535a7e71f86fcbc Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 8 Oct 2024 17:51:13 -0700 Subject: [PATCH 139/150] Update library.properties --- library.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/library.properties b/library.properties index 845f69c1..0a7fbc2b 100644 --- a/library.properties +++ b/library.properties @@ -7,3 +7,4 @@ paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Ta category=Signal Input/Output url=https://github.com/earlephilhower/ESP8266Audio architectures=esp8266,esp32,rp2040 +dot_a_linkage=true From 7e50a43b4be47d34ba4b4a40f6461a7a96f1f7c8 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 8 Oct 2024 18:13:22 -0700 Subject: [PATCH 140/150] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a4e9c1b3..4aad8153 100644 --- a/README.md +++ b/README.md @@ -214,8 +214,8 @@ As of the latest ESP8266Audio release, with the software delta-sigma DAC the LRC ### Hardware PDM on ESP32 -Hardware PDM outputs 128 * 48Khz pulses regardles of samplerate. -It seems that currently hardware PDM either does not output constant One at maximum sample level, or does not output 3.3V voltage at pulse ( unfortunatelly I not have oscilloscope to test currently) - sound is not as loud as desired. You may consider using software delta-sigma DAC instead. +Hardware PDM outputs 128 * 48Khz pulses regardless of sample rate. +It seems that currently hardware PDM either does not output constant One at maximum sample level, or does not output 3.3V voltage at pulse sound is not as loud as desired. You may consider using software delta-sigma DAC instead. ### High pitched buzzing with the 1-T circuit The 1-T amp can _NOT_ drive any sort of amplified speaker. If there is a power or USB input to the speaker, or it has lights or Bluetooth or a battery, it can _NOT_ be used with this circuit. From 0e5870a44015c91c8e6ae99cc34ff285f372dfbe Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 8 Oct 2024 18:24:41 -0700 Subject: [PATCH 141/150] Update library.properties dot_a_linkage seems to cause issues with CI --- library.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/library.properties b/library.properties index 0a7fbc2b..845f69c1 100644 --- a/library.properties +++ b/library.properties @@ -7,4 +7,3 @@ paragraph=Decode compressed MP3, AAC, FLAC, Screamtracker MOD, MIDI, RTTL, TI Ta category=Signal Input/Output url=https://github.com/earlephilhower/ESP8266Audio architectures=esp8266,esp32,rp2040 -dot_a_linkage=true From 2f43b3b57d846bd7eb02ec30b318194b30fd8e2b Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Mon, 14 Oct 2024 17:48:14 -0700 Subject: [PATCH 142/150] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4aad8153..5579fbea 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi Pico RP2040 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) +# ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi Pico RP2040 and Pico 2 RP2350 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTTL files and playing them on an I2S DAC or even using a software-simulated delta-sigma DAC with dynamic 32x-128x oversampling. ESP8266 is fully supported and most mature, but ESP32 is also mostly there with built-in DAC as well as external ones. From fbe69b8cd81052af61248aca480da0c559fdcd46 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 18 Dec 2024 14:39:07 -0800 Subject: [PATCH 143/150] Fix AAC HR decode on RP2040 U64 big/little endian mismatch for ARM cores. Remove the whole PowerPC support option as there aren't any commerically significant PPC embedded systems still being developed. --- src/libhelix-aac/assembly.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/libhelix-aac/assembly.h b/src/libhelix-aac/assembly.h index 0c17f0c4..73c2e390 100644 --- a/src/libhelix-aac/assembly.h +++ b/src/libhelix-aac/assembly.h @@ -558,14 +558,8 @@ static __inline int CLZ(int x) typedef union _U64 { Word64 w64; struct { -#if defined(__XTENSA__) || defined (__riscv) unsigned int lo32; signed int hi32; -#else - /* PowerPC = big endian */ - signed int hi32; - unsigned int lo32; -#endif } r; } U64; From 90b83fb95e9e4b33798ba08e3bb74175cf8fe550 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 18 Dec 2024 15:11:36 -0800 Subject: [PATCH 144/150] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5579fbea..5ef61e9e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi Pico RP2040 and Pico 2 RP2350 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTTL files and playing them on an I2S DAC or even using a software-simulated delta-sigma DAC with dynamic 32x-128x oversampling. +# Raspberry Pi Pico (RP2040 and RP2350) Users +Consider using [BackgroundAudio](https://github.com/earlephilhower/BackgroundAudio) instead of this library as it can provide a simpler usage model and better results and performance on the Pico by using an interrupt-based, frame-aligned output model. + +# ESP8266 and ESP32 Users ESP8266 is fully supported and most mature, but ESP32 is also mostly there with built-in DAC as well as external ones. For real-time, autonomous speech synthesis, check out [ESP8266SAM](https://github.com/earlephilhower/ESP8266SAM), a library which uses this one and a port of an ancient formant-based synthesis program to allow your ESP8266 to talk with low memory and no network required. From aafabf236797e45385b7b469961c6fe10bf7d1aa Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 19 Dec 2024 09:33:01 -0800 Subject: [PATCH 145/150] Ensure MP3 can safely exit on OOM (#716) Fixes #715. Good catch, @EternityForest --- src/AudioGeneratorMP3.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/AudioGeneratorMP3.cpp b/src/AudioGeneratorMP3.cpp index 36c93ba5..4aa8b250 100644 --- a/src/AudioGeneratorMP3.cpp +++ b/src/AudioGeneratorMP3.cpp @@ -27,6 +27,9 @@ AudioGeneratorMP3::AudioGeneratorMP3() file = NULL; output = NULL; buff = NULL; + synth = NULL; + frame = NULL; + stream = NULL; nsCountMax = 1152/32; madInitted = false; } @@ -37,6 +40,9 @@ AudioGeneratorMP3::AudioGeneratorMP3(void *space, int size): preallocateSpace(sp file = NULL; output = NULL; buff = NULL; + synth = NULL; + frame = NULL; + stream = NULL; nsCountMax = 1152/32; madInitted = false; } @@ -51,6 +57,9 @@ AudioGeneratorMP3::AudioGeneratorMP3(void *buff, int buffSize, void *stream, int file = NULL; output = NULL; buff = NULL; + synth = NULL; + frame = NULL; + stream = NULL; nsCountMax = 1152/32; madInitted = false; } From cdd07c92c27a86f445f1f440a0e665ecb655161f Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Thu, 19 Dec 2024 14:33:24 -0800 Subject: [PATCH 146/150] Only block tsf.h on Xtensa ESP32, not RISCV (#722) Fixes #721 --- src/libtinysoundfont/tsf.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtinysoundfont/tsf.h b/src/libtinysoundfont/tsf.h index e40be989..a1bca925 100644 --- a/src/libtinysoundfont/tsf.h +++ b/src/libtinysoundfont/tsf.h @@ -50,7 +50,9 @@ // 2101 | } // | ^ -#if !defined(ESP32) +#if defined(ESP32) && (__GNUC__ >= 8) && (__XTENSA__) +// Not defined, can't build +#else #ifndef TSF_INCLUDE_TSF_INL #define TSF_INCLUDE_TSF_INL From b0a06edde2044e3d13497360072048f71e24c864 Mon Sep 17 00:00:00 2001 From: Kurt Haenen Date: Wed, 25 Dec 2024 22:19:16 +0100 Subject: [PATCH 147/150] Fixing crash on MP3 playback on ESP8266. (#723) Co-authored-by: kurt.haenen --- src/libmad/layer3.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/libmad/layer3.c b/src/libmad/layer3.c index 95d5f4f4..027183b4 100644 --- a/src/libmad/layer3.c +++ b/src/libmad/layer3.c @@ -363,7 +363,8 @@ static mad_fixed_t const root_table_val[7] PROGMEM = { }; static inline mad_fixed_t root_table(int i) { - return root_table_val[i]; + volatile mad_fixed_t a = root_table_val[i]; + return a; } /* coefficients for aliasing reduction @@ -381,7 +382,8 @@ static mad_fixed_t const cs_val[8] PROGMEM = { }; static inline mad_fixed_t cs(int i) { - return cs_val[i]; + volatile mad_fixed_t a = cs_val[i]; + return a; } static mad_fixed_t const ca_val[8] PROGMEM = { @@ -392,7 +394,8 @@ static mad_fixed_t const ca_val[8] PROGMEM = { }; static inline mad_fixed_t ca(int i) { - return ca_val[i]; + volatile mad_fixed_t a = ca_val[i]; + return a; } /* @@ -438,7 +441,8 @@ static mad_fixed_t const window_l_val[36] PROGMEM = { }; static inline mad_fixed_t window_l(int i) { - return window_l_val[i]; + volatile mad_fixed_t a = window_l_val[i]; + return *(mad_fixed_t*)&a; } # endif /* ASO_IMDCT */ @@ -458,7 +462,8 @@ static mad_fixed_t const window_s_val[12] PROGMEM = { }; static inline mad_fixed_t window_s(int i) { - return window_s_val[i]; + volatile mad_fixed_t a = window_s_val[i]; + return a; } /* @@ -479,7 +484,8 @@ static mad_fixed_t const is_table_val[7] PROGMEM = { }; static inline mad_fixed_t is_table(int i) { - return is_table_val[i]; + volatile mad_fixed_t a = is_table_val[i]; + return a; } /* From 8adeb31d2090e1d933aa7ce0a7359bd2f4fe0331 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 31 Dec 2024 10:30:06 -0800 Subject: [PATCH 148/150] Automate version bumps, avoid manual mistakes (#725) --- tools/README.md | 15 +++++++++++++++ tools/makever.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 tools/README.md create mode 100755 tools/makever.py diff --git a/tools/README.md b/tools/README.md new file mode 100644 index 00000000..51d3e0ca --- /dev/null +++ b/tools/README.md @@ -0,0 +1,15 @@ +Publishing New Releases +======================= + +First, update the version number throughout the repo and push the change: + + ./tools/makever.py --version X.Y.Z + git commit -a -m "Update version" + git push + +Then tag it + + git tag X.Y.Z + git push origin X.Y.Z + +Then on the GH web interface make a new release from that tag. diff --git a/tools/makever.py b/tools/makever.py new file mode 100755 index 00000000..7ae3f47e --- /dev/null +++ b/tools/makever.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +import sys +import struct +import subprocess +import re +import os +import os.path +import argparse +import time +import shutil +import json + +def main(): + parser = argparse.ArgumentParser(description='Version updater') + parser.add_argument('-v', '--version', action='store', required=True, help='Version in X.Y.Z form') + args = parser.parse_args() + + major, minor, sub = args.version.split(".") + # Silly way to check for integer x.y.z + major = int(major) + minor = int(minor) + sub = int(sub) + + # library.properties + with open("library.properties", "r") as fin: + with open("library.properties.new", "w") as fout: + for l in fin: + if l.startswith("version="): + l = "version=" + str(args.version) + "\n" + fout.write(l); + shutil.move("library.properties.new", "library.properties") + + # package.json + with open("library.json", "r") as fin: + library = json.load(fin); + library["version"] = str(args.version); + with open("library.json.new", "w") as fout: + json.dump(library, fout, indent = 4); + shutil.move("library.json.new", "library.json") + +main() From 3044568f85224e0f5f13b19c15640ef3f1629ff7 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Tue, 31 Dec 2024 10:30:46 -0800 Subject: [PATCH 149/150] Update version --- library.json | 12 ++++++------ library.properties | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/library.json b/library.json index ac419f22..79970df8 100644 --- a/library.json +++ b/library.json @@ -12,15 +12,15 @@ ], "repository": { "type": "git", - "url": "https://github.com/earlephilhower/ESP8266Audio" + "url": "https://github.com/earlephilhower/ESP8266Audio" }, - "version": "1.9.9", + "version": "2.0.0", "homepage": "https://github.com/earlephilhower/ESP8266Audio", "frameworks": "Arduino", "examples": [ "examples/*/*.ino" ], - "build": { - "libLDFMode": "deep" - } -} + "build": { + "libLDFMode": "deep" + } +} \ No newline at end of file diff --git a/library.properties b/library.properties index 845f69c1..acf74ab0 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=ESP8266Audio -version=1.9.9 +version=2.0.0 author=Earle F. Philhower, III maintainer=Earle F. Philhower, III sentence=Audio file and I2S sound playing routines for ESP8266, ESP32, and Raspberry Pi Pico RP2040 From 7e2b839f213df577a2ae88ba02ab94f07ad8e490 Mon Sep 17 00:00:00 2001 From: "Earle F. Philhower, III" Date: Wed, 22 Jan 2025 13:33:31 -0800 Subject: [PATCH 150/150] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5ef61e9e..4ff7d141 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # ESP8266Audio - supports ESP8266 & ESP32 & Raspberry Pi Pico RP2040 and Pico 2 RP2350 [![Gitter](https://badges.gitter.im/ESP8266Audio/community.svg)](https://gitter.im/ESP8266Audio/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) Arduino library for parsing and decoding MOD, WAV, MP3, FLAC, MIDI, AAC, and RTTL files and playing them on an I2S DAC or even using a software-simulated delta-sigma DAC with dynamic 32x-128x oversampling. -# Raspberry Pi Pico (RP2040 and RP2350) Users +# ESP32, Raspberry Pi Pico (RP2040 and RP2350) Users Consider using [BackgroundAudio](https://github.com/earlephilhower/BackgroundAudio) instead of this library as it can provide a simpler usage model and better results and performance on the Pico by using an interrupt-based, frame-aligned output model. # ESP8266 and ESP32 Users