├── .github └── workflows │ └── ci.yml ├── .gitignore ├── COPYING ├── ChangeLog ├── Makefile.am ├── README.md ├── README.old ├── android ├── Binary.mk └── Library.mk ├── bootstrap ├── configure.ac ├── js ├── .npmignore ├── .prettierignore ├── .prettierrc ├── Makefile ├── README.md ├── dist │ ├── libshine_browser.js │ ├── libshine_browser_stubs.js │ └── libshine_node.js ├── libshine.d.ts ├── package-lock.json ├── package.json ├── src │ ├── libshine_browser_wrapper.js │ ├── libshine_class.js │ ├── libshine_node_wrapper.js │ └── wrapper.c └── test │ ├── browser │ ├── Makefile │ ├── encode.js │ ├── encode.wav │ ├── index.html │ ├── libshine_node.js │ └── rounds.js │ ├── lib │ ├── encode.wav │ └── rounds.js │ ├── nextjs │ ├── .eslintrc.json │ ├── .gitignore │ ├── .prettierignore │ ├── .prettierrc │ ├── README.md │ ├── lib │ │ ├── encode.ts │ │ ├── encode.wav │ │ └── rounds.ts │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── pages │ │ └── index.tsx │ ├── pnpm-lock.yaml │ ├── public │ │ └── encode.wav │ └── tsconfig.json │ └── node │ ├── encode.ts │ ├── package-lock.json │ ├── package.json │ ├── pnpm-lock.yaml │ ├── rounds.ts │ └── tsconfig.json ├── libshine.sym ├── shine.pc.in └── src ├── bin ├── main.c ├── main.h ├── wave.c └── wave.h └── lib ├── bitstream.c ├── bitstream.h ├── huffman.c ├── huffman.h ├── l3bitstream.c ├── l3bitstream.h ├── l3loop.c ├── l3loop.h ├── l3mdct.c ├── l3mdct.h ├── l3subband.c ├── l3subband.h ├── layer3.c ├── layer3.h ├── mult_mips_gcc.h ├── mult_noarch_gcc.h ├── mult_sarm_gcc.h ├── reservoir.c ├── reservoir.h ├── tables.c ├── tables.h └── types.h /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Build and install 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | 8 | concurrency: 9 | group: ${{ github.workflow }}-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | build: 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | os: [macos-latest, ubuntu-latest] 19 | steps: 20 | - uses: actions/checkout@v3 21 | - name: Install required packages on macos 22 | if: matrix.os == 'macos-latest' 23 | run: brew install autoconf automake pkg-config 24 | - name: Install required packages on ubuntu 25 | if: matrix.os == 'ubuntu-latest' 26 | run: sudo apt-get -y install automake autoconf pkg-config 27 | - name: bootstrap 28 | run: ./bootstrap 29 | - name: configure 30 | run: ./configure 31 | - name: make 32 | run: make 33 | - name: make install on macos 34 | if: matrix.os == 'macos-latest' 35 | run: make install 36 | - name: make install on ubuntu 37 | if: matrix.os == 'ubuntu-latest' 38 | run: sudo make install 39 | - name: Test pkg-config setup 40 | run: pkg-config --libs shine 41 | 42 | android_build: 43 | runs-on: ubuntu-latest 44 | steps: 45 | - uses: actions/checkout@v3 46 | - uses: nttld/setup-ndk@v1 47 | with: 48 | ndk-version: r25b 49 | local-cache: true 50 | - name: Install autoconf/automake 51 | run: sudo apt-get -y install automake autoconf 52 | - name: bootstrap 53 | run: ./bootstrap 54 | - name: configure 55 | run: ./configure 56 | - name: make android 57 | run: make android 58 | 59 | js_build: 60 | runs-on: ubuntu-latest 61 | steps: 62 | - uses: actions/checkout@v3 63 | - uses: mymindstorm/setup-emsdk@v11 64 | - name: JS build 65 | run: | 66 | cd js 67 | make 68 | - uses: actions/setup-node@v3 69 | - name: Run node test 70 | run: | 71 | cd js/test/node 72 | npm install 73 | npm run test 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | obj 3 | libs 4 | compile 5 | android/ 6 | js/src/post-node.js 7 | !android/*.mk 8 | shine 9 | shine.pc 10 | m4 11 | /Makefile 12 | Makefile.in 13 | aclocal.m4 14 | autom4te.cache/ 15 | config.guess 16 | config.log 17 | config.status 18 | config.sub 19 | configure 20 | depcomp 21 | install-sh 22 | libtool 23 | ltmain.sh 24 | missing 25 | src/.deps/ 26 | src/.libs/ 27 | src/unused 28 | src/Makefile 29 | src/Makefile.in 30 | src/bitstream.lo 31 | src/bitstream.o 32 | src/formatbits.lo 33 | src/formatbits.o 34 | src/huffman.lo 35 | src/huffman.o 36 | src/l3bitstream.lo 37 | src/l3bitstream.o 38 | src/l3loop.lo 39 | src/l3loop.o 40 | src/l3mdct.lo 41 | src/l3mdct.o 42 | src/l3subband.lo 43 | src/l3subband.o 44 | src/layer3.lo 45 | src/layer3.o 46 | src/libshine.la 47 | src/main.o 48 | src/reservoir.lo 49 | src/reservoir.o 50 | src/shineenc 51 | src/tables.lo 52 | src/tables.o 53 | src/wave.o 54 | .libs/ 55 | libshine.la 56 | shineenc 57 | src/bin/.deps/ 58 | src/bin/.dirstamp 59 | src/bin/shineenc-main.o 60 | src/bin/shineenc-wave.o 61 | src/lib/.deps/ 62 | src/lib/.dirstamp 63 | src/lib/.libs/ 64 | src/lib/bitstream.lo 65 | src/lib/bitstream.o 66 | src/lib/formatbits.lo 67 | src/lib/formatbits.o 68 | src/lib/huffman.lo 69 | src/lib/huffman.o 70 | src/lib/l3bitstream.lo 71 | src/lib/l3bitstream.o 72 | src/lib/l3loop.lo 73 | src/lib/l3loop.o 74 | src/lib/l3mdct.lo 75 | src/lib/l3mdct.o 76 | src/lib/l3subband.lo 77 | src/lib/l3subband.o 78 | src/lib/layer3.lo 79 | src/lib/layer3.o 80 | src/lib/reservoir.lo 81 | src/lib/reservoir.o 82 | src/lib/tables.lo 83 | src/lib/tables.o 84 | shine-*.tar.gz 85 | *.o 86 | *.mp3 87 | node_modules 88 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | x.y.z () 2 | ===== 3 | * Be more specific when enabling MIPS assembly routines. 4 | * Fix wave header reading on big endian machines (#34) 5 | 6 | 3.1.1 (2017-07-28) 7 | ===== 8 | * Remove invalid MPEG 2.5 bitrates. 9 | 10 | 3.1.0 (2014-08-01): 11 | ===== 12 | * Fixed WAV file parsing. 13 | * Explicitely unroll some loops 14 | to enhance encoding speed. Thanks 15 | to @ckthomas on github for these 16 | changes! 17 | * Add -funroll-loops to CFLAGS 18 | * Major code cleanup by @zhaoxiu-zeng 19 | on `LingYunZhi/shine`. 20 | * Added interleaved API, also contributed 21 | by @zhaoxiu-zeng 22 | * Bumped ABI to 3.1.0 23 | 24 | 3.0.0 (2013-07-21): 25 | ====== 26 | * Added support for MPEG-II and 2.5 27 | * Added Javascript build and API. 28 | 29 | 2.0.0 (2013-04-07): 30 | ====== 31 | * Prefix symbols to avoid name clash 32 | with libmp3lame. 33 | * Rename public API from L3_ to shine_ 34 | to also avoid name clash. 35 | 36 | 1.0.0 (2013-02-02): 37 | ====== 38 | * Initial release 39 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | .PHONY : android 2 | 3 | EXTRA_DIST = ChangeLog src/lib/*.h src/bin/*.h README* libshine.sym js 4 | 5 | AUTOMAKE_OPTIONS = foreign 6 | ACLOCAL_AMFLAGS = -I m4 7 | 8 | CFLAGS = @CFLAGS@ -funroll-loops -fno-exceptions -Wall -O2 -fsigned-char 9 | 10 | lib_LTLIBRARIES = libshine.la 11 | libshine_la_SOURCES = src/lib/bitstream.c src/lib/huffman.c \ 12 | src/lib/l3bitstream.c src/lib/l3loop.c src/lib/l3mdct.c \ 13 | src/lib/l3subband.c src/lib/layer3.c src/lib/reservoir.c \ 14 | src/lib/tables.c 15 | 16 | libshine_la_LDFLAGS = -lm -no-undefined -version-info 3:1:0 -export-symbols libshine.sym 17 | libshine_ladir = ${prefix}/include/shine 18 | libshine_la_HEADERS = src/lib/layer3.h 19 | 20 | bin_PROGRAMS = shineenc 21 | shineenc_SOURCES = src/bin/main.c src/bin/wave.c 22 | shineenc_LDADD = libshine.la 23 | shineenc_CFLAGS = -Isrc/lib 24 | 25 | pkgconfigdir = $(libdir)/pkgconfig 26 | pkgconfig_DATA = shine.pc 27 | 28 | android: 29 | [ -d android/include ] || mkdir android/include 30 | [ -d android/lib ] || mkdir android/lib 31 | [ -d android/bin ] || mkdir android/bin 32 | cp src/lib/layer3.h android/include 33 | NDK_PROJECT_PATH=$(shell pwd) ndk-build APP_BUILD_SCRIPT=$(shell pwd)/android/Library.mk 34 | mv libs/* android/lib 35 | NDK_PROJECT_PATH=$(shell pwd) ndk-build APP_BUILD_SCRIPT=$(shell pwd)/android/Binary.mk 36 | mv libs/* android/bin 37 | 38 | clean-local: 39 | -rm -rf obj libs android/lib android/bin android/include 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Shine: fast fixed-point mp3 encoding 2 | ==================================== 3 | 4 | [shine](https://github.com/savonet/shine) is a blazing fast mp3 encoding library implemented in 5 | fixed-point arithmetic. The library can thus be used to perform super fast mp3 encoding on architectures 6 | without a FPU, such as `armel`, etc.. It is also super fast on architectures with a FPU! 7 | 8 | How to use? 9 | ----------- 10 | 11 | The encoding API should be quite straight forward: 12 | 13 | ```c 14 | #include 15 | 16 | (...) 17 | 18 | /* See if samplerate and bitrate are valid */ 19 | if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) 20 | error("Unsupported samplerate/bitrate configuration."); 21 | 22 | /* Initiate encoder */ 23 | s = shine_initialise(&config); 24 | 25 | /* Number of samples (per channel) to feed the encoder with. */ 26 | int samples_per_pass = shine_samples_per_pass(s); 27 | 28 | /* All the magic happens here */ 29 | while (read(buffer, infile, samples_per_pass)) { 30 | data = shine_encode_buffer(s,buffer,&written); 31 | write(data, written); 32 | } 33 | 34 | /* Flush and write remaining data. */ 35 | data = shine_flush(s,&written); 36 | write(written, data); 37 | 38 | /* Close encoder. */ 39 | shine_close(s); 40 | ``` 41 | 42 | How fast is it? 43 | --------------- 44 | 45 | On a macbook pro (`arm64`/M1 pro, `FPU`, December 30, 2022): 46 | 47 | Lame, `88.7x` realtime: 48 | ```bash 49 | LAME 3.100 64bits (http://lame.sf.net) 50 | Using polyphase lowpass filter, transition band: 16538 Hz - 17071 Hz 51 | Encoding /tmp/decoded.wav to /tmp/lame.mp3 52 | Encoding as 44.1 kHz j-stereo MPEG-1 Layer III (11x) 128 kbps qval=3 53 | Frame | CPU time/estim | REAL time/estim | play/CPU | ETA 54 | 12203/12203 (100%)| 0:03/ 0:03| 0:04/ 0:04| 88.773x| 0:00 55 | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 56 | kbps LR MS % long switch short % 57 | 128.0 32.6 67.4 96.4 1.9 1.7 58 | Writing LAME Tag...done 59 | ReplayGain: -9.3dB 60 | lame -b 128 /tmp/decoded.wav /tmp/lame.mp3 3.55s user 0.05s system 99% cpu 3.609 total 61 | ``` 62 | 63 | Shine, `318.0x` realtime: 64 | ``` 65 | shineenc (Liquidsoap version) 66 | WAVE PCM Data, stereo 44100Hz 16bit, duration: 00:05:18 67 | MPEG-I layer III, stereo Psychoacoustic Model: Shine 68 | Bitrate: 128 kbps De-emphasis: none Original 69 | Encoding "/tmp/bla.wav" to "/tmp/shine.mp3" 70 | Finished in 00:00:01 (318.0x realtime) 71 | ``` 72 | 73 | ### ⚠ The following are outdated tests ⚠ 74 | 75 | On a [Raspberry Pi](http://www.raspberrypi.org/) (`ARM`, `FPU`): 76 | 77 | Lame, `1.8x` realtime: 78 | ```bash 79 | pi@raspberrypi ~ $ lame bla.wav bla.mp3 80 | LAME 3.99.5 32bits (http://lame.sf.net) 81 | Using polyphase lowpass filter, transition band: 16538 Hz - 17071 Hz 82 | Encoding bla.wav to bla.mp3 83 | Encoding as 44.1 kHz j-stereo MPEG-1 Layer III (11x) 128 kbps qval=3 84 | Frame | CPU time/estim | REAL time/estim | play/CPU | ETA 85 | 12987/12987 (100%)| 3:06/ 3:06| 3:06/ 3:06| 1.8216x| 0:00 86 | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 87 | kbps LR MS % long switch short % 88 | 128.0 0.1 99.9 89.1 6.1 4.9 89 | Writing LAME Tag...done 90 | ReplayGain: -10.5dB 91 | ``` 92 | 93 | Shine, `3.6x` realtime: 94 | ```bash 95 | pi@raspberrypi ~ $ shineenc bla.wav bla.mp3 96 | shineenc (Liquidsoap version) 97 | WAVE PCM Data, stereo 44100Hz 16bit, duration: 00:05:39 98 | MPEG-I layer III, stereo Psychoacoustic Model: Shine 99 | Bitrate: 128 kbps De-emphasis: none Original 100 | Encoding "bla.wav" to "bla.mp3" 101 | Finished in 00:01:35 (3.6x realtime) 102 | ``` 103 | 104 | On a Google Nexus 5 (`ARM`, `FPU`): 105 | 106 | Shine, `14s`, `24.2x` realtime: 107 | ```bash 108 | u0_a65@hammerhead:/mnt/sdcard $ shineenc bla.wav bla.mp3 109 | shineenc (Liquidsoap version) 110 | WAVE PCM Data, stereo 44100Hz 16bit, duration: 00:05:39 111 | MPEG-I layer III, stereo Psychoacoustic Model: Shine 112 | Bitrate: 128 kbps De-emphasis: none Original 113 | Encoding "bla.wav" to "bla.mp3" 114 | Finished in 00:00:14 (24.2x realtime) 115 | ``` 116 | 117 | Limitations 118 | ----------- 119 | 120 | The code for the encoder has been written a long time ago (see below) and 121 | the only work done on this fork consists of reorganizing the code and making a 122 | proper shared API out of it. Thus, the encoder may not be exempt of bugs. 123 | 124 | Also, the encoding algorithm is rather simple. In particular, it does not 125 | have any Psychoacoustic Model. 126 | 127 | A bit of history 128 | ---------------- 129 | 130 | This code was dug out from the dusty crates of those times before internet 131 | and github. It apparently was created by Gabriel Bouvigne sometime around 132 | the end of the 20th century. The encoder was converted circa 2001 by Pete 133 | Everett to fixed-point arithmetic for the RISC OS. Last we know, Patrick 134 | Roberts had worked on the code to make it multi-platform and more library 135 | oriented. That was around 2006. 136 | 137 | You can consult `README.old` and the various source files for more 138 | informations on this code. 139 | -------------------------------------------------------------------------------- /README.old: -------------------------------------------------------------------------------- 1 | libShine-fxp Fixed-point MP3 Encoder. 2 | 3 | ---------From Original Readme---------- 4 | 5 | Shine (RISC OS fixed point port) 6 | 7 | This port of Gabriel Bouvigne's Shine has been converted to fixed point 8 | to reduce encoding time on Acorn/RISC OS computers without hardware 9 | floating point coprocessors. 10 | 11 | For use on other platforms, the RISC OS specifics in main.c should be 12 | undefined, and the assembler fractional multiply functions will need to 13 | be changed. Big endian support may also have to be re-instated. 14 | 15 | Pete Everett. 9/4/01 16 | 17 | email: peter@everett9981.freeserve.co.uk 18 | web: http://www.everett9981.freeserve.co.uk 19 | 20 | 21 | --------------------------------------------- 22 | 23 | 24 | Ported to GCC StrongARM Linux by Patrick Roberts for Lower Mars, LLC. This 25 | port will also work on X86, X86_64 and probably other platforms and CPUs, but 26 | the mult_noarch_gcc.h needs to be fixed as the math is bad. (I only need x86 to 27 | make testing easier... ARM code is 100% correct). 28 | 29 | 30 | Tested Compiler: 31 | 32 | GCC VERSION 3.3.6 33 | --target=arm-linux 34 | --with-cpu=iwmmxt 35 | --with-float=soft (no float in Shine anyway) 36 | 37 | Compiled with the dev-ezx toolchain from the dev-ezx directory. 38 | 39 | 40 | CHANGES from Peter Everett's version: 41 | 42 | - Removed global data from all but main.c 43 | - Created a DSO and static library from encoding functions 44 | - Ported assembly to gcc 3.6 StrongARM inline format 45 | - Changed file read/write functions so no direct file i/o 46 | is done by library functions (function pointers now) 47 | - All printf's in lib blocked if #ifdef DEBUG 48 | - Makefile for StrongARM/EZX and for generic platforms 49 | - Restored missing COPYING from original floating point Shine source 50 | - Moved RISC_OS-specific files to "unused" directory 51 | - Removed RISC_OS stuff from Main.c (shineenc), which is now more 52 | an example for library usage. 53 | 54 | What could be improved: 55 | 56 | - "noarch-gcc" defines are not correct math (just close...) 57 | - Vectorize code for WMMX-capable CPUs. 58 | - Optimized assembly (mult_XXX_YYY.h) files 59 | 60 | -------------------------------------------------------------------------------- /android/Binary.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir)/.. 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_ARM_MODE := arm 6 | 7 | LOCAL_CFLAGS := -I$(LOCAL_PATH)/src/lib 8 | 9 | LOCAL_MODULE := shineenc 10 | LOCAL_SRC_FILES := src/bin/main.c src/bin/wave.c \ 11 | src/lib/bitstream.c src/lib/huffman.c \ 12 | src/lib/l3bitstream.c src/lib/l3loop.c src/lib/l3mdct.c \ 13 | src/lib/l3subband.c src/lib/layer3.c src/lib/reservoir.c \ 14 | src/lib/tables.c 15 | 16 | include $(BUILD_EXECUTABLE) 17 | 18 | -------------------------------------------------------------------------------- /android/Library.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir)/.. 2 | 3 | include $(CLEAR_VARS) 4 | 5 | LOCAL_ARM_MODE := arm 6 | LOCAL_MODULE := shine 7 | LOCAL_SRC_FILES := src/lib/bitstream.c src/lib/huffman.c \ 8 | src/lib/l3bitstream.c src/lib/l3loop.c src/lib/l3mdct.c \ 9 | src/lib/l3subband.c src/lib/layer3.c src/lib/reservoir.c \ 10 | src/lib/tables.c 11 | LOCAL_LDLIBS := -lm 12 | 13 | include $(BUILD_SHARED_LIBRARY) 14 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | [ -d m4 ] || mkdir m4 4 | autoreconf -i 5 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([shine],[3.1.1],[toots@rastageeks.org]) 2 | AM_INIT_AUTOMAKE([subdir-objects]) 3 | LT_INIT 4 | AC_CONFIG_MACRO_DIR([m4]) 5 | AC_C_BIGENDIAN([CFLAGS="$CFLAGS -DSHINE_BIG_ENDIAN"]) 6 | AC_CHECK_HEADER([byteswap.h],[CFLAGS="$CFLAGS -DSHINE_HAVE_BSWAP_H"]) 7 | AC_OUTPUT([Makefile shine.pc]) 8 | -------------------------------------------------------------------------------- /js/.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | src/ 3 | Makefile 4 | .* 5 | -------------------------------------------------------------------------------- /js/.prettierignore: -------------------------------------------------------------------------------- 1 | .next/ 2 | dist/ 3 | stubs/ 4 | public/audio 5 | __ENV.js 6 | -------------------------------------------------------------------------------- /js/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": false, 3 | "quoteProps": "as-needed", 4 | "arrowParens": "avoid", 5 | "tabWidth": 2, 6 | "trailingComma": "es5", 7 | "semi": true, 8 | "jsxSingleQuote": true, 9 | "bracketSameLine": false, 10 | "printWidth": 120, 11 | "parser": "typescript" 12 | } 13 | -------------------------------------------------------------------------------- /js/Makefile: -------------------------------------------------------------------------------- 1 | # Emscriptem compilation 2 | 3 | EMCC:=emcc 4 | EXPORTED_FUNCTIONS:='["_malloc", "_free", "_shine_check_config", "_shine_js_init",\ 5 | "_shine_js_int16_len", "_shine_js_ptr_len", \ 6 | "_shine_samples_per_pass", "_shine_encode_buffer",\ 7 | "_shine_flush", "_shine_close"]' 8 | CFLAGS:=-O3 9 | LINKFLAGS:=-s EXPORTED_FUNCTIONS=$(EXPORTED_FUNCTIONS) -s SINGLE_FILE=1 -s EXPORTED_RUNTIME_METHODS=setValue,getValue --memory-init-file 0 $(CFLAGS) 10 | WEB_LINKFLAGS:=$(LINKFLAGS) -s ENVIRONMENT='web' -s EXPORT_NAME='createModule' -s USE_ES6_IMPORT_META=0 11 | 12 | C_FILES:=$(wildcard ../src/lib/*.c) src/wrapper.c 13 | HEADER_FILES:=$(wildcard ../src/lib/*.h) 14 | SOURCES:=$(C_FILES) $(HEADER_FILES) 15 | OBJECTS:=$(C_FILES:%.c=%.o) 16 | 17 | all: dist/libshine_node.js dist/libshine_browser.js 18 | 19 | src/post-node.js: src/libshine_class.js src/libshine_node_wrapper.js 20 | rm -f src/post-node.js 21 | cat src/libshine_class.js src/libshine_node_wrapper.js > src/post-node.js 22 | 23 | dist/libshine_node.js: $(SOURCES) $(OBJECTS) src/post-node.js 24 | $(EMCC) $(LINKFLAGS) --post-js src/post-node.js $(OBJECTS) -o dist/libshine_node.js 25 | 26 | dist/libshine_browser_stubs.js: $(SOURCES) $(OBJECTS) 27 | $(EMCC) $(WEB_LINKFLAGS) $(OBJECTS) -o dist/libshine_browser_stubs.mjs 28 | mv dist/libshine_browser_stubs.mjs dist/libshine_browser_stubs.js 29 | 30 | dist/libshine_browser.js: src/libshine_class.js src/libshine_browser_wrapper.js dist/libshine_browser_stubs.js 31 | cat src/libshine_class.js src/libshine_browser_wrapper.js > dist/libshine_browser.js 32 | 33 | %.o: %.c 34 | $(EMCC) $(CFLAGS) -I../src/lib -c $< -o $@ 35 | 36 | clean: 37 | rm -rf *.o ../src/lib/*.o dist/libshine*js 38 | -------------------------------------------------------------------------------- /js/README.md: -------------------------------------------------------------------------------- 1 | Shine encoder library for Javascript 2 | ==================================== 3 | 4 | This package contains a build of the [shine](https://github.com/toots/shine) fixed-point 5 | mp3 encoder compiled for Javascript and wasm using [emscripten-core/emscripten](https://github.com/emscripten-core/emscripten). 6 | 7 | Install 8 | ------- 9 | 10 | Using `npm`: 11 | 12 | ```shell 13 | npm install @toots/shine.js 14 | ``` 15 | 16 | Using `yarn`: 17 | 18 | ```shell 19 | yarn add @toots/shine.js 20 | ``` 21 | 22 | Using `pnpm`: 23 | 24 | ```shell 25 | pnpm install @toots/shine.js 26 | ``` 27 | 28 | In a HTML page: 29 | 30 | When using `webpack`, the package should point to the correct 31 | `libshine_browser.js` file automatically. 32 | 33 | When using directly as a script, you can load the `libshine_node.js` 34 | file as: 35 | 36 | ```html 37 | 38 | ``` 39 | 40 | See: [test/browser](https://github.com/toots/shine/tree/main/js/test/browser) for an example. 41 | 42 | How to use? 43 | ----------- 44 | 45 | The encoding API should be quite straight forward: 46 | 47 | ```js 48 | import { Shine, StereoModel } from "@toots/shine.js"; 49 | 50 | const exec = async () => { 51 | await Shine.initialized; 52 | 53 | shine = new Shine({ 54 | samplerate: 44100, 55 | bitrate: 128, 56 | channels: 2, 57 | stereoModel: StereoModel.STEREO 58 | }); 59 | 60 | // All the magic happens here 61 | while (..) { 62 | // data here is an array of channels. 63 | // Channels must have the same number of samples 64 | // and both be either Int16Array or Float32Array. 65 | encoded = shine.encode(data); 66 | ... 67 | } 68 | 69 | // Close and get remaining data. 70 | flushed = shine.close(); 71 | 72 | ... 73 | } 74 | 75 | exec(); 76 | ``` 77 | 78 | How fast is it? 79 | --------------- 80 | 81 | You can run the test suite located in `test/`. Encoding rate above `1X` means that 82 | the browser should be suitable for real-time encoding. 83 | 84 | Results, as of December 30, 2022: 85 | 86 | Chrome (`108.0.5359.124`): 87 | ``` 88 | Executing encoding test 89 | Got WAV file. 90 | Encoding.. 91 | Done encoding. 92 | File duration: 5.57 seconds 93 | Encoding time: 0.08 seconds 94 | Encoding rate: 67.96X 95 | 96 | Executing rounds test 97 | Encoding 50 buffers of 4096 samples 98 | Done encoding 99 | Total duration: 4.64 100 | Encoding time: 0.03 101 | Encoding rate: 160.00X 102 | ``` 103 | 104 | Firefox (`108.0.1`): 105 | ``` 106 | Executing encoding test 107 | Got WAV file. 108 | Encoding.. 109 | Done encoding. 110 | File duration: 5.57 seconds 111 | Encoding time: 0.06 seconds 112 | Encoding rate: 99.52X 113 | 114 | Executing rounds test 115 | Encoding 50 buffers of 4096 samples 116 | Done encoding 117 | Total duration: 4.64 118 | Encoding time: 0.03 119 | Encoding rate: 178.46X 120 | ``` 121 | 122 | Safari (`16.2`): 123 | ``` 124 | Executing encoding test 125 | Got WAV file. 126 | Encoding.. 127 | Done encoding. 128 | File duration: 5.57 seconds 129 | Encoding time: 0.12 seconds 130 | Encoding rate: 46.44X 131 | 132 | Executing rounds test 133 | Encoding 50 buffers of 4096 samples 134 | Done encoding 135 | Total duration: 4.64 136 | Encoding time: 0.02 137 | Encoding rate: 210.91X 138 | ``` 139 | 140 | NodeJS (`v19.3.0`): 141 | ``` 142 | Executing encoding test 143 | Got WAV file. 144 | Encoding.. 145 | Done encoding. 146 | File duration: 5.57 seconds 147 | Encoding time: 0.06 seconds 148 | Encoding rate: 94.45X 149 | 150 | Executing rounds test 151 | Encoding 50 buffers of 4096 samples 152 | Done encoding 153 | Total duration: 4.64 154 | Encoding time: 0.03 155 | Encoding rate: 178.46X 156 | ``` 157 | -------------------------------------------------------------------------------- /js/dist/libshine_browser.js: -------------------------------------------------------------------------------- 1 | // libshine function wrappers 2 | 3 | var StereoMode = { 4 | '0': 'STEREO', 5 | '1': 'JOINT_STEREO', 6 | '2': 'DUAL_CHANNEL', 7 | '3': 'MONO', 8 | STEREO: 0, 9 | JOINT_STEREO: 1, 10 | DUAL_CHANNEL: 2, 11 | MONO: 3 12 | }; 13 | 14 | var ShineModule; 15 | var int16Len; 16 | var ptrLen; 17 | 18 | function shineInit() { 19 | int16Len = ShineModule._shine_js_int16_len(); 20 | ptrLen = ShineModule._shine_js_ptr_len(); 21 | }; 22 | 23 | function Shine(args) { 24 | if (ShineModule._shine_check_config(args.samplerate, args.bitrate) < 0) 25 | throw "Invalid configuration"; 26 | 27 | var stereoMode; 28 | if (!args.stereoMode) { 29 | if (args.channels === 1) { 30 | stereoMode = Shine.MONO; 31 | } else { 32 | stereoMode = Shine.JOINT_STEREO; 33 | } 34 | } else { 35 | stereoMode = args.stereoMode; 36 | } 37 | 38 | this._handle = ShineModule._shine_js_init(args.channels, args.samplerate, stereoMode, args.bitrate); 39 | 40 | this._channels = args.channels; 41 | this._samples_per_pass = ShineModule._shine_samples_per_pass(this._handle); 42 | 43 | this._buffer = ShineModule._malloc(this._channels * ptrLen); 44 | this._pcm = new Array(this._channels); 45 | this._rem = new Array(this._channels); 46 | this._written = ShineModule._malloc(int16Len); 47 | 48 | var _tmp, chan; 49 | for (chan=0; chan= 0; 61 | }; 62 | 63 | Shine.prototype._encodePass = function (data) { 64 | if (!this._handle) 65 | throw "Closed"; 66 | 67 | var chan; 68 | for (chan=0;chan 1 ? 1 : (x < -1 ? -1 : x)); 90 | } 91 | 92 | function convertFloat32(buf) { 93 | var ret = new Array(buf.length); 94 | var samples = buf[0].length; 95 | var chan, i; 96 | 97 | for (chan=0;chan 0) { 134 | encoded = concat(Uint8Array, encoded, enc); 135 | } 136 | } 137 | } 138 | 139 | if (tmp[0].length < this._samples_per_pass) { 140 | this._rem = tmp; 141 | } else { 142 | for (chan=0; chan; 10 | static checkConfig(samplerate: number, bitrate: number): boolean; 11 | constructor(args: { 12 | samplerate: number; 13 | bitrate: number; 14 | channels: number; 15 | stereoMode?: StereoMode; 16 | }); 17 | encode(data: Data[]): Uint8Array; 18 | close(): Uint8Array; 19 | } 20 | -------------------------------------------------------------------------------- /js/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@toots/shine.js", 3 | "version": "1.0.1", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@toots/shine.js", 9 | "version": "1.0.1", 10 | "license": "LGPL-2.0-only" 11 | }, 12 | "stubs": { 13 | "version": "1.0.0", 14 | "extraneous": true, 15 | "license": "ISC" 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@toots/shine.js", 3 | "version": "1.0.3", 4 | "description": "Shine fixed-point mp3 encoder", 5 | "main": "dist/libshine_node.js", 6 | "browser": "dist/libshine_browser.js", 7 | "types": "libshine.d.ts", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/toots/shine.git" 11 | }, 12 | "keywords": [ 13 | "mp3", 14 | "encoder", 15 | "wasm", 16 | "fixed-point" 17 | ], 18 | "author": "Romain Beauxis ", 19 | "license": "LGPL-2.0-only", 20 | "bugs": { 21 | "url": "https://github.com/toots/shine/issues" 22 | }, 23 | "homepage": "https://github.com/toots/shine#readme" 24 | } 25 | -------------------------------------------------------------------------------- /js/src/libshine_browser_wrapper.js: -------------------------------------------------------------------------------- 1 | var createModule = require("./libshine_browser_stubs").default; 2 | 3 | Shine.initialized = (createModule()).then(function (Module) { 4 | ShineModule = Module; 5 | shineInit(); 6 | }); 7 | 8 | module.exports.Shine = Shine; 9 | 10 | module.exports.StereoMode = StereoMode; 11 | -------------------------------------------------------------------------------- /js/src/libshine_class.js: -------------------------------------------------------------------------------- 1 | // libshine function wrappers 2 | 3 | var StereoMode = { 4 | '0': 'STEREO', 5 | '1': 'JOINT_STEREO', 6 | '2': 'DUAL_CHANNEL', 7 | '3': 'MONO', 8 | STEREO: 0, 9 | JOINT_STEREO: 1, 10 | DUAL_CHANNEL: 2, 11 | MONO: 3 12 | }; 13 | 14 | var ShineModule; 15 | var int16Len; 16 | var ptrLen; 17 | 18 | function shineInit() { 19 | int16Len = ShineModule._shine_js_int16_len(); 20 | ptrLen = ShineModule._shine_js_ptr_len(); 21 | }; 22 | 23 | function Shine(args) { 24 | if (ShineModule._shine_check_config(args.samplerate, args.bitrate) < 0) 25 | throw "Invalid configuration"; 26 | 27 | var stereoMode; 28 | if (!args.stereoMode) { 29 | if (args.channels === 1) { 30 | stereoMode = Shine.MONO; 31 | } else { 32 | stereoMode = Shine.JOINT_STEREO; 33 | } 34 | } else { 35 | stereoMode = args.stereoMode; 36 | } 37 | 38 | this._handle = ShineModule._shine_js_init(args.channels, args.samplerate, stereoMode, args.bitrate); 39 | 40 | this._channels = args.channels; 41 | this._samples_per_pass = ShineModule._shine_samples_per_pass(this._handle); 42 | 43 | this._buffer = ShineModule._malloc(this._channels * ptrLen); 44 | this._pcm = new Array(this._channels); 45 | this._rem = new Array(this._channels); 46 | this._written = ShineModule._malloc(int16Len); 47 | 48 | var _tmp, chan; 49 | for (chan=0; chan= 0; 61 | }; 62 | 63 | Shine.prototype._encodePass = function (data) { 64 | if (!this._handle) 65 | throw "Closed"; 66 | 67 | var chan; 68 | for (chan=0;chan 1 ? 1 : (x < -1 ? -1 : x)); 90 | } 91 | 92 | function convertFloat32(buf) { 93 | var ret = new Array(buf.length); 94 | var samples = buf[0].length; 95 | var chan, i; 96 | 97 | for (chan=0;chan 0) { 134 | encoded = concat(Uint8Array, encoded, enc); 135 | } 136 | } 137 | } 138 | 139 | if (tmp[0].length < this._samples_per_pass) { 140 | this._rem = tmp; 141 | } else { 142 | for (chan=0; chan 4 | #include 5 | #include 6 | 7 | size_t shine_js_int16_len() { 8 | return sizeof(int16_t); 9 | } 10 | 11 | size_t shine_js_ptr_len() { 12 | return sizeof(void*); 13 | } 14 | 15 | shine_t shine_js_init(int channels, int samplerate, int mode, int bitr) { 16 | shine_config_t config; 17 | config.wave.channels = channels; 18 | config.wave.samplerate = samplerate; 19 | 20 | shine_set_config_mpeg_defaults(&config.mpeg); 21 | config.mpeg.mode = mode; 22 | config.mpeg.bitr = bitr; 23 | 24 | return shine_initialise(&config); 25 | } 26 | -------------------------------------------------------------------------------- /js/test/browser/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | python -m http.server 3 | -------------------------------------------------------------------------------- /js/test/browser/encode.js: -------------------------------------------------------------------------------- 1 | function runEncodeTest(log, callback) { 2 | log("Executing encoding test"); 3 | 4 | var samplerate = 44100; 5 | var channels = 2; 6 | var bitrate = 128; 7 | 8 | var shine = new Shine({ 9 | samplerate: samplerate, 10 | channels: channels, 11 | bitrate: bitrate, 12 | }); 13 | 14 | var started = new Date(); 15 | var duration = 0.0; 16 | var encoded = []; 17 | 18 | var xhr = new XMLHttpRequest(); 19 | xhr.open("GET", "encode.wav", true); 20 | xhr.responseType = "arraybuffer"; 21 | xhr.onload = function () { 22 | var samples = xhr.response.byteLength / (2 * channels); 23 | var data = new Int16Array(xhr.response); 24 | var buf = convertInterleavedBuffer(data, channels, samples); 25 | duration += parseFloat(samples) / samplerate; 26 | encoded.push(shine.encode(buf)); 27 | }; 28 | 29 | log("Got WAV file."); 30 | log("Encoding.."); 31 | xhr.addEventListener("load", function () { 32 | encoded.push(shine.close()); 33 | 34 | var ended = new Date(); 35 | var encodingTime = (ended.getTime() - started.getTime()) / 1000; 36 | log("Done encoding."); 37 | log("File duration: " + duration.toFixed(2) + " seconds"); 38 | log("Encoding time: " + encodingTime.toFixed(2) + " seconds"); 39 | log("Encoding rate: " + (duration / encodingTime).toFixed(2) + "X"); 40 | callback(new Blob(encoded)); 41 | }); 42 | 43 | xhr.send(); 44 | } 45 | 46 | function convertInterleavedBuffer(buf, channels, samples) { 47 | var chan, i; 48 | ret = new Array(channels); 49 | for (chan = 0; chan < channels; chan++) { 50 | ret[chan] = new Int16Array(samples); 51 | for (i = 0; i < samples; i++) { 52 | ret[chan][i] = buf[i * channels + chan]; 53 | } 54 | } 55 | return ret; 56 | } 57 | -------------------------------------------------------------------------------- /js/test/browser/encode.wav: -------------------------------------------------------------------------------- 1 | ../lib/encode.wav -------------------------------------------------------------------------------- /js/test/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 26 | Download encoded file 27 |
28 | -------------------------------------------------------------------------------- /js/test/browser/libshine_node.js: -------------------------------------------------------------------------------- 1 | ../../dist/libshine_node.js -------------------------------------------------------------------------------- /js/test/browser/rounds.js: -------------------------------------------------------------------------------- 1 | ../lib/rounds.js -------------------------------------------------------------------------------- /js/test/lib/encode.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toots/shine/ab5e3526b64af1a2eaa43aa6f441a7312e013519/js/test/lib/encode.wav -------------------------------------------------------------------------------- /js/test/lib/rounds.js: -------------------------------------------------------------------------------- 1 | var channels = 2; // test.wav is stereo 2 | var samplerate = 44100; // ditto 3 | 4 | var runRoundsTest = function (Shine, log) { 5 | log("Executing rounds test"); 6 | 7 | var nPasses = 50; 8 | var frameSize = 4096; 9 | var data = new Array(channels); 10 | var chan; 11 | for (chan = 0; chan < channels; chan++) data[chan] = new Int16Array(frameSize); 12 | 13 | log("Encoding " + nPasses + " buffers of " + frameSize + " samples"); 14 | var started = new Date(); 15 | 16 | var shine = new Shine({ 17 | samplerate: samplerate, 18 | bitrate: 128, 19 | channels: channels, 20 | }); 21 | 22 | var i; 23 | for (i = 0; i < nPasses; i++) shine.encode(data); 24 | shine.close(); 25 | 26 | var ended = new Date(); 27 | var duration = (parseFloat(nPasses * frameSize) / parseFloat(samplerate)).toFixed(2); 28 | var encodingTime = (ended.getTime() - started.getTime()) / 1000; 29 | log("Done encoding"); 30 | log("Total duration: " + duration); 31 | log("Encoding time: " + encodingTime.toFixed(2)); 32 | log("Encoding rate: " + (duration / encodingTime).toFixed(2) + "X"); 33 | }; 34 | 35 | if (typeof process === "object" && typeof require === "function") module.exports = runRoundsTest; 36 | -------------------------------------------------------------------------------- /js/test/nextjs/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /js/test/nextjs/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /js/test/nextjs/.prettierignore: -------------------------------------------------------------------------------- 1 | .next/ 2 | out/ 3 | public/audio 4 | __ENV.js 5 | -------------------------------------------------------------------------------- /js/test/nextjs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": false, 3 | "quoteProps": "as-needed", 4 | "arrowParens": "avoid", 5 | "tabWidth": 2, 6 | "trailingComma": "es5", 7 | "semi": false, 8 | "jsxSingleQuote": true, 9 | "bracketSameLine": false, 10 | "printWidth": 120, 11 | "parser": "typescript" 12 | } 13 | -------------------------------------------------------------------------------- /js/test/nextjs/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | ``` 12 | 13 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 14 | 15 | You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. 16 | 17 | [API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. 18 | 19 | The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /js/test/nextjs/lib/encode.ts: -------------------------------------------------------------------------------- 1 | import { Shine } from "@toots/shine.js" 2 | 3 | const convertInterleavedBuffer = (buf: Int16Array, channels: number, samples: number) => { 4 | const ret = new Array(channels) 5 | for (let chan = 0; chan < channels; chan++) { 6 | ret[chan] = new Int16Array(samples) 7 | for (let i = 0; i < samples; i++) { 8 | ret[chan][i] = buf[i * channels + chan] 9 | } 10 | } 11 | return ret 12 | } 13 | 14 | export const runEncodeTest = (log: (_: string) => void, callback: (_: Blob) => void) => { 15 | log("Executing encoding test") 16 | 17 | const samplerate = 44100 18 | const channels = 2 19 | const bitrate = 128 20 | //const stereoMode = StereoMode.STEREO 21 | 22 | const shine = new Shine({ 23 | samplerate: samplerate, 24 | channels: channels, 25 | bitrate: bitrate, 26 | // stereoMode: stereoMode, 27 | }) 28 | 29 | const started = new Date() 30 | let duration = 0.0 31 | const encoded: Uint8Array[] = [] 32 | 33 | const xhr = new XMLHttpRequest() 34 | xhr.open("GET", "encode.wav", true) 35 | xhr.responseType = "arraybuffer" 36 | xhr.onload = () => { 37 | const samples = xhr.response.byteLength / (2 * channels) 38 | const data = new Int16Array(xhr.response) 39 | const buf = convertInterleavedBuffer(data, channels, samples) 40 | duration += samples / samplerate 41 | encoded.push(shine.encode(buf)) 42 | } 43 | 44 | log("Got WAV file.") 45 | log("Encoding..") 46 | xhr.addEventListener("load", () => { 47 | encoded.push(shine.close()) 48 | 49 | const ended = new Date() 50 | const encodingTime = (ended.getTime() - started.getTime()) / 1000 51 | log("Done encoding.") 52 | log("File duration: " + duration.toFixed(2) + " seconds") 53 | log("Encoding time: " + encodingTime.toFixed(2) + " seconds") 54 | log("Encoding rate: " + (duration / encodingTime).toFixed(2) + "X") 55 | callback(new Blob(encoded)) 56 | }) 57 | 58 | xhr.send() 59 | } 60 | -------------------------------------------------------------------------------- /js/test/nextjs/lib/encode.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toots/shine/ab5e3526b64af1a2eaa43aa6f441a7312e013519/js/test/nextjs/lib/encode.wav -------------------------------------------------------------------------------- /js/test/nextjs/lib/rounds.ts: -------------------------------------------------------------------------------- 1 | import { Shine, StereoMode } from "@toots/shine.js" 2 | 3 | const channels = 2 // test.wav is stereo 4 | const samplerate = 44100 // ditto 5 | 6 | export const runRoundsTest = (log: (_: string) => void) => { 7 | log("Executing rounds test") 8 | 9 | const nPasses = 50 10 | const frameSize = 4096 11 | const data = new Array(channels) 12 | for (let chan = 0; chan < channels; chan++) data[chan] = new Int16Array(frameSize) 13 | 14 | log("Encoding " + nPasses + " buffers of " + frameSize + " samples") 15 | const started = new Date() 16 | 17 | const shine = new Shine({ 18 | samplerate: samplerate, 19 | bitrate: 128, 20 | channels: channels, 21 | stereoMode: StereoMode.STEREO, 22 | }) 23 | 24 | for (let i = 0; i < nPasses; i++) shine.encode(data) 25 | shine.close() 26 | 27 | const ended = new Date() 28 | const duration = (nPasses * frameSize) / samplerate 29 | const encodingTime = (ended.getTime() - started.getTime()) / 1000 30 | log("Done encoding") 31 | log("Total duration: " + duration.toFixed(2)) 32 | log("Encoding time: " + encodingTime.toFixed(2)) 33 | log("Encoding rate: " + (duration / encodingTime).toFixed(2) + "X") 34 | } 35 | -------------------------------------------------------------------------------- /js/test/nextjs/next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = { 3 | reactStrictMode: true, 4 | } 5 | 6 | module.exports = nextConfig 7 | -------------------------------------------------------------------------------- /js/test/nextjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shine-nextjs-test-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "lint": "next lint --fix", 8 | "build": "next build && next export && touch out/.nojekyll", 9 | "format": "prettier '**/*.{ts,tsx,js,jsx}' --write", 10 | "typecheck": "tsc --noEmit" 11 | }, 12 | "dependencies": { 13 | "@next/font": "13.1.1", 14 | "@toots/shine.js": "file:../..", 15 | "@types/node": "18.11.18", 16 | "@types/react": "18.0.26", 17 | "@types/react-dom": "18.0.10", 18 | "eslint": "8.31.0", 19 | "eslint-config-next": "13.1.1", 20 | "next": "13.1.1", 21 | "react": "18.2.0", 22 | "react-dom": "18.2.0", 23 | "typescript": "4.9.4" 24 | }, 25 | "devDependencies": { 26 | "prettier": "^2.8.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /js/test/nextjs/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import { Fragment, useEffect, useState, useCallback } from "react" 2 | import { runEncodeTest } from "@shine/lib/encode" 3 | import { runRoundsTest } from "@shine/lib/rounds" 4 | 5 | const logEntries: string[] = [] 6 | let encoderStarted = false 7 | 8 | export default function Home() { 9 | const [logs, setLogs] = useState(logEntries) 10 | const [encodedBlobUrl, setEncodedBlobUrl] = useState() 11 | 12 | const log = useCallback( 13 | (entry: string) => { 14 | logEntries.push(entry) 15 | setLogs(logEntries) 16 | }, 17 | [setLogs] 18 | ) 19 | 20 | useEffect(() => { 21 | if (encoderStarted) return 22 | 23 | runEncodeTest(log, blob => { 24 | if (!encodedBlobUrl) setEncodedBlobUrl(URL.createObjectURL(blob)) 25 | 26 | log("") 27 | runRoundsTest(log) 28 | }) 29 | 30 | encoderStarted = true 31 | }, [log, encodedBlobUrl, setEncodedBlobUrl]) 32 | 33 | return ( 34 | <> 35 | {encodedBlobUrl && ( 36 | 37 | Download encoded file 38 | 39 | )} 40 |
41 | {logs.map(entry => ( 42 | 43 | {entry} 44 |
45 |
46 | ))} 47 |
48 | 49 | ) 50 | } 51 | -------------------------------------------------------------------------------- /js/test/nextjs/public/encode.wav: -------------------------------------------------------------------------------- 1 | ../lib/encode.wav -------------------------------------------------------------------------------- /js/test/nextjs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "strict": true, 8 | "forceConsistentCasingInFileNames": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "module": "esnext", 12 | "moduleResolution": "node", 13 | "resolveJsonModule": true, 14 | "isolatedModules": true, 15 | "jsx": "preserve", 16 | "incremental": true, 17 | "paths": { 18 | "@shine/*": ["./*"] 19 | } 20 | }, 21 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], 22 | "exclude": ["node_modules"] 23 | } 24 | -------------------------------------------------------------------------------- /js/test/node/encode.ts: -------------------------------------------------------------------------------- 1 | import { Shine } from "@toots/shine.js"; 2 | import { Reader } from "wav"; 3 | import fs from "fs"; 4 | 5 | const convertInterleavedBuffer = (buf, channels, samples) => { 6 | const ret = new Array(channels); 7 | for (let chan = 0; chan < channels; chan++) { 8 | ret[chan] = new Int16Array(samples); 9 | for (let i = 0; i < samples; i++) { 10 | ret[chan][i] = buf.readInt16LE(2 * (i * channels + chan)); 11 | } 12 | } 13 | 14 | return ret; 15 | }; 16 | 17 | const exec = async () => { 18 | await Shine.initialized; 19 | 20 | console.log(""); 21 | console.log("Executing encoding test"); 22 | 23 | const bitrate = 128; 24 | const str = fs.createReadStream("../lib/encode.wav"); 25 | const fd = fs.openSync("./encode.mp3", "w"); 26 | const reader = new Reader(); 27 | 28 | str.pipe(reader); 29 | 30 | const write = encoded => { 31 | if (encoded.length <= 0) return; 32 | 33 | const buf = Buffer.from(encoded); 34 | fs.writeSync(fd, buf, 0, buf.length); 35 | }; 36 | 37 | reader.on("format", format => { 38 | console.log("Got WAV file."); 39 | 40 | const shine = new Shine({ 41 | bitrate: bitrate, 42 | samplerate: format.sampleRate, 43 | channels: format.channels, 44 | }); 45 | 46 | console.log("Encoding.."); 47 | const started = new Date(); 48 | let duration = 0.0; 49 | const samplerate = format.sampleRate; 50 | 51 | reader.on("data", buf => { 52 | const samples = buf.length / (2 * format.channels); 53 | 54 | duration += samples / samplerate; 55 | 56 | write(shine.encode(convertInterleavedBuffer(buf, format.channels, samples))); 57 | }); 58 | 59 | reader.on("end", () => { 60 | write(shine.close()); 61 | 62 | const ended = new Date(); 63 | const encodingTime = (ended.getTime() - started.getTime()) / 1000; 64 | console.log("Done encoding."); 65 | console.log(`File duration: ${duration.toFixed(2)} seconds`); 66 | console.log(`Encoding time: ${encodingTime.toFixed(2)} seconds`); 67 | console.log(`Encoding rate: ${(duration / encodingTime).toFixed(2)}X`); 68 | process.exit(0); 69 | }); 70 | }); 71 | }; 72 | 73 | exec(); 74 | -------------------------------------------------------------------------------- /js/test/node/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shine-js-test", 3 | "version": "0.0.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "shine-js-test", 9 | "version": "0.0.1", 10 | "dependencies": { 11 | "@toots/shine.js": "file:../..", 12 | "@types/node": "^18.11.18", 13 | "ts-node": "^10.9.1", 14 | "typescript": "^4.9.4", 15 | "wav": "^1.0.2" 16 | } 17 | }, 18 | "../..": { 19 | "name": "@toots/shine.js", 20 | "version": "1.0.1", 21 | "license": "LGPL-2.0-only" 22 | }, 23 | "node_modules/@cspotcode/source-map-support": { 24 | "version": "0.8.1", 25 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 26 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 27 | "dependencies": { 28 | "@jridgewell/trace-mapping": "0.3.9" 29 | }, 30 | "engines": { 31 | "node": ">=12" 32 | } 33 | }, 34 | "node_modules/@jridgewell/resolve-uri": { 35 | "version": "3.1.0", 36 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 37 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 38 | "engines": { 39 | "node": ">=6.0.0" 40 | } 41 | }, 42 | "node_modules/@jridgewell/sourcemap-codec": { 43 | "version": "1.4.14", 44 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 45 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" 46 | }, 47 | "node_modules/@jridgewell/trace-mapping": { 48 | "version": "0.3.9", 49 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 50 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 51 | "dependencies": { 52 | "@jridgewell/resolve-uri": "^3.0.3", 53 | "@jridgewell/sourcemap-codec": "^1.4.10" 54 | } 55 | }, 56 | "node_modules/@toots/shine.js": { 57 | "resolved": "../..", 58 | "link": true 59 | }, 60 | "node_modules/@tsconfig/node10": { 61 | "version": "1.0.9", 62 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 63 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" 64 | }, 65 | "node_modules/@tsconfig/node12": { 66 | "version": "1.0.11", 67 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 68 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" 69 | }, 70 | "node_modules/@tsconfig/node14": { 71 | "version": "1.0.3", 72 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 73 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" 74 | }, 75 | "node_modules/@tsconfig/node16": { 76 | "version": "1.0.3", 77 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 78 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" 79 | }, 80 | "node_modules/@types/node": { 81 | "version": "18.11.18", 82 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", 83 | "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" 84 | }, 85 | "node_modules/acorn": { 86 | "version": "8.8.1", 87 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 88 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", 89 | "bin": { 90 | "acorn": "bin/acorn" 91 | }, 92 | "engines": { 93 | "node": ">=0.4.0" 94 | } 95 | }, 96 | "node_modules/acorn-walk": { 97 | "version": "8.2.0", 98 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 99 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", 100 | "engines": { 101 | "node": ">=0.4.0" 102 | } 103 | }, 104 | "node_modules/arg": { 105 | "version": "4.1.3", 106 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 107 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" 108 | }, 109 | "node_modules/buffer-alloc": { 110 | "version": "1.2.0", 111 | "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", 112 | "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", 113 | "dependencies": { 114 | "buffer-alloc-unsafe": "^1.1.0", 115 | "buffer-fill": "^1.0.0" 116 | } 117 | }, 118 | "node_modules/buffer-alloc-unsafe": { 119 | "version": "1.1.0", 120 | "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", 121 | "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" 122 | }, 123 | "node_modules/buffer-fill": { 124 | "version": "1.0.0", 125 | "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", 126 | "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" 127 | }, 128 | "node_modules/buffer-from": { 129 | "version": "1.1.1", 130 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 131 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 132 | }, 133 | "node_modules/core-util-is": { 134 | "version": "1.0.2", 135 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 136 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 137 | }, 138 | "node_modules/create-require": { 139 | "version": "1.1.1", 140 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 141 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" 142 | }, 143 | "node_modules/debug": { 144 | "version": "2.6.9", 145 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 146 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 147 | "dependencies": { 148 | "ms": "2.0.0" 149 | } 150 | }, 151 | "node_modules/diff": { 152 | "version": "4.0.2", 153 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 154 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", 155 | "engines": { 156 | "node": ">=0.3.1" 157 | } 158 | }, 159 | "node_modules/inherits": { 160 | "version": "2.0.3", 161 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 162 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 163 | }, 164 | "node_modules/isarray": { 165 | "version": "0.0.1", 166 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 167 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 168 | }, 169 | "node_modules/make-error": { 170 | "version": "1.3.6", 171 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 172 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" 173 | }, 174 | "node_modules/ms": { 175 | "version": "2.0.0", 176 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 177 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 178 | }, 179 | "node_modules/readable-stream": { 180 | "version": "1.1.14", 181 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 182 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 183 | "dependencies": { 184 | "core-util-is": "~1.0.0", 185 | "inherits": "~2.0.1", 186 | "isarray": "0.0.1", 187 | "string_decoder": "~0.10.x" 188 | } 189 | }, 190 | "node_modules/stream-parser": { 191 | "version": "0.3.1", 192 | "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", 193 | "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", 194 | "dependencies": { 195 | "debug": "2" 196 | } 197 | }, 198 | "node_modules/string_decoder": { 199 | "version": "0.10.31", 200 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 201 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 202 | }, 203 | "node_modules/ts-node": { 204 | "version": "10.9.1", 205 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 206 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 207 | "dependencies": { 208 | "@cspotcode/source-map-support": "^0.8.0", 209 | "@tsconfig/node10": "^1.0.7", 210 | "@tsconfig/node12": "^1.0.7", 211 | "@tsconfig/node14": "^1.0.0", 212 | "@tsconfig/node16": "^1.0.2", 213 | "acorn": "^8.4.1", 214 | "acorn-walk": "^8.1.1", 215 | "arg": "^4.1.0", 216 | "create-require": "^1.1.0", 217 | "diff": "^4.0.1", 218 | "make-error": "^1.1.1", 219 | "v8-compile-cache-lib": "^3.0.1", 220 | "yn": "3.1.1" 221 | }, 222 | "bin": { 223 | "ts-node": "dist/bin.js", 224 | "ts-node-cwd": "dist/bin-cwd.js", 225 | "ts-node-esm": "dist/bin-esm.js", 226 | "ts-node-script": "dist/bin-script.js", 227 | "ts-node-transpile-only": "dist/bin-transpile.js", 228 | "ts-script": "dist/bin-script-deprecated.js" 229 | }, 230 | "peerDependencies": { 231 | "@swc/core": ">=1.2.50", 232 | "@swc/wasm": ">=1.2.50", 233 | "@types/node": "*", 234 | "typescript": ">=2.7" 235 | }, 236 | "peerDependenciesMeta": { 237 | "@swc/core": { 238 | "optional": true 239 | }, 240 | "@swc/wasm": { 241 | "optional": true 242 | } 243 | } 244 | }, 245 | "node_modules/typescript": { 246 | "version": "4.9.4", 247 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", 248 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==", 249 | "bin": { 250 | "tsc": "bin/tsc", 251 | "tsserver": "bin/tsserver" 252 | }, 253 | "engines": { 254 | "node": ">=4.2.0" 255 | } 256 | }, 257 | "node_modules/v8-compile-cache-lib": { 258 | "version": "3.0.1", 259 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 260 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" 261 | }, 262 | "node_modules/wav": { 263 | "version": "1.0.2", 264 | "resolved": "https://registry.npmjs.org/wav/-/wav-1.0.2.tgz", 265 | "integrity": "sha512-viHtz3cDd/Tcr/HbNqzQCofKdF6kWUymH9LGDdskfWFoIy/HJ+RTihgjEcHfnsy1PO4e9B+y4HwgTwMrByquhg==", 266 | "dependencies": { 267 | "buffer-alloc": "^1.1.0", 268 | "buffer-from": "^1.0.0", 269 | "debug": "^2.2.0", 270 | "readable-stream": "^1.1.14", 271 | "stream-parser": "^0.3.1" 272 | } 273 | }, 274 | "node_modules/yn": { 275 | "version": "3.1.1", 276 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 277 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", 278 | "engines": { 279 | "node": ">=6" 280 | } 281 | } 282 | }, 283 | "dependencies": { 284 | "@cspotcode/source-map-support": { 285 | "version": "0.8.1", 286 | "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", 287 | "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", 288 | "requires": { 289 | "@jridgewell/trace-mapping": "0.3.9" 290 | } 291 | }, 292 | "@jridgewell/resolve-uri": { 293 | "version": "3.1.0", 294 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 295 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" 296 | }, 297 | "@jridgewell/sourcemap-codec": { 298 | "version": "1.4.14", 299 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 300 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" 301 | }, 302 | "@jridgewell/trace-mapping": { 303 | "version": "0.3.9", 304 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", 305 | "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", 306 | "requires": { 307 | "@jridgewell/resolve-uri": "^3.0.3", 308 | "@jridgewell/sourcemap-codec": "^1.4.10" 309 | } 310 | }, 311 | "@toots/shine.js": { 312 | "version": "file:../.." 313 | }, 314 | "@tsconfig/node10": { 315 | "version": "1.0.9", 316 | "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", 317 | "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==" 318 | }, 319 | "@tsconfig/node12": { 320 | "version": "1.0.11", 321 | "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", 322 | "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" 323 | }, 324 | "@tsconfig/node14": { 325 | "version": "1.0.3", 326 | "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", 327 | "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" 328 | }, 329 | "@tsconfig/node16": { 330 | "version": "1.0.3", 331 | "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", 332 | "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==" 333 | }, 334 | "@types/node": { 335 | "version": "18.11.18", 336 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", 337 | "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" 338 | }, 339 | "acorn": { 340 | "version": "8.8.1", 341 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", 342 | "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==" 343 | }, 344 | "acorn-walk": { 345 | "version": "8.2.0", 346 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", 347 | "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" 348 | }, 349 | "arg": { 350 | "version": "4.1.3", 351 | "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", 352 | "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" 353 | }, 354 | "buffer-alloc": { 355 | "version": "1.2.0", 356 | "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", 357 | "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", 358 | "requires": { 359 | "buffer-alloc-unsafe": "^1.1.0", 360 | "buffer-fill": "^1.0.0" 361 | } 362 | }, 363 | "buffer-alloc-unsafe": { 364 | "version": "1.1.0", 365 | "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", 366 | "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==" 367 | }, 368 | "buffer-fill": { 369 | "version": "1.0.0", 370 | "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", 371 | "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=" 372 | }, 373 | "buffer-from": { 374 | "version": "1.1.1", 375 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 376 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" 377 | }, 378 | "core-util-is": { 379 | "version": "1.0.2", 380 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 381 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 382 | }, 383 | "create-require": { 384 | "version": "1.1.1", 385 | "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", 386 | "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" 387 | }, 388 | "debug": { 389 | "version": "2.6.9", 390 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 391 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 392 | "requires": { 393 | "ms": "2.0.0" 394 | } 395 | }, 396 | "diff": { 397 | "version": "4.0.2", 398 | "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", 399 | "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==" 400 | }, 401 | "inherits": { 402 | "version": "2.0.3", 403 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 404 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 405 | }, 406 | "isarray": { 407 | "version": "0.0.1", 408 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", 409 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" 410 | }, 411 | "make-error": { 412 | "version": "1.3.6", 413 | "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", 414 | "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" 415 | }, 416 | "ms": { 417 | "version": "2.0.0", 418 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 419 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 420 | }, 421 | "readable-stream": { 422 | "version": "1.1.14", 423 | "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", 424 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", 425 | "requires": { 426 | "core-util-is": "~1.0.0", 427 | "inherits": "~2.0.1", 428 | "isarray": "0.0.1", 429 | "string_decoder": "~0.10.x" 430 | } 431 | }, 432 | "stream-parser": { 433 | "version": "0.3.1", 434 | "resolved": "https://registry.npmjs.org/stream-parser/-/stream-parser-0.3.1.tgz", 435 | "integrity": "sha1-FhhUhpRCACGhGC/wrxkRwSl2F3M=", 436 | "requires": { 437 | "debug": "2" 438 | } 439 | }, 440 | "string_decoder": { 441 | "version": "0.10.31", 442 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", 443 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" 444 | }, 445 | "ts-node": { 446 | "version": "10.9.1", 447 | "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", 448 | "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", 449 | "requires": { 450 | "@cspotcode/source-map-support": "^0.8.0", 451 | "@tsconfig/node10": "^1.0.7", 452 | "@tsconfig/node12": "^1.0.7", 453 | "@tsconfig/node14": "^1.0.0", 454 | "@tsconfig/node16": "^1.0.2", 455 | "acorn": "^8.4.1", 456 | "acorn-walk": "^8.1.1", 457 | "arg": "^4.1.0", 458 | "create-require": "^1.1.0", 459 | "diff": "^4.0.1", 460 | "make-error": "^1.1.1", 461 | "v8-compile-cache-lib": "^3.0.1", 462 | "yn": "3.1.1" 463 | } 464 | }, 465 | "typescript": { 466 | "version": "4.9.4", 467 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.4.tgz", 468 | "integrity": "sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==" 469 | }, 470 | "v8-compile-cache-lib": { 471 | "version": "3.0.1", 472 | "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", 473 | "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" 474 | }, 475 | "wav": { 476 | "version": "1.0.2", 477 | "resolved": "https://registry.npmjs.org/wav/-/wav-1.0.2.tgz", 478 | "integrity": "sha512-viHtz3cDd/Tcr/HbNqzQCofKdF6kWUymH9LGDdskfWFoIy/HJ+RTihgjEcHfnsy1PO4e9B+y4HwgTwMrByquhg==", 479 | "requires": { 480 | "buffer-alloc": "^1.1.0", 481 | "buffer-from": "^1.0.0", 482 | "debug": "^2.2.0", 483 | "readable-stream": "^1.1.14", 484 | "stream-parser": "^0.3.1" 485 | } 486 | }, 487 | "yn": { 488 | "version": "3.1.1", 489 | "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", 490 | "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==" 491 | } 492 | } 493 | } 494 | -------------------------------------------------------------------------------- /js/test/node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shine-js-test", 3 | "description": "Test encoder for libshine.js", 4 | "version": "0.0.1", 5 | "author": "Romain Beauxis =12'} 24 | dependencies: 25 | '@jridgewell/trace-mapping': 0.3.9 26 | dev: false 27 | 28 | /@jridgewell/resolve-uri/3.1.0: 29 | resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} 30 | engines: {node: '>=6.0.0'} 31 | dev: false 32 | 33 | /@jridgewell/sourcemap-codec/1.4.14: 34 | resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} 35 | dev: false 36 | 37 | /@jridgewell/trace-mapping/0.3.9: 38 | resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} 39 | dependencies: 40 | '@jridgewell/resolve-uri': 3.1.0 41 | '@jridgewell/sourcemap-codec': 1.4.14 42 | dev: false 43 | 44 | /@tsconfig/node10/1.0.9: 45 | resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} 46 | dev: false 47 | 48 | /@tsconfig/node12/1.0.11: 49 | resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} 50 | dev: false 51 | 52 | /@tsconfig/node14/1.0.3: 53 | resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} 54 | dev: false 55 | 56 | /@tsconfig/node16/1.0.3: 57 | resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==} 58 | dev: false 59 | 60 | /@types/node/18.11.18: 61 | resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} 62 | dev: false 63 | 64 | /@types/wav/1.0.1: 65 | resolution: {integrity: sha512-AKJeM5mqO1pdR2/HaTUQzSCm12No36KUM1larivXUmsLx+4JmMuC2Tv0kCdZzTx66h7IH2Xr92DGc9NQsXxa9Q==} 66 | dependencies: 67 | '@types/node': 18.11.18 68 | dev: false 69 | 70 | /acorn-walk/8.2.0: 71 | resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} 72 | engines: {node: '>=0.4.0'} 73 | dev: false 74 | 75 | /acorn/8.8.1: 76 | resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} 77 | engines: {node: '>=0.4.0'} 78 | hasBin: true 79 | dev: false 80 | 81 | /arg/4.1.3: 82 | resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} 83 | dev: false 84 | 85 | /buffer-alloc-unsafe/1.1.0: 86 | resolution: {integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==} 87 | dev: false 88 | 89 | /buffer-alloc/1.2.0: 90 | resolution: {integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==} 91 | dependencies: 92 | buffer-alloc-unsafe: 1.1.0 93 | buffer-fill: 1.0.0 94 | dev: false 95 | 96 | /buffer-fill/1.0.0: 97 | resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} 98 | dev: false 99 | 100 | /buffer-from/1.1.2: 101 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 102 | dev: false 103 | 104 | /core-util-is/1.0.3: 105 | resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} 106 | dev: false 107 | 108 | /create-require/1.1.1: 109 | resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} 110 | dev: false 111 | 112 | /debug/2.6.9: 113 | resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} 114 | peerDependencies: 115 | supports-color: '*' 116 | peerDependenciesMeta: 117 | supports-color: 118 | optional: true 119 | dependencies: 120 | ms: 2.0.0 121 | dev: false 122 | 123 | /diff/4.0.2: 124 | resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} 125 | engines: {node: '>=0.3.1'} 126 | dev: false 127 | 128 | /inherits/2.0.4: 129 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 130 | dev: false 131 | 132 | /isarray/0.0.1: 133 | resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} 134 | dev: false 135 | 136 | /make-error/1.3.6: 137 | resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} 138 | dev: false 139 | 140 | /ms/2.0.0: 141 | resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} 142 | dev: false 143 | 144 | /readable-stream/1.1.14: 145 | resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} 146 | dependencies: 147 | core-util-is: 1.0.3 148 | inherits: 2.0.4 149 | isarray: 0.0.1 150 | string_decoder: 0.10.31 151 | dev: false 152 | 153 | /stream-parser/0.3.1: 154 | resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} 155 | dependencies: 156 | debug: 2.6.9 157 | transitivePeerDependencies: 158 | - supports-color 159 | dev: false 160 | 161 | /string_decoder/0.10.31: 162 | resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} 163 | dev: false 164 | 165 | /ts-node/10.9.1_awa2wsr5thmg3i7jqycphctjfq: 166 | resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} 167 | hasBin: true 168 | peerDependencies: 169 | '@swc/core': '>=1.2.50' 170 | '@swc/wasm': '>=1.2.50' 171 | '@types/node': '*' 172 | typescript: '>=2.7' 173 | peerDependenciesMeta: 174 | '@swc/core': 175 | optional: true 176 | '@swc/wasm': 177 | optional: true 178 | dependencies: 179 | '@cspotcode/source-map-support': 0.8.1 180 | '@tsconfig/node10': 1.0.9 181 | '@tsconfig/node12': 1.0.11 182 | '@tsconfig/node14': 1.0.3 183 | '@tsconfig/node16': 1.0.3 184 | '@types/node': 18.11.18 185 | acorn: 8.8.1 186 | acorn-walk: 8.2.0 187 | arg: 4.1.3 188 | create-require: 1.1.1 189 | diff: 4.0.2 190 | make-error: 1.3.6 191 | typescript: 4.9.4 192 | v8-compile-cache-lib: 3.0.1 193 | yn: 3.1.1 194 | dev: false 195 | 196 | /typescript/4.9.4: 197 | resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} 198 | engines: {node: '>=4.2.0'} 199 | hasBin: true 200 | dev: false 201 | 202 | /v8-compile-cache-lib/3.0.1: 203 | resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} 204 | dev: false 205 | 206 | /wav/1.0.2: 207 | resolution: {integrity: sha512-viHtz3cDd/Tcr/HbNqzQCofKdF6kWUymH9LGDdskfWFoIy/HJ+RTihgjEcHfnsy1PO4e9B+y4HwgTwMrByquhg==} 208 | dependencies: 209 | buffer-alloc: 1.2.0 210 | buffer-from: 1.1.2 211 | debug: 2.6.9 212 | readable-stream: 1.1.14 213 | stream-parser: 0.3.1 214 | transitivePeerDependencies: 215 | - supports-color 216 | dev: false 217 | 218 | /yn/3.1.1: 219 | resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} 220 | engines: {node: '>=6'} 221 | dev: false 222 | 223 | file:../..: 224 | resolution: {directory: ../.., type: directory} 225 | name: '@toots/shine.js' 226 | version: 1.0.3 227 | dev: false 228 | -------------------------------------------------------------------------------- /js/test/node/rounds.ts: -------------------------------------------------------------------------------- 1 | import { Shine } from "@toots/shine.js"; 2 | import runRoundsTest from "../lib/rounds"; 3 | 4 | const exec = async () => { 5 | await Shine.initialized; 6 | 7 | console.log(""); 8 | runRoundsTest(Shine, s => console.log(s)); 9 | }; 10 | 11 | exec(); 12 | -------------------------------------------------------------------------------- /js/test/node/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["**/*.ts"], 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "skipLibCheck": true, 6 | "esModuleInterop": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /libshine.sym: -------------------------------------------------------------------------------- 1 | shine_close 2 | shine_encode_buffer 3 | shine_encode_buffer_interleaved 4 | shine_find_bitrate_index 5 | shine_find_samplerate_index 6 | shine_mpeg_version 7 | shine_check_config 8 | shine_flush 9 | shine_initialise 10 | shine_set_config_mpeg_defaults 11 | shine_samples_per_pass 12 | -------------------------------------------------------------------------------- /shine.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=${prefix} 3 | includedir=${prefix}/include 4 | libdir=${exec_prefix}/lib 5 | 6 | Name: shine 7 | Description: Fixed-point mp3 encoding library. 8 | Version: @VERSION@ 9 | Cflags: -I${includedir} 10 | Libs: -L${libdir} -lm -lshine 11 | -------------------------------------------------------------------------------- /src/bin/main.c: -------------------------------------------------------------------------------- 1 | /* main.c 2 | * Command line interface. 3 | * 4 | * This fixed point version of shine is based on Gabriel Bouvigne's original 5 | * source, version 0.1.2 6 | * It was converted for use on Acorn computers running RISC OS and will require 7 | * the assembler multiply file to be replaced for other platforms. 8 | * 09/02/01 P.Everett 9 | * 10 | * Converted to a no-globals library-based system primarily for ARM-LINUX-GCC 11 | * but also works on x86 and x86_64 with the Makefile-generic, however 12 | * quality is worse right now on non-ARM as the noarch file uses bad math. 13 | * Jan 2, 2006 P.Roberts 14 | * 15 | */ 16 | 17 | /* Global headers. */ 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | /* Required headers from libshine. */ 24 | #include "layer3.h" 25 | 26 | /* Local header */ 27 | #include "main.h" 28 | #include "wave.h" 29 | 30 | /* Some global vars. */ 31 | char *infname, *outfname; 32 | FILE *infile, *outfile; 33 | int quiet = 0; 34 | int _verbose = 0; 35 | int stereo = STEREO; 36 | int force_mono = 0; 37 | 38 | int verbose() { return _verbose; } 39 | 40 | /* Write out the MP3 file */ 41 | int write_mp3(long bytes, void *buffer, void *config) { 42 | return fwrite(buffer, sizeof(unsigned char), bytes, outfile) / 43 | sizeof(unsigned char); 44 | } 45 | 46 | /* Output error message and exit */ 47 | void error(char *s) { 48 | fprintf(stderr, "Error: %s\n", s); 49 | exit(1); 50 | } 51 | 52 | static void print_name() { printf("shineenc (Liquidsoap version)\n"); } 53 | 54 | static void print_usage() { 55 | printf("Usage: shineenc [options] \n\n"); 56 | printf("Use \"-\" for standard input or output.\n\n"); 57 | printf("Options:\n"); 58 | printf(" -h this help message\n"); 59 | printf(" -b set the bitrate [8-320], default 128kbit\n"); 60 | printf(" -m force encoder to operate in mono\n"); 61 | printf(" -c set copyright flag, default off\n"); 62 | printf(" -j encode in joint stereo (stereo data only)\n"); 63 | printf(" -d encode in dual-channel (stereo data only)\n"); 64 | printf(" -q quiet mode\n"); 65 | printf(" -v verbose mode\n"); 66 | } 67 | 68 | /* Use these default settings, can be overridden */ 69 | static void set_defaults(shine_config_t *config) { 70 | shine_set_config_mpeg_defaults(&config->mpeg); 71 | } 72 | 73 | /* Parse command line arguments */ 74 | static int parse_command(int argc, char **argv, shine_config_t *config) { 75 | int i = 0; 76 | 77 | if (argc < 3) 78 | return 0; 79 | 80 | while (argv[++i][0] == '-' && argv[i][1] != '\000' && argv[i][1] != ' ') 81 | switch (argv[i][1]) { 82 | case 'b': 83 | config->mpeg.bitr = atoi(argv[++i]); 84 | break; 85 | 86 | case 'm': 87 | force_mono = 1; 88 | break; 89 | 90 | case 'j': 91 | stereo = JOINT_STEREO; 92 | break; 93 | 94 | case 'd': 95 | stereo = DUAL_CHANNEL; 96 | break; 97 | 98 | case 'c': 99 | config->mpeg.copyright = 1; 100 | break; 101 | 102 | case 'q': 103 | quiet = 1; 104 | _verbose = 0; 105 | break; 106 | 107 | case 'v': 108 | _verbose = 1; 109 | quiet = 0; 110 | break; 111 | 112 | case 'h': 113 | default: 114 | return 0; 115 | } 116 | 117 | if (argc - i != 2) 118 | return 0; 119 | infname = argv[i++]; 120 | outfname = argv[i]; 121 | return 1; 122 | } 123 | 124 | /* Print some info about what we're going to encode */ 125 | static void check_config(shine_config_t *config) { 126 | static char *version_names[4] = {"2.5", "reserved", "II", "I"}; 127 | static char *mode_names[4] = {"stereo", "joint-stereo", "dual-channel", 128 | "mono"}; 129 | static char *demp_names[4] = {"none", "50/15us", "", "CITT"}; 130 | 131 | printf("MPEG-%s layer III, %s Psychoacoustic Model: Shine\n", 132 | version_names[shine_check_config(config->wave.samplerate, 133 | config->mpeg.bitr)], 134 | mode_names[config->mpeg.mode]); 135 | printf("Bitrate: %d kbps ", config->mpeg.bitr); 136 | printf("De-emphasis: %s %s %s\n", demp_names[config->mpeg.emph], 137 | ((config->mpeg.original) ? "Original" : ""), 138 | ((config->mpeg.copyright) ? "(C)" : "")); 139 | printf("Encoding \"%s\" to \"%s\"\n", infname, outfname); 140 | } 141 | 142 | int main(int argc, char **argv) { 143 | wave_t wave; 144 | time_t start_time, end_time; 145 | int16_t buffer[2 * SHINE_MAX_SAMPLES]; 146 | shine_config_t config; 147 | shine_t s; 148 | int written; 149 | unsigned char *data; 150 | int samples_per_pass; 151 | 152 | time(&start_time); 153 | 154 | /* Set the default MPEG encoding paramters - basically init the struct */ 155 | set_defaults(&config); 156 | 157 | if (!parse_command(argc, argv, &config)) { 158 | print_usage(); 159 | exit(1); 160 | } 161 | 162 | quiet = quiet || !strcmp(outfname, "-"); 163 | 164 | if (!quiet) 165 | print_name(); 166 | 167 | /* Open the input file and fill the config shine_wave_t header */ 168 | if (!wave_open(infname, &wave, &config, quiet)) 169 | error("Could not open WAVE file"); 170 | 171 | infile = wave.file; 172 | 173 | if (force_mono) 174 | config.wave.channels = 1; 175 | 176 | /* See if samplerate and bitrate are valid */ 177 | if (shine_check_config(config.wave.samplerate, config.mpeg.bitr) < 0) 178 | error("Unsupported samplerate/bitrate configuration."); 179 | 180 | /* open the output file */ 181 | if (!strcmp(outfname, "-")) 182 | outfile = stdout; 183 | else 184 | outfile = fopen(outfname, "wb"); 185 | if (!outfile) { 186 | fprintf(stderr, "Could not create \"%s\".\n", outfname); 187 | exit(1); 188 | } 189 | 190 | /* Set to stereo mode if wave data is stereo, mono otherwise. */ 191 | if (config.wave.channels > 1) 192 | config.mpeg.mode = stereo; 193 | else 194 | config.mpeg.mode = MONO; 195 | 196 | /* Initiate encoder */ 197 | s = shine_initialise(&config); 198 | 199 | // assert(s != NULL); 200 | 201 | /* Print some info about the file about to be created (optional) */ 202 | if (!quiet) 203 | check_config(&config); 204 | 205 | samples_per_pass = shine_samples_per_pass(s); 206 | 207 | /* All the magic happens here */ 208 | while (wave_get(buffer, &wave, samples_per_pass)) { 209 | data = shine_encode_buffer_interleaved(s, buffer, &written); 210 | if (write_mp3(written, data, &config) != written) { 211 | fprintf(stderr, "shineenc: write error\n"); 212 | return 1; 213 | } 214 | } 215 | 216 | /* Flush and write remaining data. */ 217 | data = shine_flush(s, &written); 218 | write_mp3(written, data, &config); 219 | 220 | /* Close encoder. */ 221 | shine_close(s); 222 | 223 | /* Close the wave file (using the wav reader) */ 224 | wave_close(&wave); 225 | 226 | /* Close the MP3 file */ 227 | fclose(outfile); 228 | 229 | time(&end_time); 230 | end_time -= start_time; 231 | if (!quiet) 232 | printf("Finished in %02ld:%02ld:%02ld (%01.1fx realtime)\n", 233 | end_time / 3600, (end_time / 60) % 60, end_time % 60, 234 | (float)wave.duration / (float)end_time); 235 | 236 | return 0; 237 | } 238 | -------------------------------------------------------------------------------- /src/bin/main.h: -------------------------------------------------------------------------------- 1 | #ifndef MAIN_H 2 | #define MAIN_H 3 | 4 | void error(char *s); 5 | int verbose(); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/bin/wave.c: -------------------------------------------------------------------------------- 1 | /* wave.c 2 | * 3 | * MS Wave files store data 'little endian' sytle. These functions will only 4 | * work on 'little endian' machines. 09/02/01 P.Everett 5 | * note. both Acorn/RISC OS and PC/DOS are little endian. 6 | */ 7 | 8 | /* Required headers from libshine. */ 9 | #include "layer3.h" 10 | 11 | /* Local header */ 12 | #include "main.h" 13 | #include "wave.h" 14 | #include 15 | #include 16 | 17 | /* RISC OS specifics */ 18 | #define WAVE 0xfb1 /* Wave filetype */ 19 | #define DATA 0xffd /* Data filetype */ 20 | 21 | #define MODE_MONO 3 22 | 23 | #ifdef SHINE_BIG_ENDIAN 24 | #if defined(SHINE_HAVE_BSWAP_H) 25 | #include 26 | #elif defined(__GNUC__) && \ 27 | (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) 28 | #define bswap_16(x) __builtin_bswap16(x) 29 | #define bswap_32(x) __builtin_bswap32(x) 30 | #else 31 | #define bswap_16(x) ((((x) >> 8) & 0xff) | (((x)&0xff) << 8)) 32 | #define bswap_32(x) \ 33 | ((((x)&0xFF) << 24) | (((x) >> 24) & 0xFF) | (((x)&0x0000FF00) << 8) | \ 34 | (((x)&0x00FF0000) >> 8)) 35 | #endif 36 | #endif 37 | 38 | typedef struct { 39 | char id[4]; 40 | uint32_t length; 41 | } riff_chunk_header_t; 42 | 43 | typedef struct { 44 | riff_chunk_header_t header; 45 | char wave[4]; 46 | } wave_chunk_t; 47 | 48 | typedef struct { 49 | riff_chunk_header_t header; 50 | uint16_t format; /* MS PCM = 1 */ 51 | uint16_t channels; /* channels, mono = 1, stereo = 2 */ 52 | uint32_t sample_rate; /* samples per second = 44100 */ 53 | uint32_t byte_rate; /* bytes per second = samp_rate * byte_samp = 176400 */ 54 | uint16_t frame_size; /* block align (bytes per sample) = channels * 55 | bits_per_sample / 8 = 4 */ 56 | uint16_t depth; /* bits per sample = 16 for MS PCM (format specific) */ 57 | } fmt_chunk_t; 58 | 59 | #ifdef SHINE_BIG_ENDIAN 60 | #define native_fmt_chunk(fmt) \ 61 | { \ 62 | fmt.header.length = bswap_32(fmt.header.length); \ 63 | fmt.format = bswap_16(fmt.format); \ 64 | fmt.channels = bswap_16(fmt.channels); \ 65 | fmt.sample_rate = bswap_32(fmt.sample_rate); \ 66 | fmt.byte_rate = bswap_32(fmt.byte_rate); \ 67 | fmt.frame_size = bswap_16(fmt.frame_size); \ 68 | fmt.depth = bswap_16(fmt.depth); \ 69 | } 70 | #endif 71 | 72 | void wave_seek(FILE *file, int has_seek, uint32_t bytes) { 73 | uint32_t i; 74 | if (has_seek == 1) 75 | fseek(file, bytes, SEEK_CUR); 76 | else { 77 | for (i = 0; i < bytes; i++) 78 | getc(file); 79 | } 80 | } 81 | 82 | unsigned char wave_get_chunk_header(FILE *file, int has_seek, const char id[4], 83 | riff_chunk_header_t *header) { 84 | unsigned char found = 0; 85 | uint32_t chunk_length; 86 | 87 | if (verbose()) 88 | fprintf(stderr, "Looking for chunk '%s'\n", id); 89 | 90 | while (!found) { 91 | if (fread(header, sizeof(riff_chunk_header_t), 1, file) != 1) { 92 | if (feof(file)) 93 | return 0; 94 | else 95 | error("Read error"); 96 | } 97 | 98 | /* chunks must be word-aligned, chunk data doesn't need to */ 99 | chunk_length = header->length + header->length % 2; 100 | if (verbose()) { 101 | fprintf(stderr, "Found chunk '%.4s', length: %u\n", header->id, 102 | header->length); 103 | } 104 | 105 | if (strncmp(header->id, id, 4) == 0) 106 | return 1; 107 | 108 | wave_seek(file, has_seek, chunk_length); 109 | } 110 | 111 | return 1; 112 | } 113 | 114 | void wave_close(wave_t *wave) { fclose(wave->file); } 115 | 116 | /* 117 | * wave_open: 118 | * ---------- 119 | * Opens and verifies the header of the Input Wave file. The file pointer is 120 | * left pointing to the start of the samples. 121 | */ 122 | unsigned char wave_open(const char *fname, wave_t *wave, shine_config_t *config, 123 | int quiet) { 124 | static char *channel_mappings[] = {NULL, "mono", "stereo"}; 125 | wave_chunk_t wave_chunk; 126 | fmt_chunk_t fmt_chunk; 127 | riff_chunk_header_t data_chunk; 128 | uint32_t fmt_data, fmt_length; 129 | 130 | if (!strcmp(fname, "-")) { 131 | /* TODO: support raw PCM stream with commandline parameters specifying 132 | * format */ 133 | wave->file = stdin; 134 | wave->has_seek = 0; 135 | } else { 136 | wave->file = fopen(fname, "rb"); 137 | wave->has_seek = 1; 138 | } 139 | 140 | if (!wave->file) 141 | error("Unable to open file"); 142 | 143 | if (fread(&wave_chunk, sizeof(wave_chunk), 1, wave->file) != 1) 144 | error("Invalid header"); 145 | 146 | if (strncmp(wave_chunk.header.id, "RIFF", 4) != 0) 147 | error("Not a MS-RIFF file"); 148 | 149 | if (strncmp(wave_chunk.wave, "WAVE", 4) != 0) 150 | error("Not a WAVE audio file"); 151 | 152 | /* Check the fmt chunk */ 153 | if (!wave_get_chunk_header(wave->file, wave->has_seek, "fmt ", 154 | (riff_chunk_header_t *)&fmt_chunk)) 155 | error("WAVE fmt chunk not found"); 156 | 157 | fmt_data = sizeof(fmt_chunk_t) - sizeof(riff_chunk_header_t); 158 | 159 | if (fread(&fmt_chunk.format, fmt_data, 1, wave->file) != 1) 160 | error("Read error"); 161 | 162 | #ifdef SHINE_BIG_ENDIAN 163 | native_fmt_chunk(fmt_chunk); 164 | #endif 165 | 166 | if (verbose()) 167 | fprintf(stderr, "WAVE format: %u\n", fmt_chunk.format); 168 | 169 | if (fmt_chunk.format != 1) 170 | error("Unknown WAVE format"); 171 | 172 | if (fmt_chunk.channels > 2) 173 | error("More than 2 channels"); 174 | 175 | if (fmt_chunk.depth != 16) 176 | error("Unsupported PCM bit depth"); 177 | 178 | // Skip remaining data. 179 | fmt_length = fmt_chunk.header.length + fmt_chunk.header.length % 2; 180 | if (fmt_length > fmt_data) 181 | wave_seek(wave->file, wave->has_seek, fmt_length - fmt_data); 182 | 183 | /* Position the file pointer at the data chunk */ 184 | if (!wave_get_chunk_header(wave->file, wave->has_seek, "data", &data_chunk)) 185 | error("WAVE data chunk not found"); 186 | 187 | config->wave.channels = fmt_chunk.channels; 188 | config->wave.samplerate = fmt_chunk.sample_rate; 189 | 190 | wave->channels = fmt_chunk.channels; 191 | wave->length = data_chunk.length; 192 | wave->duration = data_chunk.length / fmt_chunk.byte_rate; 193 | 194 | if (!quiet) 195 | printf("%s, %s %ldHz %ldbit, duration: %02ld:%02ld:%02ld\n", 196 | "WAVE PCM Data", channel_mappings[fmt_chunk.channels], 197 | (long)fmt_chunk.sample_rate, (long)fmt_chunk.depth, 198 | (long)wave->duration / 3600, (long)(wave->duration / 60) % 60, 199 | (long)wave->duration % 60); 200 | return 1; 201 | } 202 | 203 | #ifdef SHINE_BIG_ENDIAN 204 | void swap_buffer(int16_t *sample_buffer, int length) { 205 | int16_t *end = sample_buffer + length; 206 | 207 | if (length >= 2 * sizeof(long) / sizeof(int16_t)) { 208 | const unsigned long mask = 209 | (~0UL / 0xffff) * 0xff; /* 0x00ff00ff or 0x00ff00ff00ff00ff */ 210 | unsigned long *long_ptr = 211 | (unsigned long *)((unsigned long)sample_buffer & -sizeof(long)); 212 | 213 | /* make sample_buffer aligned on word boundary */ 214 | if ((int16_t *)long_ptr != sample_buffer) { 215 | long_ptr++; 216 | do { 217 | register uint16_t tmp = *sample_buffer++; 218 | sample_buffer[-1] = bswap_16(tmp); 219 | } while (sample_buffer != (int16_t *)long_ptr); 220 | } 221 | 222 | while ((int16_t *)(long_ptr + 1) <= end) { 223 | register unsigned long tmp = *long_ptr++; 224 | long_ptr[-1] = ((tmp & mask) << 8) | ((tmp >> 8) & mask); 225 | } 226 | 227 | sample_buffer = (int16_t *)long_ptr; 228 | } 229 | 230 | while (sample_buffer < end) { 231 | register uint16_t tmp = *sample_buffer++; 232 | sample_buffer[-1] = bswap_16(tmp); 233 | } 234 | } 235 | #endif 236 | 237 | /* 238 | * read_samples: 239 | * ------------- 240 | */ 241 | 242 | /* TODO: respect data chunk length */ 243 | int read_samples(int16_t *sample_buffer, int frame_size, FILE *file) { 244 | int samples_read = 0; 245 | 246 | samples_read = fread(sample_buffer, sizeof(int16_t), frame_size, file); 247 | 248 | #ifdef SHINE_BIG_ENDIAN 249 | swap_buffer(sample_buffer, samples_read); 250 | #endif 251 | 252 | if (samples_read < frame_size && 253 | samples_read > 0) { /* Pad sample with zero's */ 254 | memset(sample_buffer + samples_read, 0, 255 | (frame_size - samples_read) * sizeof(int16_t)); 256 | samples_read = frame_size; 257 | } 258 | 259 | return samples_read; 260 | } 261 | 262 | /* 263 | * wave_get: 264 | * --------- 265 | * Expects an interleaved 16bit pcm stream from read_samples, which it 266 | * reads into the given buffer. 267 | */ 268 | int wave_get(int16_t *buffer, wave_t *wave, int samp_per_pass) { 269 | return read_samples(buffer, samp_per_pass * wave->channels, wave->file); 270 | } 271 | -------------------------------------------------------------------------------- /src/bin/wave.h: -------------------------------------------------------------------------------- 1 | #ifndef WAVE_H 2 | #define WAVE_H 3 | 4 | #include 5 | 6 | typedef struct { 7 | FILE *file; 8 | int has_seek; 9 | int channels; 10 | long length; 11 | long duration; 12 | } wave_t; 13 | 14 | unsigned char wave_open(const char *fname, wave_t *wave, shine_config_t *config, 15 | int quiet); 16 | int wave_get(int16_t *buffer, wave_t *wave, int samp_per_frame); 17 | void wave_close(wave_t *wave); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /src/lib/bitstream.c: -------------------------------------------------------------------------------- 1 | /* 2 | * bit_stream.c package 3 | * Author: Jean-Georges Fritsch, C-Cube Microsystems 4 | * 5 | * This package provides functions to write information to the bit stream. 6 | * 7 | * Removed unused functions. Feb 2001 P.Everett 8 | */ 9 | 10 | #include "bitstream.h" 11 | #include "types.h" 12 | 13 | #if !defined(__APPLE__) && !defined(__FreeBSD__) 14 | #include 15 | #endif 16 | 17 | /* open the device to write the bit stream into it */ 18 | void shine_open_bit_stream(bitstream_t *bs, int size) { 19 | bs->data = (unsigned char *)malloc(size * sizeof(unsigned char)); 20 | bs->data_size = size; 21 | bs->data_position = 0; 22 | bs->cache = 0; 23 | bs->cache_bits = 32; 24 | } 25 | 26 | /*close the device containing the bit stream */ 27 | void shine_close_bit_stream(bitstream_t *bs) { 28 | if (bs->data) 29 | free(bs->data); 30 | } 31 | 32 | /* 33 | * shine_putbits: 34 | * -------- 35 | * write N bits into the bit stream. 36 | * bs = bit stream structure 37 | * val = value to write into the buffer 38 | * N = number of bits of val 39 | */ 40 | void shine_putbits(bitstream_t *bs, unsigned int val, unsigned int N) { 41 | #ifdef DEBUG 42 | if (N > 32) 43 | printf("Cannot write more than 32 bits at a time.\n"); 44 | if (N < 32 && (val >> N) != 0) 45 | printf("Upper bits (higher than %d) are not all zeros.\n", N); 46 | #endif 47 | 48 | if (bs->cache_bits > N) { 49 | bs->cache_bits -= N; 50 | bs->cache |= val << bs->cache_bits; 51 | } else { 52 | if (bs->data_position + sizeof(unsigned int) >= bs->data_size) { 53 | bs->data = (unsigned char *)realloc(bs->data, 54 | bs->data_size + (bs->data_size / 2)); 55 | bs->data_size += (bs->data_size / 2); 56 | } 57 | 58 | N -= bs->cache_bits; 59 | bs->cache |= val >> N; 60 | #ifdef SHINE_BIG_ENDIAN 61 | *(unsigned int *)(bs->data + bs->data_position) = bs->cache; 62 | #else 63 | *(unsigned int *)(bs->data + bs->data_position) = SWAB32(bs->cache); 64 | #endif 65 | bs->data_position += sizeof(unsigned int); 66 | bs->cache_bits = 32 - N; 67 | if (N != 0) 68 | bs->cache = val << bs->cache_bits; 69 | else 70 | bs->cache = 0; 71 | } 72 | } 73 | 74 | int shine_get_bits_count(bitstream_t *bs) { 75 | return bs->data_position * 8 + 32 - bs->cache_bits; 76 | } 77 | -------------------------------------------------------------------------------- /src/lib/bitstream.h: -------------------------------------------------------------------------------- 1 | #ifndef BITSTREAM_H 2 | #define BITSTREAM_H 3 | 4 | typedef struct bit_stream_struc { 5 | unsigned char *data; /* Processed data */ 6 | int data_size; /* Total data size */ 7 | int data_position; /* Data position */ 8 | unsigned int cache; /* bit stream cache */ 9 | int cache_bits; /* free bits in cache */ 10 | } bitstream_t; 11 | 12 | /* "bit_stream.h" Definitions */ 13 | 14 | #define MINIMUM 4 /* Minimum size of the buffer in bytes */ 15 | #define MAX_LENGTH \ 16 | 32 /* Maximum length of word written or \ 17 | read from bit stream */ 18 | 19 | #define BUFFER_SIZE 4096 20 | 21 | #define MIN(A, B) ((A) < (B) ? (A) : (B)) 22 | #define MAX(A, B) ((A) > (B) ? (A) : (B)) 23 | 24 | void shine_open_bit_stream(bitstream_t *bs, const int size); 25 | void shine_close_bit_stream(bitstream_t *bs); 26 | void shine_putbits(bitstream_t *bs, unsigned int val, unsigned int N); 27 | int shine_get_bits_count(bitstream_t *bs); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /src/lib/huffman.c: -------------------------------------------------------------------------------- 1 | /* huffman.c */ 2 | 3 | #include "huffman.h" 4 | #include "bitstream.h" 5 | #include "l3bitstream.h" 6 | #include "types.h" 7 | 8 | const HUFFBITS dmask = 1 << (((sizeof(HUFFBITS)) << 3) - 1); 9 | const unsigned int hs = sizeof(HUFFBITS) << 3; 10 | 11 | static const HUFFBITS t1HB[] = {1, 1, 1, 0}; 12 | static const HUFFBITS t2HB[] = {1, 2, 1, 3, 1, 1, 3, 2, 0}; 13 | static const HUFFBITS t3HB[] = {3, 2, 1, 1, 1, 1, 3, 2, 0}; 14 | static const HUFFBITS t5HB[] = {1, 2, 6, 5, 3, 1, 4, 4, 7, 5, 7, 1, 6, 1, 1, 0}; 15 | static const HUFFBITS t6HB[] = {7, 3, 5, 1, 6, 2, 3, 2, 5, 4, 4, 1, 3, 3, 2, 0}; 16 | static const HUFFBITS t7HB[] = {1, 2, 10, 19, 16, 10, 3, 3, 7, 10, 5, 3, 17 | 11, 4, 13, 17, 8, 4, 12, 11, 18, 15, 11, 2, 18 | 7, 6, 9, 14, 3, 1, 6, 4, 5, 3, 2, 0}; 19 | static const HUFFBITS t8HB[] = {3, 4, 6, 18, 12, 5, 5, 1, 2, 16, 9, 3, 20 | 7, 3, 5, 14, 7, 3, 19, 17, 15, 13, 10, 4, 21 | 13, 5, 8, 11, 5, 1, 12, 4, 4, 1, 1, 0}; 22 | static const HUFFBITS t9HB[] = {7, 5, 9, 14, 15, 7, 6, 4, 5, 5, 6, 7, 23 | 7, 6, 8, 8, 8, 5, 15, 6, 9, 10, 5, 1, 24 | 11, 7, 9, 6, 4, 1, 14, 4, 6, 2, 6, 0}; 25 | static const HUFFBITS t10HB[] = { 26 | 1, 2, 10, 23, 35, 30, 12, 17, 3, 3, 8, 12, 18, 21, 12, 7, 27 | 11, 9, 15, 21, 32, 40, 19, 6, 14, 13, 22, 34, 46, 23, 18, 7, 28 | 20, 19, 33, 47, 27, 22, 9, 3, 31, 22, 41, 26, 21, 20, 5, 3, 29 | 14, 13, 10, 11, 16, 6, 5, 1, 9, 8, 7, 8, 4, 4, 2, 0}; 30 | static const HUFFBITS t11HB[] = { 31 | 3, 4, 10, 24, 34, 33, 21, 15, 5, 3, 4, 10, 32, 17, 11, 10, 32 | 11, 7, 13, 18, 30, 31, 20, 5, 25, 11, 19, 59, 27, 18, 12, 5, 33 | 35, 33, 31, 58, 30, 16, 7, 5, 28, 26, 32, 19, 17, 15, 8, 14, 34 | 14, 12, 9, 13, 14, 9, 4, 1, 11, 4, 6, 6, 6, 3, 2, 0}; 35 | static const HUFFBITS t12HB[] = { 36 | 9, 6, 16, 33, 41, 39, 38, 26, 7, 5, 6, 9, 23, 16, 26, 11, 37 | 17, 7, 11, 14, 21, 30, 10, 7, 17, 10, 15, 12, 18, 28, 14, 5, 38 | 32, 13, 22, 19, 18, 16, 9, 5, 40, 17, 31, 29, 17, 13, 4, 2, 39 | 27, 12, 11, 15, 10, 7, 4, 1, 27, 12, 8, 12, 6, 3, 1, 0}; 40 | static const HUFFBITS t13HB[] = { 41 | 1, 5, 14, 21, 34, 51, 46, 71, 42, 52, 68, 52, 67, 44, 43, 19, 3, 4, 42 | 12, 19, 31, 26, 44, 33, 31, 24, 32, 24, 31, 35, 22, 14, 15, 13, 23, 36, 43 | 59, 49, 77, 65, 29, 40, 30, 40, 27, 33, 42, 16, 22, 20, 37, 61, 56, 79, 44 | 73, 64, 43, 76, 56, 37, 26, 31, 25, 14, 35, 16, 60, 57, 97, 75, 114, 91, 45 | 54, 73, 55, 41, 48, 53, 23, 24, 58, 27, 50, 96, 76, 70, 93, 84, 77, 58, 46 | 79, 29, 74, 49, 41, 17, 47, 45, 78, 74, 115, 94, 90, 79, 69, 83, 71, 50, 47 | 59, 38, 36, 15, 72, 34, 56, 95, 92, 85, 91, 90, 86, 73, 77, 65, 51, 44, 48 | 43, 42, 43, 20, 30, 44, 55, 78, 72, 87, 78, 61, 46, 54, 37, 30, 20, 16, 49 | 53, 25, 41, 37, 44, 59, 54, 81, 66, 76, 57, 54, 37, 18, 39, 11, 35, 33, 50 | 31, 57, 42, 82, 72, 80, 47, 58, 55, 21, 22, 26, 38, 22, 53, 25, 23, 38, 51 | 70, 60, 51, 36, 55, 26, 34, 23, 27, 14, 9, 7, 34, 32, 28, 39, 49, 75, 52 | 30, 52, 48, 40, 52, 28, 18, 17, 9, 5, 45, 21, 34, 64, 56, 50, 49, 45, 53 | 31, 19, 12, 15, 10, 7, 6, 3, 48, 23, 20, 39, 36, 35, 53, 21, 16, 23, 54 | 13, 10, 6, 1, 4, 2, 16, 15, 17, 27, 25, 20, 29, 11, 17, 12, 16, 8, 55 | 1, 1, 0, 1}; 56 | static const HUFFBITS t15HB[] = { 57 | 7, 12, 18, 53, 47, 76, 124, 108, 89, 123, 108, 119, 107, 81, 122, 63, 58 | 13, 5, 16, 27, 46, 36, 61, 51, 42, 70, 52, 83, 65, 41, 59, 36, 59 | 19, 17, 15, 24, 41, 34, 59, 48, 40, 64, 50, 78, 62, 80, 56, 33, 60 | 29, 28, 25, 43, 39, 63, 55, 93, 76, 59, 93, 72, 54, 75, 50, 29, 61 | 52, 22, 42, 40, 67, 57, 95, 79, 72, 57, 89, 69, 49, 66, 46, 27, 62 | 77, 37, 35, 66, 58, 52, 91, 74, 62, 48, 79, 63, 90, 62, 40, 38, 63 | 125, 32, 60, 56, 50, 92, 78, 65, 55, 87, 71, 51, 73, 51, 70, 30, 64 | 109, 53, 49, 94, 88, 75, 66, 122, 91, 73, 56, 42, 64, 44, 21, 25, 65 | 90, 43, 41, 77, 73, 63, 56, 92, 77, 66, 47, 67, 48, 53, 36, 20, 66 | 71, 34, 67, 60, 58, 49, 88, 76, 67, 106, 71, 54, 38, 39, 23, 15, 67 | 109, 53, 51, 47, 90, 82, 58, 57, 48, 72, 57, 41, 23, 27, 62, 9, 68 | 86, 42, 40, 37, 70, 64, 52, 43, 70, 55, 42, 25, 29, 18, 11, 11, 69 | 118, 68, 30, 55, 50, 46, 74, 65, 49, 39, 24, 16, 22, 13, 14, 7, 70 | 91, 44, 39, 38, 34, 63, 52, 45, 31, 52, 28, 19, 14, 8, 9, 3, 71 | 123, 60, 58, 53, 47, 43, 32, 22, 37, 24, 17, 12, 15, 10, 2, 1, 72 | 71, 37, 34, 30, 28, 20, 17, 26, 21, 16, 10, 6, 8, 6, 2, 0}; 73 | static const HUFFBITS t16HB[] = { 74 | 1, 5, 14, 44, 74, 63, 110, 93, 172, 149, 138, 242, 225, 195, 75 | 376, 17, 3, 4, 12, 20, 35, 62, 53, 47, 83, 75, 68, 119, 76 | 201, 107, 207, 9, 15, 13, 23, 38, 67, 58, 103, 90, 161, 72, 77 | 127, 117, 110, 209, 206, 16, 45, 21, 39, 69, 64, 114, 99, 87, 78 | 158, 140, 252, 212, 199, 387, 365, 26, 75, 36, 68, 65, 115, 101, 79 | 179, 164, 155, 264, 246, 226, 395, 382, 362, 9, 66, 30, 59, 56, 80 | 102, 185, 173, 265, 142, 253, 232, 400, 388, 378, 445, 16, 111, 54, 81 | 52, 100, 184, 178, 160, 133, 257, 244, 228, 217, 385, 366, 715, 10, 82 | 98, 48, 91, 88, 165, 157, 148, 261, 248, 407, 397, 372, 380, 889, 83 | 884, 8, 85, 84, 81, 159, 156, 143, 260, 249, 427, 401, 392, 383, 84 | 727, 713, 708, 7, 154, 76, 73, 141, 131, 256, 245, 426, 406, 394, 85 | 384, 735, 359, 710, 352, 11, 139, 129, 67, 125, 247, 233, 229, 219, 86 | 393, 743, 737, 720, 885, 882, 439, 4, 243, 120, 118, 115, 227, 223, 87 | 396, 746, 742, 736, 721, 712, 706, 223, 436, 6, 202, 224, 222, 218, 88 | 216, 389, 386, 381, 364, 888, 443, 707, 440, 437, 1728, 4, 747, 211, 89 | 210, 208, 370, 379, 734, 723, 714, 1735, 883, 877, 876, 3459, 865, 2, 90 | 377, 369, 102, 187, 726, 722, 358, 711, 709, 866, 1734, 871, 3458, 870, 91 | 434, 0, 12, 10, 7, 11, 10, 17, 11, 9, 13, 12, 10, 7, 92 | 5, 3, 1, 3}; 93 | static const HUFFBITS t24HB[] = { 94 | 15, 13, 46, 80, 146, 262, 248, 434, 426, 669, 653, 649, 621, 517, 1032, 95 | 88, 14, 12, 21, 38, 71, 130, 122, 216, 209, 198, 327, 345, 319, 297, 96 | 279, 42, 47, 22, 41, 74, 68, 128, 120, 221, 207, 194, 182, 340, 315, 97 | 295, 541, 18, 81, 39, 75, 70, 134, 125, 116, 220, 204, 190, 178, 325, 98 | 311, 293, 271, 16, 147, 72, 69, 135, 127, 118, 112, 210, 200, 188, 352, 99 | 323, 306, 285, 540, 14, 263, 66, 129, 126, 119, 114, 214, 202, 192, 180, 100 | 341, 317, 301, 281, 262, 12, 249, 123, 121, 117, 113, 215, 206, 195, 185, 101 | 347, 330, 308, 291, 272, 520, 10, 435, 115, 111, 109, 211, 203, 196, 187, 102 | 353, 332, 313, 298, 283, 531, 381, 17, 427, 212, 208, 205, 201, 193, 186, 103 | 177, 169, 320, 303, 286, 268, 514, 377, 16, 335, 199, 197, 191, 189, 181, 104 | 174, 333, 321, 305, 289, 275, 521, 379, 371, 11, 668, 184, 183, 179, 175, 105 | 344, 331, 314, 304, 290, 277, 530, 383, 373, 366, 10, 652, 346, 171, 168, 106 | 164, 318, 309, 299, 287, 276, 263, 513, 375, 368, 362, 6, 648, 322, 316, 107 | 312, 307, 302, 292, 284, 269, 261, 512, 376, 370, 364, 359, 4, 620, 300, 108 | 296, 294, 288, 282, 273, 266, 515, 380, 374, 369, 365, 361, 357, 2, 1033, 109 | 280, 278, 274, 267, 264, 259, 382, 378, 372, 367, 363, 360, 358, 356, 0, 110 | 43, 20, 19, 17, 15, 13, 11, 9, 7, 6, 4, 7, 5, 3, 1, 111 | 3}; 112 | static const HUFFBITS t32HB[] = {1, 5, 4, 5, 6, 5, 4, 4, 113 | 7, 3, 6, 0, 7, 2, 3, 1}; 114 | static const HUFFBITS t33HB[] = {15, 14, 13, 12, 11, 10, 9, 8, 115 | 7, 6, 5, 4, 3, 2, 1, 0}; 116 | 117 | static const unsigned char t1l[] = {1, 3, 2, 3}; 118 | static const unsigned char t2l[] = {1, 3, 6, 3, 3, 5, 5, 5, 6}; 119 | static const unsigned char t3l[] = {2, 2, 6, 3, 2, 5, 5, 5, 6}; 120 | static const unsigned char t5l[] = {1, 3, 6, 7, 3, 3, 6, 7, 121 | 6, 6, 7, 8, 7, 6, 7, 8}; 122 | static const unsigned char t6l[] = {3, 3, 5, 7, 3, 2, 4, 5, 123 | 4, 4, 5, 6, 6, 5, 6, 7}; 124 | static const unsigned char t7l[] = {1, 3, 6, 8, 8, 9, 3, 4, 6, 7, 7, 8, 125 | 6, 5, 7, 8, 8, 9, 7, 7, 8, 9, 9, 9, 126 | 7, 7, 8, 9, 9, 10, 8, 8, 9, 10, 10, 10}; 127 | static const unsigned char t8l[] = {2, 3, 6, 8, 8, 9, 3, 2, 4, 8, 8, 8, 128 | 6, 4, 6, 8, 8, 9, 8, 8, 8, 9, 9, 10, 129 | 8, 7, 8, 9, 10, 10, 9, 8, 9, 9, 11, 11}; 130 | static const unsigned char t9l[] = {3, 3, 5, 6, 8, 9, 3, 3, 4, 5, 6, 8, 131 | 4, 4, 5, 6, 7, 8, 6, 5, 6, 7, 7, 8, 132 | 7, 6, 7, 7, 8, 9, 8, 7, 8, 8, 9, 9}; 133 | static const unsigned char t10l[] = { 134 | 1, 3, 6, 8, 9, 9, 9, 10, 3, 4, 6, 7, 8, 9, 8, 8, 135 | 6, 6, 7, 8, 9, 10, 9, 9, 7, 7, 8, 9, 10, 10, 9, 10, 136 | 8, 8, 9, 10, 10, 10, 10, 10, 9, 9, 10, 10, 11, 11, 10, 11, 137 | 8, 8, 9, 10, 10, 10, 11, 11, 9, 8, 9, 10, 10, 11, 11, 11}; 138 | static const unsigned char t11l[] = { 139 | 2, 3, 5, 7, 8, 9, 8, 9, 3, 3, 4, 6, 8, 8, 7, 8, 140 | 5, 5, 6, 7, 8, 9, 8, 8, 7, 6, 7, 9, 8, 10, 8, 9, 141 | 8, 8, 8, 9, 9, 10, 9, 10, 8, 8, 9, 10, 10, 11, 10, 11, 142 | 8, 7, 7, 8, 9, 10, 10, 10, 8, 7, 8, 9, 10, 10, 10, 10}; 143 | static const unsigned char t12l[] = { 144 | 4, 3, 5, 7, 8, 9, 9, 9, 3, 3, 4, 5, 7, 7, 8, 8, 5, 4, 5, 6, 7, 8, 145 | 7, 8, 6, 5, 6, 6, 7, 8, 8, 8, 7, 6, 7, 7, 8, 8, 8, 9, 8, 7, 8, 8, 146 | 8, 9, 8, 9, 8, 7, 7, 8, 8, 9, 9, 10, 9, 8, 8, 9, 9, 9, 9, 10}; 147 | static const unsigned char t13l[] = { 148 | 1, 4, 6, 7, 8, 9, 9, 10, 9, 10, 11, 11, 12, 12, 13, 13, 3, 4, 6, 149 | 7, 8, 8, 9, 9, 9, 9, 10, 10, 11, 12, 12, 12, 6, 6, 7, 8, 9, 9, 150 | 10, 10, 9, 10, 10, 11, 11, 12, 13, 13, 7, 7, 8, 9, 9, 10, 10, 10, 10, 151 | 11, 11, 11, 11, 12, 13, 13, 8, 7, 9, 9, 10, 10, 11, 11, 10, 11, 11, 12, 152 | 12, 13, 13, 14, 9, 8, 9, 10, 10, 10, 11, 11, 11, 11, 12, 11, 13, 13, 14, 153 | 14, 9, 9, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 13, 13, 14, 14, 10, 9, 154 | 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 16, 16, 9, 8, 9, 10, 10, 155 | 11, 11, 12, 12, 12, 12, 13, 13, 14, 15, 15, 10, 9, 10, 10, 11, 11, 11, 13, 156 | 12, 13, 13, 14, 14, 14, 16, 15, 10, 10, 10, 11, 11, 12, 12, 13, 12, 13, 14, 157 | 13, 14, 15, 16, 17, 11, 10, 10, 11, 12, 12, 12, 12, 13, 13, 13, 14, 15, 15, 158 | 15, 16, 11, 11, 11, 12, 12, 13, 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 12, 159 | 11, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 16, 15, 16, 16, 13, 12, 12, 13, 160 | 13, 13, 15, 14, 14, 17, 15, 15, 15, 17, 16, 16, 12, 12, 13, 14, 14, 14, 15, 161 | 14, 15, 15, 16, 16, 19, 18, 19, 16}; 162 | static const unsigned char t15l[] = { 163 | 3, 4, 5, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 13, 4, 3, 5, 164 | 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 5, 5, 5, 6, 7, 7, 165 | 8, 8, 8, 9, 9, 10, 10, 11, 11, 11, 6, 6, 6, 7, 7, 8, 8, 9, 9, 166 | 9, 10, 10, 10, 11, 11, 11, 7, 6, 7, 7, 8, 8, 9, 9, 9, 9, 10, 10, 167 | 10, 11, 11, 11, 8, 7, 7, 8, 8, 8, 9, 9, 9, 9, 10, 10, 11, 11, 11, 168 | 12, 9, 7, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 9, 8, 169 | 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 12, 9, 8, 8, 9, 9, 170 | 9, 9, 10, 10, 10, 10, 11, 11, 12, 12, 12, 9, 8, 9, 9, 9, 9, 10, 10, 171 | 10, 11, 11, 11, 11, 12, 12, 12, 10, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 172 | 11, 11, 12, 13, 12, 10, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 173 | 12, 13, 11, 10, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 13, 13, 11, 174 | 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 12, 11, 11, 11, 175 | 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 12, 13, 12, 11, 11, 11, 11, 11, 11, 176 | 12, 12, 12, 12, 12, 13, 13, 13, 13}; 177 | static const unsigned char t16l[] = { 178 | 1, 4, 6, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 9, 3, 4, 6, 179 | 7, 8, 9, 9, 9, 10, 10, 10, 11, 12, 11, 12, 8, 6, 6, 7, 8, 9, 9, 180 | 10, 10, 11, 10, 11, 11, 11, 12, 12, 9, 8, 7, 8, 9, 9, 10, 10, 10, 11, 181 | 11, 12, 12, 12, 13, 13, 10, 9, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 182 | 13, 13, 13, 9, 9, 8, 9, 9, 10, 11, 11, 12, 11, 12, 12, 13, 13, 13, 14, 183 | 10, 10, 9, 9, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 10, 10, 9, 184 | 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 13, 15, 15, 10, 10, 10, 10, 11, 11, 185 | 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 10, 11, 10, 10, 11, 11, 12, 12, 13, 186 | 13, 13, 13, 14, 13, 14, 13, 11, 11, 11, 10, 11, 12, 12, 12, 12, 13, 14, 14, 187 | 14, 15, 15, 14, 10, 12, 11, 11, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14, 13, 188 | 14, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 15, 14, 14, 14, 14, 16, 11, 14, 189 | 12, 12, 12, 13, 13, 14, 14, 14, 16, 15, 15, 15, 17, 15, 11, 13, 13, 11, 12, 190 | 14, 14, 13, 14, 14, 15, 16, 15, 17, 15, 14, 11, 9, 8, 8, 9, 9, 10, 10, 191 | 10, 11, 11, 11, 11, 11, 11, 11, 8}; 192 | static const unsigned char t24l[] = { 193 | 4, 4, 6, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 12, 9, 4, 4, 5, 194 | 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10, 8, 6, 5, 6, 7, 7, 8, 195 | 8, 9, 9, 9, 9, 10, 10, 10, 11, 7, 7, 6, 7, 7, 8, 8, 8, 9, 9, 196 | 9, 9, 10, 10, 10, 10, 7, 8, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, 197 | 10, 10, 11, 7, 9, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 198 | 7, 9, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 7, 10, 8, 199 | 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 8, 10, 9, 9, 9, 9, 200 | 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 8, 10, 9, 9, 9, 9, 9, 9, 10, 201 | 10, 10, 10, 10, 11, 11, 11, 8, 11, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 202 | 11, 11, 11, 11, 8, 11, 10, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, 203 | 11, 8, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 8, 11, 204 | 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 8, 12, 10, 10, 10, 205 | 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 8, 8, 7, 7, 7, 7, 7, 7, 206 | 7, 7, 7, 7, 8, 8, 8, 8, 4}; 207 | static const unsigned char t32l[] = {1, 4, 4, 5, 4, 6, 5, 6, 208 | 4, 5, 5, 6, 5, 6, 6, 6}; 209 | static const unsigned char t33l[] = {4, 4, 4, 4, 4, 4, 4, 4, 210 | 4, 4, 4, 4, 4, 4, 4, 4}; 211 | 212 | #define NOREF -1 213 | const struct huffcodetab shine_huffman_table[HTN] = { 214 | {0, 0, 0, 0, NULL, NULL}, 215 | {2, 2, 0, 0, t1HB, t1l}, 216 | {3, 3, 0, 0, t2HB, t2l}, 217 | {3, 3, 0, 0, t3HB, t3l}, 218 | {0, 0, 0, 0, NULL, NULL}, /* Apparently not used*/ 219 | {4, 4, 0, 0, t5HB, t5l}, 220 | {4, 4, 0, 0, t6HB, t6l}, 221 | {6, 6, 0, 0, t7HB, t7l}, 222 | {6, 6, 0, 0, t8HB, t8l}, 223 | {6, 6, 0, 0, t9HB, t9l}, 224 | {8, 8, 0, 0, t10HB, t10l}, 225 | {8, 8, 0, 0, t11HB, t11l}, 226 | {8, 8, 0, 0, t12HB, t12l}, 227 | {16, 16, 0, 0, t13HB, t13l}, 228 | {0, 0, 0, 0, NULL, NULL}, /* Apparently not used*/ 229 | {16, 16, 0, 0, t15HB, t15l}, 230 | {16, 16, 1, 1, t16HB, t16l}, 231 | {16, 16, 2, 3, t16HB, t16l}, 232 | {16, 16, 3, 7, t16HB, t16l}, 233 | {16, 16, 4, 15, t16HB, t16l}, 234 | {16, 16, 6, 63, t16HB, t16l}, 235 | {16, 16, 8, 255, t16HB, t16l}, 236 | {16, 16, 10, 1023, t16HB, t16l}, 237 | {16, 16, 13, 8191, t16HB, t16l}, 238 | {16, 16, 4, 15, t24HB, t24l}, 239 | {16, 16, 5, 31, t24HB, t24l}, 240 | {16, 16, 6, 63, t24HB, t24l}, 241 | {16, 16, 7, 127, t24HB, t24l}, 242 | {16, 16, 8, 255, t24HB, t24l}, 243 | {16, 16, 9, 511, t24HB, t24l}, 244 | {16, 16, 11, 2047, t24HB, t24l}, 245 | {16, 16, 13, 8191, t24HB, t24l}, 246 | {1, 16, 0, 0, t32HB, t32l}, 247 | {1, 16, 0, 0, t33HB, t33l}, 248 | }; 249 | -------------------------------------------------------------------------------- /src/lib/huffman.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define HUFFBITS uint16_t 4 | #define HTN 34 5 | #define MXOFF 250 6 | 7 | struct huffcodetab { 8 | unsigned int xlen; /*max. x-index+ */ 9 | unsigned int ylen; /*max. y-index+ */ 10 | unsigned int linbits; /*number of linbits */ 11 | unsigned int linmax; /*max number to be stored in linbits */ 12 | const HUFFBITS *table; /*pointer to array[xlen][ylen] */ 13 | const unsigned char *hlen; /*pointer to array[xlen][ylen] */ 14 | }; 15 | 16 | extern const struct huffcodetab 17 | shine_huffman_table[HTN]; /* global memory block */ 18 | /* array of all huffcodtable headers */ 19 | /* 0..31 Huffman code table 0..31 */ 20 | /* 32,33 count1-tables */ 21 | -------------------------------------------------------------------------------- /src/lib/l3bitstream.c: -------------------------------------------------------------------------------- 1 | /* l3bitstrea.c */ 2 | 3 | #include "l3bitstream.h" /* the public interface */ 4 | #include "bitstream.h" 5 | #include "huffman.h" 6 | #include "l3loop.h" 7 | #include "l3mdct.h" 8 | #include "layer3.h" 9 | #include "tables.h" 10 | #include "types.h" 11 | 12 | static void shine_HuffmanCode(bitstream_t *bs, int table_select, int x, int y); 13 | static void shine_huffman_coder_count1(bitstream_t *bs, 14 | const struct huffcodetab *h, int v, 15 | int w, int x, int y); 16 | 17 | static void encodeSideInfo(shine_global_config *config); 18 | static void encodeMainData(shine_global_config *config); 19 | static void Huffmancodebits(shine_global_config *config, int *ix, gr_info *gi); 20 | 21 | /* 22 | shine_format_bitstream() 23 | 24 | This is called after a frame of audio has been quantized and coded. 25 | It will write the encoded audio to the bitstream. Note that 26 | from a layer3 encoder's perspective the bit stream is primarily 27 | a series of main_data() blocks, with header and side information 28 | inserted at the proper locations to maintain framing. (See Figure A.7 29 | in the IS). 30 | */ 31 | 32 | void shine_format_bitstream(shine_global_config *config) { 33 | int gr, ch, i; 34 | 35 | for (ch = 0; ch < config->wave.channels; ch++) 36 | for (gr = 0; gr < config->mpeg.granules_per_frame; gr++) { 37 | int *pi = &config->l3_enc[ch][gr][0]; 38 | int32_t *pr = &config->mdct_freq[ch][gr][0]; 39 | for (i = 0; i < GRANULE_SIZE; i++) { 40 | if ((pr[i] < 0) && (pi[i] > 0)) 41 | pi[i] *= -1; 42 | } 43 | } 44 | 45 | encodeSideInfo(config); 46 | encodeMainData(config); 47 | } 48 | 49 | static void encodeMainData(shine_global_config *config) { 50 | int gr, ch, sfb; 51 | shine_side_info_t si = config->side_info; 52 | 53 | for (gr = 0; gr < config->mpeg.granules_per_frame; gr++) { 54 | for (ch = 0; ch < config->wave.channels; ch++) { 55 | gr_info *gi = &(si.gr[gr].ch[ch].tt); 56 | unsigned slen1 = shine_slen1_tab[gi->scalefac_compress]; 57 | unsigned slen2 = shine_slen2_tab[gi->scalefac_compress]; 58 | int *ix = &config->l3_enc[ch][gr][0]; 59 | 60 | if (gr == 0 || si.scfsi[ch][0] == 0) 61 | for (sfb = 0; sfb < 6; sfb++) 62 | shine_putbits(&config->bs, config->scalefactor.l[gr][ch][sfb], slen1); 63 | if (gr == 0 || si.scfsi[ch][1] == 0) 64 | for (sfb = 6; sfb < 11; sfb++) 65 | shine_putbits(&config->bs, config->scalefactor.l[gr][ch][sfb], slen1); 66 | if (gr == 0 || si.scfsi[ch][2] == 0) 67 | for (sfb = 11; sfb < 16; sfb++) 68 | shine_putbits(&config->bs, config->scalefactor.l[gr][ch][sfb], slen2); 69 | if (gr == 0 || si.scfsi[ch][3] == 0) 70 | for (sfb = 16; sfb < 21; sfb++) 71 | shine_putbits(&config->bs, config->scalefactor.l[gr][ch][sfb], slen2); 72 | 73 | Huffmancodebits(config, ix, gi); 74 | } 75 | } 76 | } 77 | 78 | static void encodeSideInfo(shine_global_config *config) { 79 | int gr, ch, scfsi_band, region; 80 | shine_side_info_t si = config->side_info; 81 | 82 | shine_putbits(&config->bs, 0x7ff, 11); 83 | shine_putbits(&config->bs, config->mpeg.version, 2); 84 | shine_putbits(&config->bs, config->mpeg.layer, 2); 85 | shine_putbits(&config->bs, !config->mpeg.crc, 1); 86 | shine_putbits(&config->bs, config->mpeg.bitrate_index, 4); 87 | shine_putbits(&config->bs, config->mpeg.samplerate_index % 3, 2); 88 | shine_putbits(&config->bs, config->mpeg.padding, 1); 89 | shine_putbits(&config->bs, config->mpeg.ext, 1); 90 | shine_putbits(&config->bs, config->mpeg.mode, 2); 91 | shine_putbits(&config->bs, config->mpeg.mode_ext, 2); 92 | shine_putbits(&config->bs, config->mpeg.copyright, 1); 93 | shine_putbits(&config->bs, config->mpeg.original, 1); 94 | shine_putbits(&config->bs, config->mpeg.emph, 2); 95 | 96 | if (config->mpeg.version == MPEG_I) { 97 | shine_putbits(&config->bs, 0, 9); 98 | if (config->wave.channels == 2) 99 | shine_putbits(&config->bs, si.private_bits, 3); 100 | else 101 | shine_putbits(&config->bs, si.private_bits, 5); 102 | } else { 103 | shine_putbits(&config->bs, 0, 8); 104 | if (config->wave.channels == 2) 105 | shine_putbits(&config->bs, si.private_bits, 2); 106 | else 107 | shine_putbits(&config->bs, si.private_bits, 1); 108 | } 109 | 110 | if (config->mpeg.version == MPEG_I) 111 | for (ch = 0; ch < config->wave.channels; ch++) { 112 | for (scfsi_band = 0; scfsi_band < 4; scfsi_band++) 113 | shine_putbits(&config->bs, si.scfsi[ch][scfsi_band], 1); 114 | } 115 | 116 | for (gr = 0; gr < config->mpeg.granules_per_frame; gr++) 117 | for (ch = 0; ch < config->wave.channels; ch++) { 118 | gr_info *gi = &(si.gr[gr].ch[ch].tt); 119 | 120 | shine_putbits(&config->bs, gi->part2_3_length, 12); 121 | shine_putbits(&config->bs, gi->big_values, 9); 122 | shine_putbits(&config->bs, gi->global_gain, 8); 123 | if (config->mpeg.version == MPEG_I) 124 | shine_putbits(&config->bs, gi->scalefac_compress, 4); 125 | else 126 | shine_putbits(&config->bs, gi->scalefac_compress, 9); 127 | shine_putbits(&config->bs, 0, 1); 128 | 129 | for (region = 0; region < 3; region++) 130 | shine_putbits(&config->bs, gi->table_select[region], 5); 131 | 132 | shine_putbits(&config->bs, gi->region0_count, 4); 133 | shine_putbits(&config->bs, gi->region1_count, 3); 134 | 135 | if (config->mpeg.version == MPEG_I) 136 | shine_putbits(&config->bs, gi->preflag, 1); 137 | shine_putbits(&config->bs, gi->scalefac_scale, 1); 138 | shine_putbits(&config->bs, gi->count1table_select, 1); 139 | } 140 | } 141 | 142 | /* Note the discussion of huffmancodebits() on pages 28 and 29 of the IS, as 143 | well as the definitions of the side information on pages 26 and 27. */ 144 | static void Huffmancodebits(shine_global_config *config, int *ix, gr_info *gi) { 145 | const int *scalefac = 146 | &shine_scale_fact_band_index[config->mpeg.samplerate_index][0]; 147 | unsigned scalefac_index; 148 | int region1Start, region2Start; 149 | int i, bigvalues, count1End; 150 | int v, w, x, y; 151 | const struct huffcodetab *h; 152 | int bits; 153 | 154 | bits = shine_get_bits_count(&config->bs); 155 | 156 | /* 1: Write the bigvalues */ 157 | bigvalues = gi->big_values << 1; 158 | 159 | scalefac_index = gi->region0_count + 1; 160 | region1Start = scalefac[scalefac_index]; 161 | scalefac_index += gi->region1_count + 1; 162 | region2Start = scalefac[scalefac_index]; 163 | 164 | for (i = 0; i < bigvalues; i += 2) { 165 | /* get table pointer */ 166 | int idx = (i >= region1Start) + (i >= region2Start); 167 | unsigned tableindex = gi->table_select[idx]; 168 | /* get huffman code */ 169 | if (tableindex) { 170 | x = ix[i]; 171 | y = ix[i + 1]; 172 | shine_HuffmanCode(&config->bs, tableindex, x, y); 173 | } 174 | } 175 | 176 | /* 2: Write count1 area */ 177 | h = &shine_huffman_table[gi->count1table_select + 32]; 178 | count1End = bigvalues + (gi->count1 << 2); 179 | for (i = bigvalues; i < count1End; i += 4) { 180 | v = ix[i]; 181 | w = ix[i + 1]; 182 | x = ix[i + 2]; 183 | y = ix[i + 3]; 184 | shine_huffman_coder_count1(&config->bs, h, v, w, x, y); 185 | } 186 | 187 | bits = shine_get_bits_count(&config->bs) - bits; 188 | bits = gi->part2_3_length - gi->part2_length - bits; 189 | if (bits) { 190 | int stuffingWords = bits / 32; 191 | int remainingBits = bits % 32; 192 | 193 | /* Due to the nature of the Huffman code tables, we will pad with ones */ 194 | while (stuffingWords--) 195 | shine_putbits(&config->bs, ~0, 32); 196 | if (remainingBits) 197 | shine_putbits(&config->bs, (1UL << remainingBits) - 1, remainingBits); 198 | } 199 | } 200 | 201 | static inline int shine_abs_and_sign(int *x) { 202 | if (*x > 0) 203 | return 0; 204 | *x *= -1; 205 | return 1; 206 | } 207 | 208 | static void shine_huffman_coder_count1(bitstream_t *bs, 209 | const struct huffcodetab *h, int v, 210 | int w, int x, int y) { 211 | unsigned int signv, signw, signx, signy; 212 | unsigned int code = 0; 213 | int p, cbits = 0; 214 | 215 | signv = shine_abs_and_sign(&v); 216 | signw = shine_abs_and_sign(&w); 217 | signx = shine_abs_and_sign(&x); 218 | signy = shine_abs_and_sign(&y); 219 | 220 | p = v + (w << 1) + (x << 2) + (y << 3); 221 | shine_putbits(bs, h->table[p], h->hlen[p]); 222 | 223 | if (v) { 224 | code = signv; 225 | cbits = 1; 226 | } 227 | if (w) { 228 | code = (code << 1) | signw; 229 | cbits++; 230 | } 231 | if (x) { 232 | code = (code << 1) | signx; 233 | cbits++; 234 | } 235 | if (y) { 236 | code = (code << 1) | signy; 237 | cbits++; 238 | } 239 | shine_putbits(bs, code, cbits); 240 | } 241 | 242 | /* Implements the pseudocode of page 98 of the IS */ 243 | static void shine_HuffmanCode(bitstream_t *bs, int table_select, int x, int y) { 244 | int cbits = 0, xbits = 0; 245 | unsigned int code = 0, ext = 0; 246 | unsigned signx, signy, ylen, idx; 247 | const struct huffcodetab *h; 248 | 249 | signx = shine_abs_and_sign(&x); 250 | signy = shine_abs_and_sign(&y); 251 | 252 | h = &(shine_huffman_table[table_select]); 253 | ylen = h->ylen; 254 | 255 | if (table_select > 15) { /* ESC-table is used */ 256 | unsigned linbitsx = 0, linbitsy = 0, linbits = h->linbits; 257 | 258 | if (x > 14) { 259 | linbitsx = x - 15; 260 | x = 15; 261 | } 262 | if (y > 14) { 263 | linbitsy = y - 15; 264 | y = 15; 265 | } 266 | 267 | idx = (x * ylen) + y; 268 | code = h->table[idx]; 269 | cbits = h->hlen[idx]; 270 | if (x > 14) { 271 | ext |= linbitsx; 272 | xbits += linbits; 273 | } 274 | if (x != 0) { 275 | ext <<= 1; 276 | ext |= signx; 277 | xbits += 1; 278 | } 279 | if (y > 14) { 280 | ext <<= linbits; 281 | ext |= linbitsy; 282 | xbits += linbits; 283 | } 284 | if (y != 0) { 285 | ext <<= 1; 286 | ext |= signy; 287 | xbits += 1; 288 | } 289 | 290 | shine_putbits(bs, code, cbits); 291 | shine_putbits(bs, ext, xbits); 292 | } else { /* No ESC-words */ 293 | idx = (x * ylen) + y; 294 | code = h->table[idx]; 295 | cbits = h->hlen[idx]; 296 | if (x != 0) { 297 | code <<= 1; 298 | code |= signx; 299 | cbits += 1; 300 | } 301 | if (y != 0) { 302 | code <<= 1; 303 | code |= signy; 304 | cbits += 1; 305 | } 306 | 307 | shine_putbits(bs, code, cbits); 308 | } 309 | } 310 | -------------------------------------------------------------------------------- /src/lib/l3bitstream.h: -------------------------------------------------------------------------------- 1 | #ifndef shine_BITSTREAM_H 2 | #define shine_BITSTREAM_H 3 | 4 | #include "types.h" 5 | 6 | void shine_format_bitstream(shine_global_config *config); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/lib/l3loop.c: -------------------------------------------------------------------------------- 1 | /* l3loop.c */ 2 | 3 | #include "l3loop.h" 4 | #include "bitstream.h" 5 | #include "huffman.h" 6 | #include "l3bitstream.h" 7 | #include "layer3.h" 8 | #include "reservoir.h" 9 | #include "tables.h" 10 | #include "types.h" 11 | 12 | #define e 2.71828182845 13 | #define CBLIMIT 21 14 | #define SFB_LMAX 22 15 | #define en_tot_krit 10 16 | #define en_dif_krit 100 17 | #define en_scfsi_band_krit 10 18 | #define xm_scfsi_band_krit 10 19 | 20 | static void calc_scfsi(shine_psy_xmin_t *l3_xmin, int ch, int gr, 21 | shine_global_config *config); 22 | static int part2_length(int gr, int ch, shine_global_config *config); 23 | static int bin_search_StepSize(int desired_rate, int ix[GRANULE_SIZE], 24 | gr_info *cod_info, shine_global_config *config); 25 | static int count_bit(int ix[GRANULE_SIZE], unsigned int start, unsigned int end, 26 | unsigned int table); 27 | static int bigv_bitcount(int ix[GRANULE_SIZE], gr_info *gi); 28 | static int new_choose_table(int ix[GRANULE_SIZE], unsigned int begin, 29 | unsigned int end); 30 | static void bigv_tab_select(int ix[GRANULE_SIZE], gr_info *cod_info); 31 | static void subdivide(gr_info *cod_info, shine_global_config *config); 32 | static int count1_bitcount(int ix[GRANULE_SIZE], gr_info *cod_info); 33 | static void calc_runlen(int ix[GRANULE_SIZE], gr_info *cod_info); 34 | static void calc_xmin(shine_psy_ratio_t *ratio, gr_info *cod_info, 35 | shine_psy_xmin_t *l3_xmin, int gr, int ch); 36 | static int quantize(int ix[GRANULE_SIZE], int stepsize, 37 | shine_global_config *config); 38 | 39 | /* 40 | * shine_inner_loop: 41 | * ---------- 42 | * The code selects the best quantizerStepSize for a particular set 43 | * of scalefacs. 44 | */ 45 | int shine_inner_loop(int ix[GRANULE_SIZE], int max_bits, gr_info *cod_info, 46 | int gr, int ch, shine_global_config *config) { 47 | int bits, c1bits, bvbits; 48 | 49 | if (max_bits < 0) 50 | cod_info->quantizerStepSize--; 51 | do { 52 | while (quantize(ix, ++cod_info->quantizerStepSize, config) > 8192) 53 | ; /* within table range? */ 54 | 55 | calc_runlen(ix, cod_info); /* rzero,count1,big_values*/ 56 | bits = c1bits = count1_bitcount(ix, cod_info); /* count1_table selection*/ 57 | subdivide(cod_info, config); /* bigvalues sfb division */ 58 | bigv_tab_select(ix, cod_info); /* codebook selection*/ 59 | bits += bvbits = bigv_bitcount(ix, cod_info); /* bit count */ 60 | } while (bits > max_bits); 61 | return bits; 62 | } 63 | 64 | /* 65 | * shine_outer_loop: 66 | * ----------- 67 | * Function: The outer iteration loop controls the masking conditions 68 | * of all scalefactorbands. It computes the best scalefac and 69 | * global gain. This module calls the inner iteration loop. 70 | */ 71 | 72 | int shine_outer_loop( 73 | int max_bits, 74 | shine_psy_xmin_t *l3_xmin, /* the allowed distortion of the scalefactor */ 75 | int ix[GRANULE_SIZE], /* vector of quantized values ix(0..575) */ 76 | int gr, int ch, shine_global_config *config) { 77 | int bits, huff_bits; 78 | shine_side_info_t *side_info = &config->side_info; 79 | gr_info *cod_info = &side_info->gr[gr].ch[ch].tt; 80 | 81 | cod_info->quantizerStepSize = 82 | bin_search_StepSize(max_bits, ix, cod_info, config); 83 | 84 | cod_info->part2_length = part2_length(gr, ch, config); 85 | huff_bits = max_bits - cod_info->part2_length; 86 | 87 | bits = shine_inner_loop(ix, huff_bits, cod_info, gr, ch, config); 88 | cod_info->part2_3_length = cod_info->part2_length + bits; 89 | 90 | return cod_info->part2_3_length; 91 | } 92 | 93 | /* 94 | * shine_iteration_loop: 95 | * ------------------ 96 | */ 97 | void shine_iteration_loop(shine_global_config *config) { 98 | shine_psy_xmin_t l3_xmin; 99 | gr_info *cod_info; 100 | int max_bits; 101 | int ch, gr, i; 102 | int *ix; 103 | 104 | for (ch = config->wave.channels; ch--;) { 105 | for (gr = 0; gr < config->mpeg.granules_per_frame; gr++) { 106 | /* setup pointers */ 107 | ix = config->l3_enc[ch][gr]; 108 | config->l3loop.xr = config->mdct_freq[ch][gr]; 109 | 110 | /* Precalculate the square, abs, and maximum, 111 | * for use later on. 112 | */ 113 | for (i = GRANULE_SIZE, config->l3loop.xrmax = 0; i--;) { 114 | config->l3loop.xrsq[i] = 115 | mulsr(config->l3loop.xr[i], config->l3loop.xr[i]); 116 | config->l3loop.xrabs[i] = labs(config->l3loop.xr[i]); 117 | if (config->l3loop.xrabs[i] > config->l3loop.xrmax) 118 | config->l3loop.xrmax = config->l3loop.xrabs[i]; 119 | } 120 | 121 | cod_info = (gr_info *)&(config->side_info.gr[gr].ch[ch]); 122 | cod_info->sfb_lmax = SFB_LMAX - 1; /* gr_deco */ 123 | 124 | calc_xmin(&config->ratio, cod_info, &l3_xmin, gr, ch); 125 | 126 | if (config->mpeg.version == MPEG_I) 127 | calc_scfsi(&l3_xmin, ch, gr, config); 128 | 129 | /* calculation of number of available bit( per granule ) */ 130 | max_bits = shine_max_reservoir_bits(&config->pe[ch][gr], config); 131 | 132 | /* reset of iteration variables */ 133 | memset(config->scalefactor.l[gr][ch], 0, 134 | sizeof(config->scalefactor.l[gr][ch])); 135 | memset(config->scalefactor.s[gr][ch], 0, 136 | sizeof(config->scalefactor.s[gr][ch])); 137 | 138 | for (i = 4; i--;) 139 | cod_info->slen[i] = 0; 140 | 141 | cod_info->part2_3_length = 0; 142 | cod_info->big_values = 0; 143 | cod_info->count1 = 0; 144 | cod_info->scalefac_compress = 0; 145 | cod_info->table_select[0] = 0; 146 | cod_info->table_select[1] = 0; 147 | cod_info->table_select[2] = 0; 148 | cod_info->region0_count = 0; 149 | cod_info->region1_count = 0; 150 | cod_info->part2_length = 0; 151 | cod_info->preflag = 0; 152 | cod_info->scalefac_scale = 0; 153 | cod_info->count1table_select = 0; 154 | 155 | /* all spectral values zero ? */ 156 | if (config->l3loop.xrmax) 157 | cod_info->part2_3_length = 158 | shine_outer_loop(max_bits, &l3_xmin, ix, gr, ch, config); 159 | 160 | shine_ResvAdjust(cod_info, config); 161 | cod_info->global_gain = cod_info->quantizerStepSize + 210; 162 | 163 | } /* for gr */ 164 | } /* for ch */ 165 | 166 | shine_ResvFrameEnd(config); 167 | } 168 | 169 | /* 170 | * calc_scfsi: 171 | * ----------- 172 | * calculation of the scalefactor select information ( scfsi ). 173 | */ 174 | void calc_scfsi(shine_psy_xmin_t *l3_xmin, int ch, int gr, 175 | shine_global_config *config) { 176 | shine_side_info_t *l3_side = &config->side_info; 177 | /* This is the scfsi_band table from 2.4.2.7 of the IS */ 178 | static const int scfsi_band_long[5] = {0, 6, 11, 16, 21}; 179 | 180 | int scfsi_band; 181 | 182 | int sfb, start, end, i; 183 | int condition = 0; 184 | int temp; 185 | 186 | const int *scalefac_band_long = 187 | &shine_scale_fact_band_index[config->mpeg.samplerate_index][0]; 188 | 189 | /* note. it goes quite a bit faster if you uncomment the next bit and exit 190 | early from scfsi, but you then loose the advantage of common scale factors. 191 | 192 | for(scfsi_band=0;scfsi_band<4;scfsi_band++) 193 | l3_side->scfsi[ch][scfsi_band] = 0; 194 | return; 195 | 196 | */ 197 | 198 | config->l3loop.xrmaxl[gr] = config->l3loop.xrmax; 199 | 200 | /* the total energy of the granule */ 201 | for (temp = 0, i = GRANULE_SIZE; i--;) 202 | temp += config->l3loop.xrsq[i] >> 203 | 10; /* a bit of scaling to avoid overflow, (not very good) */ 204 | if (temp) 205 | config->l3loop.en_tot[gr] = 206 | log((double)temp * 4.768371584e-7) / LN2; /* 1024 / 0x7fffffff */ 207 | else 208 | config->l3loop.en_tot[gr] = 0; 209 | 210 | /* the energy of each scalefactor band, en */ 211 | /* the allowed distortion of each scalefactor band, xm */ 212 | 213 | for (sfb = 21; sfb--;) { 214 | start = scalefac_band_long[sfb]; 215 | end = scalefac_band_long[sfb + 1]; 216 | 217 | for (temp = 0, i = start; i < end; i++) 218 | temp += config->l3loop.xrsq[i] >> 10; 219 | if (temp) 220 | config->l3loop.en[gr][sfb] = 221 | log((double)temp * 4.768371584e-7) / LN2; /* 1024 / 0x7fffffff */ 222 | else 223 | config->l3loop.en[gr][sfb] = 0; 224 | 225 | if (l3_xmin->l[gr][ch][sfb]) 226 | config->l3loop.xm[gr][sfb] = log(l3_xmin->l[gr][ch][sfb]) / LN2; 227 | else 228 | config->l3loop.xm[gr][sfb] = 0; 229 | } 230 | 231 | if (gr == 1) { 232 | int gr2, tp; 233 | 234 | for (gr2 = 2; gr2--;) { 235 | /* The spectral values are not all zero */ 236 | if (config->l3loop.xrmaxl[gr2]) 237 | condition++; 238 | 239 | condition++; 240 | } 241 | if (abs(config->l3loop.en_tot[0] - config->l3loop.en_tot[1]) < en_tot_krit) 242 | condition++; 243 | for (tp = 0, sfb = 21; sfb--;) 244 | tp += abs(config->l3loop.en[0][sfb] - config->l3loop.en[1][sfb]); 245 | if (tp < en_dif_krit) 246 | condition++; 247 | 248 | if (condition == 6) { 249 | for (scfsi_band = 0; scfsi_band < 4; scfsi_band++) { 250 | int sum0 = 0, sum1 = 0; 251 | l3_side->scfsi[ch][scfsi_band] = 0; 252 | start = scfsi_band_long[scfsi_band]; 253 | end = scfsi_band_long[scfsi_band + 1]; 254 | for (sfb = start; sfb < end; sfb++) { 255 | sum0 += abs(config->l3loop.en[0][sfb] - config->l3loop.en[1][sfb]); 256 | sum1 += abs(config->l3loop.xm[0][sfb] - config->l3loop.xm[1][sfb]); 257 | } 258 | 259 | if (sum0 < en_scfsi_band_krit && sum1 < xm_scfsi_band_krit) { 260 | l3_side->scfsi[ch][scfsi_band] = 1; 261 | } else 262 | l3_side->scfsi[ch][scfsi_band] = 0; 263 | } /* for scfsi_band */ 264 | } /* if condition == 6 */ 265 | else 266 | for (scfsi_band = 0; scfsi_band < 4; scfsi_band++) 267 | l3_side->scfsi[ch][scfsi_band] = 0; 268 | } /* if gr == 1 */ 269 | } 270 | 271 | /* 272 | * part2_length: 273 | * ------------- 274 | * calculates the number of bits needed to encode the scalefacs in the 275 | * main data block. 276 | */ 277 | int part2_length(int gr, int ch, shine_global_config *config) { 278 | int slen1, slen2, bits; 279 | gr_info *gi = &config->side_info.gr[gr].ch[ch].tt; 280 | 281 | bits = 0; 282 | 283 | { 284 | slen1 = shine_slen1_tab[gi->scalefac_compress]; 285 | slen2 = shine_slen2_tab[gi->scalefac_compress]; 286 | 287 | if (!gr || !(config->side_info.scfsi[ch][0])) 288 | bits += (6 * slen1); 289 | 290 | if (!gr || !(config->side_info.scfsi[ch][1])) 291 | bits += (5 * slen1); 292 | 293 | if (!gr || !(config->side_info.scfsi[ch][2])) 294 | bits += (5 * slen2); 295 | 296 | if (!gr || !(config->side_info.scfsi[ch][3])) 297 | bits += (5 * slen2); 298 | } 299 | return bits; 300 | } 301 | 302 | /* 303 | * calc_xmin: 304 | * ---------- 305 | * Calculate the allowed distortion for each scalefactor band, 306 | * as determined by the psychoacoustic model. 307 | * xmin(sb) = ratio(sb) * en(sb) / bw(sb) 308 | */ 309 | void calc_xmin(shine_psy_ratio_t *ratio, gr_info *cod_info, 310 | shine_psy_xmin_t *l3_xmin, int gr, int ch) { 311 | int sfb; 312 | 313 | for (sfb = cod_info->sfb_lmax; sfb--;) { 314 | /* note. xmin will always be zero with no psychoacoustic model 315 | 316 | start = scalefac_band_long[ sfb ]; 317 | end = scalefac_band_long[ sfb+1 ]; 318 | bw = end - start; 319 | 320 | for ( en = 0, l = start; l < end; l++ ) 321 | en += config->l3loop.xrsq[l]; 322 | 323 | l3_xmin->l[gr][ch][sfb] = ratio->l[gr][ch][sfb] * en / bw; 324 | */ 325 | l3_xmin->l[gr][ch][sfb] = 0; 326 | } 327 | } 328 | 329 | /* 330 | * shine_loop_initialise: 331 | * ------------------- 332 | * Calculates the look up tables used by the iteration loop. 333 | */ 334 | void shine_loop_initialise(shine_global_config *config) { 335 | int i; 336 | 337 | /* quantize: stepsize conversion, fourth root of 2 table. 338 | * The table is inverted (negative power) from the equation given 339 | * in the spec because it is quicker to do x*y than x/y. 340 | * The 0.5 is for rounding. 341 | */ 342 | for (i = 128; i--;) { 343 | config->l3loop.steptab[i] = pow(2.0, (double)(127 - i) / 4); 344 | if ((config->l3loop.steptab[i] * 2) > 345 | 0x7fffffff) /* MAXINT = 2**31 = 2**(124/4) */ 346 | config->l3loop.steptabi[i] = 0x7fffffff; 347 | else 348 | /* The table is multiplied by 2 to give an extra bit of accuracy. 349 | * In quantize, the long multiply does not shift it's result left one 350 | * bit to compensate. 351 | */ 352 | config->l3loop.steptabi[i] = 353 | (int32_t)((config->l3loop.steptab[i] * 2) + 0.5); 354 | } 355 | 356 | /* quantize: vector conversion, three quarter power table. 357 | * The 0.5 is for rounding, the .0946 comes from the spec. 358 | */ 359 | for (i = 10000; i--;) 360 | config->l3loop.int2idx[i] = 361 | (int)(sqrt(sqrt((double)i) * (double)i) - 0.0946 + 0.5); 362 | } 363 | 364 | /* 365 | * quantize: 366 | * --------- 367 | * Function: Quantization of the vector xr ( -> ix). 368 | * Returns maximum value of ix. 369 | */ 370 | int quantize(int ix[GRANULE_SIZE], int stepsize, shine_global_config *config) { 371 | int i, max, ln; 372 | int32_t scalei; 373 | double scale, dbl; 374 | 375 | scalei = config->l3loop.steptabi[stepsize + 127]; /* 2**(-stepsize/4) */ 376 | 377 | /* a quick check to see if ixmax will be less than 8192 */ 378 | /* this speeds up the early calls to bin_search_StepSize */ 379 | if ((mulr(config->l3loop.xrmax, scalei)) > 165140) /* 8192**(4/3) */ 380 | max = 16384; /* no point in continuing, stepsize not big enough */ 381 | else 382 | for (i = 0, max = 0; i < GRANULE_SIZE; i++) { 383 | /* This calculation is very sensitive. The multiply must round it's 384 | * result or bad things happen to the quality. 385 | */ 386 | ln = mulr(labs(config->l3loop.xr[i]), scalei); 387 | 388 | if (ln < 10000) /* ln < 10000 catches most values */ 389 | ix[i] = config->l3loop.int2idx[ln]; /* quick look up method */ 390 | else { 391 | /* outside table range so have to do it using floats */ 392 | scale = config->l3loop.steptab[stepsize + 127]; /* 2**(-stepsize/4) */ 393 | dbl = ((double)config->l3loop.xrabs[i]) * scale * 394 | 4.656612875e-10; /* 0x7fffffff */ 395 | ix[i] = (int)sqrt(sqrt(dbl) * dbl); /* dbl**(3/4) */ 396 | } 397 | 398 | /* calculate ixmax while we're here */ 399 | /* note. ix cannot be negative */ 400 | if (max < ix[i]) 401 | max = ix[i]; 402 | } 403 | 404 | return max; 405 | } 406 | 407 | /* 408 | * ix_max: 409 | * ------- 410 | * Function: Calculate the maximum of ix from 0 to 575 411 | */ 412 | static inline int ix_max(int ix[GRANULE_SIZE], unsigned int begin, 413 | unsigned int end) { 414 | register int i; 415 | register int max = 0; 416 | 417 | for (i = begin; i < end; i++) 418 | if (max < ix[i]) 419 | max = ix[i]; 420 | return max; 421 | } 422 | 423 | /* 424 | * calc_runlen: 425 | * ------------ 426 | * Function: Calculation of rzero, count1, big_values 427 | * (Partitions ix into big values, quadruples and zeros). 428 | */ 429 | void calc_runlen(int ix[GRANULE_SIZE], gr_info *cod_info) { 430 | int i; 431 | int rzero = 0; 432 | 433 | for (i = GRANULE_SIZE; i > 1; i -= 2) 434 | if (!ix[i - 1] && !ix[i - 2]) 435 | rzero++; 436 | else 437 | break; 438 | 439 | cod_info->count1 = 0; 440 | for (; i > 3; i -= 4) 441 | if (ix[i - 1] <= 1 && ix[i - 2] <= 1 && ix[i - 3] <= 1 && ix[i - 4] <= 1) 442 | cod_info->count1++; 443 | else 444 | break; 445 | 446 | cod_info->big_values = i >> 1; 447 | } 448 | 449 | /* 450 | * count1_bitcount: 451 | * ---------------- 452 | * Determines the number of bits to encode the quadruples. 453 | */ 454 | int count1_bitcount(int ix[GRANULE_SIZE], gr_info *cod_info) { 455 | int p, i, k; 456 | int v, w, x, y, signbits; 457 | int sum0 = 0, sum1 = 0; 458 | 459 | for (i = cod_info->big_values << 1, k = 0; k < cod_info->count1; 460 | i += 4, k++) { 461 | v = ix[i]; 462 | w = ix[i + 1]; 463 | x = ix[i + 2]; 464 | y = ix[i + 3]; 465 | 466 | p = v + (w << 1) + (x << 2) + (y << 3); 467 | 468 | signbits = 0; 469 | if (v != 0) 470 | signbits++; 471 | if (w != 0) 472 | signbits++; 473 | if (x != 0) 474 | signbits++; 475 | if (y != 0) 476 | signbits++; 477 | 478 | sum0 += signbits; 479 | sum1 += signbits; 480 | 481 | sum0 += shine_huffman_table[32].hlen[p]; 482 | sum1 += shine_huffman_table[33].hlen[p]; 483 | } 484 | 485 | if (sum0 < sum1) { 486 | cod_info->count1table_select = 0; 487 | return sum0; 488 | } else { 489 | cod_info->count1table_select = 1; 490 | return sum1; 491 | } 492 | } 493 | 494 | /* 495 | * subdivide: 496 | * ---------- 497 | * presumable subdivides the bigvalue region which will use separate Huffman 498 | * tables. 499 | */ 500 | void subdivide(gr_info *cod_info, shine_global_config *config) { 501 | static const struct { 502 | unsigned region0_count; 503 | unsigned region1_count; 504 | } subdv_table[23] = { 505 | {0, 0}, /* 0 bands */ 506 | {0, 0}, /* 1 bands */ 507 | {0, 0}, /* 2 bands */ 508 | {0, 0}, /* 3 bands */ 509 | {0, 0}, /* 4 bands */ 510 | {0, 1}, /* 5 bands */ 511 | {1, 1}, /* 6 bands */ 512 | {1, 1}, /* 7 bands */ 513 | {1, 2}, /* 8 bands */ 514 | {2, 2}, /* 9 bands */ 515 | {2, 3}, /* 10 bands */ 516 | {2, 3}, /* 11 bands */ 517 | {3, 4}, /* 12 bands */ 518 | {3, 4}, /* 13 bands */ 519 | {3, 4}, /* 14 bands */ 520 | {4, 5}, /* 15 bands */ 521 | {4, 5}, /* 16 bands */ 522 | {4, 6}, /* 17 bands */ 523 | {5, 6}, /* 18 bands */ 524 | {5, 6}, /* 19 bands */ 525 | {5, 7}, /* 20 bands */ 526 | {6, 7}, /* 21 bands */ 527 | {6, 7}, /* 22 bands */ 528 | }; 529 | 530 | if (!cod_info->big_values) { /* no big_values region */ 531 | cod_info->region0_count = 0; 532 | cod_info->region1_count = 0; 533 | } else { 534 | const int *scalefac_band_long = 535 | &shine_scale_fact_band_index[config->mpeg.samplerate_index][0]; 536 | int bigvalues_region, scfb_anz, thiscount; 537 | 538 | bigvalues_region = 2 * cod_info->big_values; 539 | 540 | /* Calculate scfb_anz */ 541 | scfb_anz = 0; 542 | while (scalefac_band_long[scfb_anz] < bigvalues_region) 543 | scfb_anz++; 544 | 545 | for (thiscount = subdv_table[scfb_anz].region0_count; thiscount; 546 | thiscount--) { 547 | if (scalefac_band_long[thiscount + 1] <= bigvalues_region) 548 | break; 549 | } 550 | cod_info->region0_count = thiscount; 551 | cod_info->address1 = scalefac_band_long[thiscount + 1]; 552 | 553 | scalefac_band_long += cod_info->region0_count + 1; 554 | 555 | for (thiscount = subdv_table[scfb_anz].region1_count; thiscount; 556 | thiscount--) { 557 | if (scalefac_band_long[thiscount + 1] <= bigvalues_region) 558 | break; 559 | } 560 | cod_info->region1_count = thiscount; 561 | cod_info->address2 = scalefac_band_long[thiscount + 1]; 562 | 563 | cod_info->address3 = bigvalues_region; 564 | } 565 | } 566 | 567 | /* 568 | * bigv_tab_select: 569 | * ---------------- 570 | * Function: Select huffman code tables for bigvalues regions 571 | */ 572 | void bigv_tab_select(int ix[GRANULE_SIZE], gr_info *cod_info) { 573 | cod_info->table_select[0] = 0; 574 | cod_info->table_select[1] = 0; 575 | cod_info->table_select[2] = 0; 576 | 577 | { 578 | if (cod_info->address1 > 0) 579 | cod_info->table_select[0] = new_choose_table(ix, 0, cod_info->address1); 580 | 581 | if (cod_info->address2 > cod_info->address1) 582 | cod_info->table_select[1] = 583 | new_choose_table(ix, cod_info->address1, cod_info->address2); 584 | 585 | if (cod_info->big_values << 1 > cod_info->address2) 586 | cod_info->table_select[2] = 587 | new_choose_table(ix, cod_info->address2, cod_info->big_values << 1); 588 | } 589 | } 590 | 591 | /* 592 | * new_choose_table: 593 | * ----------------- 594 | * Choose the Huffman table that will encode ix[begin..end] with 595 | * the fewest bits. 596 | * Note: This code contains knowledge about the sizes and characteristics 597 | * of the Huffman tables as defined in the IS (Table B.7), and will not work 598 | * with any arbitrary tables. 599 | */ 600 | int new_choose_table(int ix[GRANULE_SIZE], unsigned int begin, 601 | unsigned int end) { 602 | int i, max; 603 | int choice[2]; 604 | int sum[2]; 605 | 606 | max = ix_max(ix, begin, end); 607 | if (!max) 608 | return 0; 609 | 610 | choice[0] = 0; 611 | choice[1] = 0; 612 | 613 | if (max < 15) { 614 | /* try tables with no linbits */ 615 | for (i = 14; i--;) 616 | if (shine_huffman_table[i].xlen > max) { 617 | choice[0] = i; 618 | break; 619 | } 620 | 621 | sum[0] = count_bit(ix, begin, end, choice[0]); 622 | 623 | switch (choice[0]) { 624 | case 2: 625 | sum[1] = count_bit(ix, begin, end, 3); 626 | if (sum[1] <= sum[0]) 627 | choice[0] = 3; 628 | break; 629 | 630 | case 5: 631 | sum[1] = count_bit(ix, begin, end, 6); 632 | if (sum[1] <= sum[0]) 633 | choice[0] = 6; 634 | break; 635 | 636 | case 7: 637 | sum[1] = count_bit(ix, begin, end, 8); 638 | if (sum[1] <= sum[0]) { 639 | choice[0] = 8; 640 | sum[0] = sum[1]; 641 | } 642 | sum[1] = count_bit(ix, begin, end, 9); 643 | if (sum[1] <= sum[0]) 644 | choice[0] = 9; 645 | break; 646 | 647 | case 10: 648 | sum[1] = count_bit(ix, begin, end, 11); 649 | if (sum[1] <= sum[0]) { 650 | choice[0] = 11; 651 | sum[0] = sum[1]; 652 | } 653 | sum[1] = count_bit(ix, begin, end, 12); 654 | if (sum[1] <= sum[0]) 655 | choice[0] = 12; 656 | break; 657 | 658 | case 13: 659 | sum[1] = count_bit(ix, begin, end, 15); 660 | if (sum[1] <= sum[0]) 661 | choice[0] = 15; 662 | break; 663 | } 664 | } else { 665 | /* try tables with linbits */ 666 | max -= 15; 667 | 668 | for (i = 15; i < 24; i++) 669 | if (shine_huffman_table[i].linmax >= max) { 670 | choice[0] = i; 671 | break; 672 | } 673 | 674 | for (i = 24; i < 32; i++) 675 | if (shine_huffman_table[i].linmax >= max) { 676 | choice[1] = i; 677 | break; 678 | } 679 | 680 | sum[0] = count_bit(ix, begin, end, choice[0]); 681 | sum[1] = count_bit(ix, begin, end, choice[1]); 682 | if (sum[1] < sum[0]) 683 | choice[0] = choice[1]; 684 | } 685 | return choice[0]; 686 | } 687 | 688 | /* 689 | * bigv_bitcount: 690 | * -------------- 691 | * Function: Count the number of bits necessary to code the bigvalues region. 692 | */ 693 | int bigv_bitcount(int ix[GRANULE_SIZE], gr_info *gi) { 694 | int bits = 0; 695 | unsigned int table; 696 | 697 | if ((table = gi->table_select[0])) /* region0 */ 698 | bits += count_bit(ix, 0, gi->address1, table); 699 | if ((table = gi->table_select[1])) /* region1 */ 700 | bits += count_bit(ix, gi->address1, gi->address2, table); 701 | if ((table = gi->table_select[2])) /* region2 */ 702 | bits += count_bit(ix, gi->address2, gi->address3, table); 703 | return bits; 704 | } 705 | 706 | /* 707 | * count_bit: 708 | * ---------- 709 | * Function: Count the number of bits necessary to code the subregion. 710 | */ 711 | int count_bit(int ix[GRANULE_SIZE], unsigned int start, unsigned int end, 712 | unsigned int table) { 713 | unsigned linbits, ylen; 714 | register int i, sum; 715 | register int x, y; 716 | const struct huffcodetab *h; 717 | 718 | if (!table) 719 | return 0; 720 | 721 | h = &(shine_huffman_table[table]); 722 | sum = 0; 723 | 724 | ylen = h->ylen; 725 | linbits = h->linbits; 726 | 727 | if (table > 15) { /* ESC-table is used */ 728 | for (i = start; i < end; i += 2) { 729 | x = ix[i]; 730 | y = ix[i + 1]; 731 | if (x > 14) { 732 | x = 15; 733 | sum += linbits; 734 | } 735 | if (y > 14) { 736 | y = 15; 737 | sum += linbits; 738 | } 739 | 740 | sum += h->hlen[(x * ylen) + y]; 741 | if (x) 742 | sum++; 743 | if (y) 744 | sum++; 745 | } 746 | } else { /* No ESC-words */ 747 | for (i = start; i < end; i += 2) { 748 | x = ix[i]; 749 | y = ix[i + 1]; 750 | 751 | sum += h->hlen[(x * ylen) + y]; 752 | 753 | if (x != 0) 754 | sum++; 755 | if (y != 0) 756 | sum++; 757 | } 758 | } 759 | return sum; 760 | } 761 | 762 | /* 763 | * bin_search_StepSize: 764 | * -------------------- 765 | * Succesive approximation approach to obtaining a initial quantizer 766 | * step size. 767 | * The following optional code written by Seymour Shlien 768 | * will speed up the shine_outer_loop code which is called 769 | * by iteration_loop. When BIN_SEARCH is defined, the 770 | * shine_outer_loop function precedes the call to the function shine_inner_loop 771 | * with a call to bin_search gain defined below, which 772 | * returns a good starting quantizerStepSize. 773 | */ 774 | int bin_search_StepSize(int desired_rate, int ix[GRANULE_SIZE], 775 | gr_info *cod_info, shine_global_config *config) { 776 | int bit, next, count; 777 | 778 | next = -120; 779 | count = 120; 780 | 781 | do { 782 | int half = count / 2; 783 | 784 | if (quantize(ix, next + half, config) > 8192) 785 | bit = 100000; /* fail */ 786 | else { 787 | calc_runlen(ix, cod_info); /* rzero,count1,big_values */ 788 | bit = count1_bitcount(ix, cod_info); /* count1_table selection */ 789 | subdivide(cod_info, config); /* bigvalues sfb division */ 790 | bigv_tab_select(ix, cod_info); /* codebook selection */ 791 | bit += bigv_bitcount(ix, cod_info); /* bit count */ 792 | } 793 | 794 | if (bit < desired_rate) 795 | count = half; 796 | else { 797 | next += half; 798 | count -= half; 799 | } 800 | } while (count > 1); 801 | 802 | return next; 803 | } 804 | -------------------------------------------------------------------------------- /src/lib/l3loop.h: -------------------------------------------------------------------------------- 1 | #ifndef L3LOOP_H 2 | #define L3LOOP_H 3 | 4 | #include "types.h" 5 | 6 | void shine_loop_initialise(shine_global_config *config); 7 | 8 | void shine_iteration_loop(shine_global_config *config); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/lib/l3mdct.c: -------------------------------------------------------------------------------- 1 | /* L3mdct */ 2 | 3 | #include "l3mdct.h" 4 | #include "l3subband.h" 5 | #include "types.h" 6 | 7 | /* This is table B.9: coefficients for aliasing reduction */ 8 | #define MDCT_CA(coef) (int32_t)(coef / sqrt(1.0 + (coef * coef)) * 0x7fffffff) 9 | #define MDCT_CS(coef) (int32_t)(1.0 / sqrt(1.0 + (coef * coef)) * 0x7fffffff) 10 | 11 | #define MDCT_CA0 MDCT_CA(-0.6) 12 | #define MDCT_CA1 MDCT_CA(-0.535) 13 | #define MDCT_CA2 MDCT_CA(-0.33) 14 | #define MDCT_CA3 MDCT_CA(-0.185) 15 | #define MDCT_CA4 MDCT_CA(-0.095) 16 | #define MDCT_CA5 MDCT_CA(-0.041) 17 | #define MDCT_CA6 MDCT_CA(-0.0142) 18 | #define MDCT_CA7 MDCT_CA(-0.0037) 19 | 20 | #define MDCT_CS0 MDCT_CS(-0.6) 21 | #define MDCT_CS1 MDCT_CS(-0.535) 22 | #define MDCT_CS2 MDCT_CS(-0.33) 23 | #define MDCT_CS3 MDCT_CS(-0.185) 24 | #define MDCT_CS4 MDCT_CS(-0.095) 25 | #define MDCT_CS5 MDCT_CS(-0.041) 26 | #define MDCT_CS6 MDCT_CS(-0.0142) 27 | #define MDCT_CS7 MDCT_CS(-0.0037) 28 | 29 | /* 30 | * shine_mdct_initialise: 31 | * ------------------- 32 | */ 33 | void shine_mdct_initialise(shine_global_config *config) { 34 | int m, k; 35 | 36 | /* prepare the mdct coefficients */ 37 | for (m = 18; m--;) 38 | for (k = 36; k--;) 39 | /* combine window and mdct coefficients into a single table */ 40 | /* scale and convert to fixed point before storing */ 41 | config->mdct.cos_l[m][k] = 42 | (int32_t)(sin(PI36 * (k + 0.5)) * 43 | cos((PI / 72) * (2 * k + 19) * (2 * m + 1)) * 0x7fffffff); 44 | } 45 | 46 | /* 47 | * shine_mdct_sub: 48 | * ------------ 49 | */ 50 | void shine_mdct_sub(shine_global_config *config, int stride) { 51 | /* note. we wish to access the array 'config->mdct_freq[2][2][576]' as 52 | * [2][2][32][18]. (32*18=576), 53 | */ 54 | int32_t(*mdct_enc)[18]; 55 | 56 | int ch, gr, band, j, k; 57 | int32_t mdct_in[36]; 58 | 59 | for (ch = config->wave.channels; ch--;) { 60 | for (gr = 0; gr < config->mpeg.granules_per_frame; gr++) { 61 | /* set up pointer to the part of config->mdct_freq we're using */ 62 | mdct_enc = (int32_t(*)[18])config->mdct_freq[ch][gr]; 63 | 64 | /* polyphase filtering */ 65 | for (k = 0; k < 18; k += 2) { 66 | shine_window_filter_subband(&config->buffer[ch], 67 | &config->l3_sb_sample[ch][gr + 1][k][0], ch, 68 | config, stride); 69 | shine_window_filter_subband(&config->buffer[ch], 70 | &config->l3_sb_sample[ch][gr + 1][k + 1][0], 71 | ch, config, stride); 72 | /* Compensate for inversion in the analysis filter 73 | * (every odd index of band AND k) 74 | */ 75 | for (band = 1; band < 32; band += 2) 76 | config->l3_sb_sample[ch][gr + 1][k + 1][band] *= -1; 77 | } 78 | 79 | /* Perform imdct of 18 previous subband samples + 18 current subband 80 | * samples */ 81 | for (band = 0; band < 32; band++) { 82 | for (k = 18; k--;) { 83 | mdct_in[k] = config->l3_sb_sample[ch][gr][k][band]; 84 | mdct_in[k + 18] = config->l3_sb_sample[ch][gr + 1][k][band]; 85 | } 86 | 87 | /* Calculation of the MDCT 88 | * In the case of long blocks ( block_type 0,1,3 ) there are 89 | * 36 coefficients in the time domain and 18 in the frequency 90 | * domain. 91 | */ 92 | for (k = 18; k--;) { 93 | int32_t vm; 94 | #ifdef __BORLANDC__ 95 | uint32_t vm_lo; 96 | #else 97 | uint32_t vm_lo __attribute__((unused)); 98 | #endif 99 | 100 | mul0(vm, vm_lo, mdct_in[35], config->mdct.cos_l[k][35]); 101 | for (j = 35; j; j -= 7) { 102 | muladd(vm, vm_lo, mdct_in[j - 1], config->mdct.cos_l[k][j - 1]); 103 | muladd(vm, vm_lo, mdct_in[j - 2], config->mdct.cos_l[k][j - 2]); 104 | muladd(vm, vm_lo, mdct_in[j - 3], config->mdct.cos_l[k][j - 3]); 105 | muladd(vm, vm_lo, mdct_in[j - 4], config->mdct.cos_l[k][j - 4]); 106 | muladd(vm, vm_lo, mdct_in[j - 5], config->mdct.cos_l[k][j - 5]); 107 | muladd(vm, vm_lo, mdct_in[j - 6], config->mdct.cos_l[k][j - 6]); 108 | muladd(vm, vm_lo, mdct_in[j - 7], config->mdct.cos_l[k][j - 7]); 109 | } 110 | mulz(vm, vm_lo); 111 | mdct_enc[band][k] = vm; 112 | } 113 | 114 | /* Perform aliasing reduction butterfly */ 115 | if (band != 0) { 116 | cmuls(mdct_enc[band][0], mdct_enc[band - 1][17 - 0], 117 | mdct_enc[band][0], mdct_enc[band - 1][17 - 0], MDCT_CS0, 118 | MDCT_CA0); 119 | cmuls(mdct_enc[band][1], mdct_enc[band - 1][17 - 1], 120 | mdct_enc[band][1], mdct_enc[band - 1][17 - 1], MDCT_CS1, 121 | MDCT_CA1); 122 | cmuls(mdct_enc[band][2], mdct_enc[band - 1][17 - 2], 123 | mdct_enc[band][2], mdct_enc[band - 1][17 - 2], MDCT_CS2, 124 | MDCT_CA2); 125 | cmuls(mdct_enc[band][3], mdct_enc[band - 1][17 - 3], 126 | mdct_enc[band][3], mdct_enc[band - 1][17 - 3], MDCT_CS3, 127 | MDCT_CA3); 128 | cmuls(mdct_enc[band][4], mdct_enc[band - 1][17 - 4], 129 | mdct_enc[band][4], mdct_enc[band - 1][17 - 4], MDCT_CS4, 130 | MDCT_CA4); 131 | cmuls(mdct_enc[band][5], mdct_enc[band - 1][17 - 5], 132 | mdct_enc[band][5], mdct_enc[band - 1][17 - 5], MDCT_CS5, 133 | MDCT_CA5); 134 | cmuls(mdct_enc[band][6], mdct_enc[band - 1][17 - 6], 135 | mdct_enc[band][6], mdct_enc[band - 1][17 - 6], MDCT_CS6, 136 | MDCT_CA6); 137 | cmuls(mdct_enc[band][7], mdct_enc[band - 1][17 - 7], 138 | mdct_enc[band][7], mdct_enc[band - 1][17 - 7], MDCT_CS7, 139 | MDCT_CA7); 140 | } 141 | } 142 | } 143 | 144 | /* Save latest granule's subband samples to be used in the next mdct call */ 145 | memcpy(config->l3_sb_sample[ch][0], 146 | config->l3_sb_sample[ch][config->mpeg.granules_per_frame], 147 | sizeof(config->l3_sb_sample[0][0])); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/lib/l3mdct.h: -------------------------------------------------------------------------------- 1 | #ifndef shine_MDCT_H 2 | #define shine_MDCT_H 3 | 4 | #include "types.h" 5 | 6 | void shine_mdct_initialise(shine_global_config *config); 7 | void shine_mdct_sub(shine_global_config *config, int stride); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/lib/l3subband.c: -------------------------------------------------------------------------------- 1 | /* L3SubBand */ 2 | 3 | #include "l3subband.h" 4 | #include "tables.h" 5 | #include "types.h" 6 | 7 | /* 8 | * shine_subband_initialise: 9 | * ---------------------- 10 | * Calculates the analysis filterbank coefficients and rounds to the 11 | * 9th decimal place accuracy of the filterbank tables in the ISO 12 | * document. The coefficients are stored in #filter# 13 | */ 14 | void shine_subband_initialise(shine_global_config *config) { 15 | int i, j; 16 | double filter; 17 | 18 | for (i = MAX_CHANNELS; i--;) { 19 | config->subband.off[i] = 0; 20 | memset(config->subband.x[i], 0, sizeof(config->subband.x[i])); 21 | } 22 | 23 | for (i = SBLIMIT; i--;) 24 | for (j = 64; j--;) { 25 | if ((filter = 1e9 * cos((double)((2 * i + 1) * (16 - j) * PI64))) >= 0) 26 | modf(filter + 0.5, &filter); 27 | else 28 | modf(filter - 0.5, &filter); 29 | /* scale and convert to fixed point before storing */ 30 | config->subband.fl[i][j] = (int32_t)(filter * (0x7fffffff * 1e-9)); 31 | } 32 | } 33 | 34 | /* 35 | * shine_window_filter_subband: 36 | * ------------------------- 37 | * Overlapping window on PCM samples 38 | * 32 16-bit pcm samples are scaled to fractional 2's complement and 39 | * concatenated to the end of the window buffer #x#. The updated window 40 | * buffer #x# is then windowed by the analysis window #shine_enwindow# to 41 | * produce the windowed sample #z# Calculates the analysis filter bank 42 | * coefficients The windowed samples #z# is filtered by the digital filter 43 | * matrix #filter# to produce the subband samples #s#. This done by first 44 | * selectively picking out values from the windowed samples, and then 45 | * multiplying them by the filter matrix, producing 32 subband samples. 46 | */ 47 | void shine_window_filter_subband(int16_t **buffer, int32_t s[SBLIMIT], int ch, 48 | shine_global_config *config, int stride) { 49 | int32_t y[64]; 50 | int i, j; 51 | int16_t *ptr = *buffer; 52 | 53 | /* replace 32 oldest samples with 32 new samples */ 54 | for (i = 32; i--;) { 55 | config->subband.x[ch][i + config->subband.off[ch]] = ((int32_t)*ptr) << 16; 56 | ptr += stride; 57 | } 58 | *buffer = ptr; 59 | 60 | for (i = 64; i--;) { 61 | int32_t s_value; 62 | #ifdef __BORLANDC__ 63 | uint32_t s_value_lo; 64 | #else 65 | uint32_t s_value_lo __attribute__((unused)); 66 | #endif 67 | 68 | mul0(s_value, s_value_lo, 69 | config->subband 70 | .x[ch][(config->subband.off[ch] + i + (0 << 6)) & (HAN_SIZE - 1)], 71 | shine_enwindow[i + (0 << 6)]); 72 | muladd(s_value, s_value_lo, 73 | config->subband.x[ch][(config->subband.off[ch] + i + (1 << 6)) & 74 | (HAN_SIZE - 1)], 75 | shine_enwindow[i + (1 << 6)]); 76 | muladd(s_value, s_value_lo, 77 | config->subband.x[ch][(config->subband.off[ch] + i + (2 << 6)) & 78 | (HAN_SIZE - 1)], 79 | shine_enwindow[i + (2 << 6)]); 80 | muladd(s_value, s_value_lo, 81 | config->subband.x[ch][(config->subband.off[ch] + i + (3 << 6)) & 82 | (HAN_SIZE - 1)], 83 | shine_enwindow[i + (3 << 6)]); 84 | muladd(s_value, s_value_lo, 85 | config->subband.x[ch][(config->subband.off[ch] + i + (4 << 6)) & 86 | (HAN_SIZE - 1)], 87 | shine_enwindow[i + (4 << 6)]); 88 | muladd(s_value, s_value_lo, 89 | config->subband.x[ch][(config->subband.off[ch] + i + (5 << 6)) & 90 | (HAN_SIZE - 1)], 91 | shine_enwindow[i + (5 << 6)]); 92 | muladd(s_value, s_value_lo, 93 | config->subband.x[ch][(config->subband.off[ch] + i + (6 << 6)) & 94 | (HAN_SIZE - 1)], 95 | shine_enwindow[i + (6 << 6)]); 96 | muladd(s_value, s_value_lo, 97 | config->subband.x[ch][(config->subband.off[ch] + i + (7 << 6)) & 98 | (HAN_SIZE - 1)], 99 | shine_enwindow[i + (7 << 6)]); 100 | mulz(s_value, s_value_lo); 101 | y[i] = s_value; 102 | } 103 | 104 | config->subband.off[ch] = (config->subband.off[ch] + 480) & 105 | (HAN_SIZE - 1); /* offset is modulo (HAN_SIZE)*/ 106 | 107 | for (i = SBLIMIT; i--;) { 108 | int32_t s_value; 109 | #ifdef __BORLANDC__ 110 | uint32_t s_value_lo; 111 | #else 112 | uint32_t s_value_lo __attribute__((unused)); 113 | #endif 114 | 115 | mul0(s_value, s_value_lo, config->subband.fl[i][63], y[63]); 116 | for (j = 63; j; j -= 7) { 117 | muladd(s_value, s_value_lo, config->subband.fl[i][j - 1], y[j - 1]); 118 | muladd(s_value, s_value_lo, config->subband.fl[i][j - 2], y[j - 2]); 119 | muladd(s_value, s_value_lo, config->subband.fl[i][j - 3], y[j - 3]); 120 | muladd(s_value, s_value_lo, config->subband.fl[i][j - 4], y[j - 4]); 121 | muladd(s_value, s_value_lo, config->subband.fl[i][j - 5], y[j - 5]); 122 | muladd(s_value, s_value_lo, config->subband.fl[i][j - 6], y[j - 6]); 123 | muladd(s_value, s_value_lo, config->subband.fl[i][j - 7], y[j - 7]); 124 | } 125 | mulz(s_value, s_value_lo); 126 | s[i] = s_value; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/lib/l3subband.h: -------------------------------------------------------------------------------- 1 | #ifndef L3SUBBAND_H 2 | #define L3SUBBAND_H 3 | 4 | #include "types.h" 5 | #include 6 | 7 | void shine_subband_initialise(shine_global_config *config); 8 | void shine_window_filter_subband(int16_t **buffer, int32_t s[SBLIMIT], int k, 9 | shine_global_config *config, int stride); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/lib/layer3.c: -------------------------------------------------------------------------------- 1 | /* layer3.c */ 2 | 3 | #include "layer3.h" 4 | #include "bitstream.h" 5 | #include "l3bitstream.h" 6 | #include "l3loop.h" 7 | #include "l3mdct.h" 8 | #include "l3subband.h" 9 | #include "tables.h" 10 | #include "types.h" 11 | 12 | static int granules_per_frame[4] = { 13 | 1, /* MPEG 2.5 */ 14 | -1, /* Reserved */ 15 | 1, /* MPEG II */ 16 | 2 /* MPEG I */ 17 | }; 18 | 19 | /* Set default values for important vars */ 20 | void shine_set_config_mpeg_defaults(shine_mpeg_t *mpeg) { 21 | mpeg->bitr = 128; 22 | mpeg->emph = NONE; 23 | mpeg->copyright = 0; 24 | mpeg->original = 1; 25 | } 26 | 27 | int shine_mpeg_version(int samplerate_index) { 28 | /* Pick mpeg version according to samplerate index. */ 29 | if (samplerate_index < 3) 30 | /* First 3 samplerates are for MPEG-I */ 31 | return MPEG_I; 32 | else if (samplerate_index < 6) 33 | /* Then it's MPEG-II */ 34 | return MPEG_II; 35 | else 36 | /* Finally, MPEG-2.5 */ 37 | return MPEG_25; 38 | } 39 | 40 | int shine_find_samplerate_index(int freq) { 41 | int i; 42 | 43 | for (i = 0; i < 9; i++) 44 | if (freq == samplerates[i]) 45 | return i; 46 | 47 | return -1; /* error - not a valid samplerate for encoder */ 48 | } 49 | 50 | int shine_find_bitrate_index(int bitr, int mpeg_version) { 51 | int i; 52 | 53 | for (i = 0; i < 16; i++) 54 | if (bitr == bitrates[i][mpeg_version]) 55 | return i; 56 | 57 | return -1; /* error - not a valid samplerate for encoder */ 58 | } 59 | 60 | int shine_check_config(int freq, int bitr) { 61 | int samplerate_index, bitrate_index, mpeg_version; 62 | 63 | samplerate_index = shine_find_samplerate_index(freq); 64 | if (samplerate_index < 0) 65 | return -1; 66 | 67 | mpeg_version = shine_mpeg_version(samplerate_index); 68 | 69 | bitrate_index = shine_find_bitrate_index(bitr, mpeg_version); 70 | if (bitrate_index < 0) 71 | return -1; 72 | 73 | return mpeg_version; 74 | } 75 | 76 | int shine_samples_per_pass(shine_t s) { 77 | return s->mpeg.granules_per_frame * GRANULE_SIZE; 78 | } 79 | 80 | /* Compute default encoding values. */ 81 | shine_global_config *shine_initialise(shine_config_t *pub_config) { 82 | double avg_slots_per_frame; 83 | shine_global_config *config; 84 | 85 | if (shine_check_config(pub_config->wave.samplerate, pub_config->mpeg.bitr) < 86 | 0) 87 | return NULL; 88 | 89 | config = calloc(1, sizeof(shine_global_config)); 90 | if (config == NULL) 91 | return config; 92 | 93 | shine_subband_initialise(config); 94 | shine_mdct_initialise(config); 95 | shine_loop_initialise(config); 96 | 97 | /* Copy public config. */ 98 | config->wave.channels = pub_config->wave.channels; 99 | config->wave.samplerate = pub_config->wave.samplerate; 100 | config->mpeg.mode = pub_config->mpeg.mode; 101 | config->mpeg.bitr = pub_config->mpeg.bitr; 102 | config->mpeg.emph = pub_config->mpeg.emph; 103 | config->mpeg.copyright = pub_config->mpeg.copyright; 104 | config->mpeg.original = pub_config->mpeg.original; 105 | 106 | /* Set default values. */ 107 | config->ResvMax = 0; 108 | config->ResvSize = 0; 109 | config->mpeg.layer = LAYER_III; 110 | config->mpeg.crc = 0; 111 | config->mpeg.ext = 0; 112 | config->mpeg.mode_ext = 0; 113 | config->mpeg.bits_per_slot = 8; 114 | 115 | config->mpeg.samplerate_index = 116 | shine_find_samplerate_index(config->wave.samplerate); 117 | config->mpeg.version = shine_mpeg_version(config->mpeg.samplerate_index); 118 | config->mpeg.bitrate_index = 119 | shine_find_bitrate_index(config->mpeg.bitr, config->mpeg.version); 120 | config->mpeg.granules_per_frame = granules_per_frame[config->mpeg.version]; 121 | 122 | /* Figure average number of 'slots' per frame. */ 123 | avg_slots_per_frame = 124 | ((double)config->mpeg.granules_per_frame * GRANULE_SIZE / 125 | ((double)config->wave.samplerate)) * 126 | (1000 * (double)config->mpeg.bitr / (double)config->mpeg.bits_per_slot); 127 | 128 | config->mpeg.whole_slots_per_frame = (int)avg_slots_per_frame; 129 | 130 | config->mpeg.frac_slots_per_frame = 131 | avg_slots_per_frame - (double)config->mpeg.whole_slots_per_frame; 132 | config->mpeg.slot_lag = -config->mpeg.frac_slots_per_frame; 133 | 134 | if (config->mpeg.frac_slots_per_frame == 0) 135 | config->mpeg.padding = 0; 136 | 137 | shine_open_bit_stream(&config->bs, BUFFER_SIZE); 138 | 139 | memset((char *)&config->side_info, 0, sizeof(shine_side_info_t)); 140 | 141 | /* determine the mean bitrate for main data */ 142 | if (config->mpeg.granules_per_frame == 2) /* MPEG 1 */ 143 | config->sideinfo_len = 8 * ((config->wave.channels == 1) ? 4 + 17 : 4 + 32); 144 | else /* MPEG 2 */ 145 | config->sideinfo_len = 8 * ((config->wave.channels == 1) ? 4 + 9 : 4 + 17); 146 | 147 | return config; 148 | } 149 | 150 | static unsigned char *shine_encode_buffer_internal(shine_global_config *config, 151 | int *written, int stride) { 152 | if (config->mpeg.frac_slots_per_frame) { 153 | config->mpeg.padding = 154 | (config->mpeg.slot_lag <= (config->mpeg.frac_slots_per_frame - 1.0)); 155 | config->mpeg.slot_lag += 156 | (config->mpeg.padding - config->mpeg.frac_slots_per_frame); 157 | } 158 | 159 | config->mpeg.bits_per_frame = 160 | 8 * (config->mpeg.whole_slots_per_frame + config->mpeg.padding); 161 | config->mean_bits = (config->mpeg.bits_per_frame - config->sideinfo_len) / 162 | config->mpeg.granules_per_frame; 163 | 164 | /* apply mdct to the polyphase output */ 165 | shine_mdct_sub(config, stride); 166 | 167 | /* bit and noise allocation */ 168 | shine_iteration_loop(config); 169 | 170 | /* write the frame to the bitstream */ 171 | shine_format_bitstream(config); 172 | 173 | /* Return data. */ 174 | *written = config->bs.data_position; 175 | config->bs.data_position = 0; 176 | 177 | return config->bs.data; 178 | } 179 | 180 | unsigned char *shine_encode_buffer(shine_global_config *config, int16_t **data, 181 | int *written) { 182 | config->buffer[0] = data[0]; 183 | if (config->wave.channels == 2) 184 | config->buffer[1] = data[1]; 185 | 186 | return shine_encode_buffer_internal(config, written, 1); 187 | } 188 | 189 | unsigned char *shine_encode_buffer_interleaved(shine_global_config *config, 190 | int16_t *data, int *written) { 191 | config->buffer[0] = data; 192 | if (config->wave.channels == 2) 193 | config->buffer[1] = data + 1; 194 | 195 | return shine_encode_buffer_internal(config, written, config->wave.channels); 196 | } 197 | 198 | unsigned char *shine_flush(shine_global_config *config, int *written) { 199 | *written = config->bs.data_position; 200 | config->bs.data_position = 0; 201 | 202 | return config->bs.data; 203 | } 204 | 205 | void shine_close(shine_global_config *config) { 206 | shine_close_bit_stream(&config->bs); 207 | free(config); 208 | } 209 | -------------------------------------------------------------------------------- /src/lib/layer3.h: -------------------------------------------------------------------------------- 1 | #ifndef LAYER3_H 2 | #define LAYER3_H 3 | 4 | #include 5 | 6 | /* This is the struct used to tell the encoder about the input PCM */ 7 | 8 | enum channels { PCM_MONO = 1, PCM_STEREO = 2 }; 9 | 10 | enum mpeg_versions { MPEG_I = 3, MPEG_II = 2, MPEG_25 = 0 }; 11 | 12 | /* Only Layer III currently implemented. */ 13 | enum mpeg_layers { LAYER_III = 1 }; 14 | 15 | typedef struct { 16 | enum channels channels; 17 | int samplerate; 18 | } shine_wave_t; 19 | 20 | /* This is the struct the encoder uses to tell the encoder about the output MP3 21 | */ 22 | 23 | enum modes { STEREO = 0, JOINT_STEREO = 1, DUAL_CHANNEL = 2, MONO = 3 }; 24 | 25 | enum emph { NONE = 0, MU50_15 = 1, CITT = 3 }; 26 | 27 | typedef struct { 28 | enum modes mode; /* Stereo mode */ 29 | int bitr; /* Must conform to known bitrate */ 30 | enum emph emph; /* De-emphasis */ 31 | int copyright; 32 | int original; 33 | } shine_mpeg_t; 34 | 35 | typedef struct { 36 | shine_wave_t wave; 37 | shine_mpeg_t mpeg; 38 | } shine_config_t; 39 | 40 | /* Tables of supported audio parameters & format. 41 | * 42 | * Valid samplerates and bitrates. 43 | * const int samplerates[9] = { 44 | * 44100, 48000, 32000, // MPEG-I 45 | * 22050, 24000, 16000, // MPEG-II 46 | * 11025, 12000, 8000 // MPEG-2.5 47 | * }; 48 | * 49 | * const int bitrates[16][4] = { 50 | * // MPEG version: 51 | * // 2.5, reserved, II, I 52 | * { -1, -1, -1, -1}, 53 | * { 8, -1, 8, 32}, 54 | * { 16, -1, 16, 40}, 55 | * { 24, -1, 24, 48}, 56 | * { 32, -1, 32, 56}, 57 | * { 40, -1, 40, 64}, 58 | * { 48, -1, 48, 80}, 59 | * { 56, -1, 56, 96}, 60 | * { 64, -1, 64, 112}, 61 | * { 80, -1, 80, 128}, 62 | * { 96, -1, 96, 160}, 63 | * {112, -1, 112, 192}, 64 | * {128, -1, 128, 224}, 65 | * {144, -1, 144, 256}, 66 | * {160, -1, 160, 320}, 67 | * { -1, -1, -1, -1} 68 | * }; 69 | * 70 | */ 71 | 72 | /* Abtract type for the shine encoder handle. */ 73 | typedef struct shine_global_flags *shine_t; 74 | 75 | /* Fill in a `mpeg_t` structure with default values. */ 76 | void shine_set_config_mpeg_defaults(shine_mpeg_t *mpeg); 77 | 78 | /* Check if a given bitrate is supported by the encoder (see `bitrates` above 79 | * for a list of acceptable values. */ 80 | int shine_find_bitrate_index(int bitr, int mpeg_version); 81 | 82 | /* Check if a given samplerate is supported by the encoder (see `samplerates` 83 | * above for a list of acceptable values. */ 84 | int shine_find_samplerate_index(int freq); 85 | 86 | /* Returns the MPEG version used for the given samplerate index. See above 87 | * `mpeg_versions` for a list of possible values. */ 88 | int shine_mpeg_version(int samplerate_index); 89 | 90 | /* Check if a given bitrate and samplerate is supported by the encoder (see 91 | * `samplerates` and `bitrates` above for a list of acceptable values). 92 | * 93 | * Returns -1 on error, mpeg_version on success. */ 94 | int shine_check_config(int freq, int bitr); 95 | 96 | /* Pass a pointer to a `config_t` structure and returns an initialized 97 | * encoder. 98 | * 99 | * Configuration data is copied over to the encoder. It is not possible 100 | * to change its values after initializing the encoder at the moment. 101 | * 102 | * Checking for valid configuration values is left for the application to 103 | * implement. You can use the `shine_find_bitrate_index` and 104 | * `shine_find_samplerate_index` functions or the `bitrates` and 105 | * `samplerates` arrays above to check those parameters. Mone and stereo 106 | * mode for wave and mpeg should also be consistent with each other. 107 | * 108 | * This function returns NULL if it was not able to allocate memory data for 109 | * the encoder. */ 110 | shine_t shine_initialise(shine_config_t *config); 111 | 112 | /* Maximun possible value for the function below. */ 113 | #define SHINE_MAX_SAMPLES 1152 114 | 115 | /* Returns audio samples expected in each frame. */ 116 | int shine_samples_per_pass(shine_t s); 117 | 118 | /* Encode audio data. Source data must have `shine_samples_per_pass(s)` audio 119 | * samples per channels. Mono encoder only expect one channel. 120 | * 121 | * Returns a pointer to freshly encoded data while `written` contains the size 122 | * of available data. This pointer's memory is handled by the library and is 123 | * only valid until the next call to `shine_encode_buffer` or `shine_close` and 124 | * may be NULL if no data was written. */ 125 | unsigned char *shine_encode_buffer(shine_t s, int16_t **data, int *written); 126 | 127 | /* Encode interleaved audio data. Source data must have 128 | * `shine_samples_per_pass(s)` audio samples per channels. Mono encoder only 129 | * expect one channel. 130 | * 131 | * Returns a pointer to freshly encoded data while `written` contains the size 132 | * of available data. This pointer's memory is handled by the library and is 133 | * only valid until the next call to `shine_encode_buffer` or `shine_close` and 134 | * may be NULL if no data was written. */ 135 | unsigned char *shine_encode_buffer_interleaved(shine_t s, int16_t *data, 136 | int *written); 137 | 138 | /* Flush all data currently in the encoding buffer. Should be used before 139 | * closing the encoder, to make all encoded data has been written. */ 140 | unsigned char *shine_flush(shine_t s, int *written); 141 | 142 | /* Close an encoder, freeing all associated memory. Encoder handler is not 143 | * valid after this call. */ 144 | void shine_close(shine_t s); 145 | 146 | #endif 147 | -------------------------------------------------------------------------------- /src/lib/mult_mips_gcc.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define mul(a, b) \ 4 | ({ \ 5 | register int32_t res; \ 6 | __asm__ __volatile__("mult %0, %1" : : "r"(a), "r"(b)); \ 7 | __asm__ __volatile__("mfhi %0" : "=r"(res)); \ 8 | res; \ 9 | }) 10 | 11 | #define mul0(hi, lo, a, b) \ 12 | __asm__ __volatile__("mult %0, %1" : : "r"(a), "r"(b)) 13 | 14 | #define muladd(hi, lo, a, b) \ 15 | __asm__ __volatile__("madd %0, %1" : : "r"(a), "r"(b)) 16 | 17 | #define mulsub(hi, lo, a, b) \ 18 | __asm__ __volatile__("msub %0, %1" : : "r"(a), "r"(b)) 19 | 20 | #define mulz(hi, lo) \ 21 | do { \ 22 | register int32_t t; \ 23 | __asm__ __volatile__("mfhi %0" : "=r"(t)); \ 24 | (hi) = t; \ 25 | } while (0) 26 | 27 | #define cmuls(dre, dim, are, aim, bre, bim) \ 28 | do { \ 29 | register int32_t t1, t2, tre; \ 30 | __asm__ __volatile__("mult %0, %1" : : "r"(are), "r"(bre)); \ 31 | __asm__ __volatile__("msub %0, %1" : : "r"(aim), "r"(bim)); \ 32 | __asm__ __volatile__("mfhi %0; mflo %1" : "=r"(t1), "=r"(t2)); \ 33 | tre = (t1 << 1) | ((uint32_t)t2 >> 31); \ 34 | __asm__ __volatile__("mult %0, %1" : : "r"(are), "r"(bim)); \ 35 | __asm__ __volatile__("madd %0, %1" : : "r"(bre), "r"(aim)); \ 36 | dre = tre; \ 37 | __asm__ __volatile__("mfhi %0; mflo %1" : "=r"(t1), "=r"(t2)); \ 38 | dim = (t1 << 1) | ((uint32_t)t2 >> 31); \ 39 | } while (0) 40 | 41 | #if __mips_isa_rev >= 2 42 | static inline uint32_t SWAB32(uint32_t x) { 43 | __asm__(" wsbh %0, %1 \n" 44 | " rotr %0, %0, 16 \n" 45 | : "=r"(x) 46 | : "r"(x)); 47 | return x; 48 | } 49 | #define SWAB32 SWAB32 50 | #endif 51 | -------------------------------------------------------------------------------- /src/lib/mult_noarch_gcc.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef mul 4 | #define mul(a, b) (int32_t)((((int64_t)a) * ((int64_t)b)) >> 32) 5 | #endif 6 | 7 | #ifndef muls 8 | #define muls(a, b) (int32_t)((((int64_t)a) * ((int64_t)b)) >> 31) 9 | #endif 10 | 11 | #ifndef mulr 12 | #define mulr(a, b) \ 13 | (int32_t)(((((int64_t)a) * ((int64_t)b)) + 0x80000000LL) >> 32) 14 | #endif 15 | 16 | #ifndef mulsr 17 | #define mulsr(a, b) \ 18 | (int32_t)(((((int64_t)a) * ((int64_t)b)) + 0x40000000LL) >> 31) 19 | #endif 20 | 21 | #ifndef mul0 22 | #define mul0(hi, lo, a, b) ((hi) = mul((a), (b))) 23 | #define muladd(hi, lo, a, b) ((hi) += mul((a), (b))) 24 | #define mulsub(hi, lo, a, b) ((hi) -= mul((a), (b))) 25 | #define mulz(hi, lo) 26 | #endif 27 | 28 | #ifndef cmuls 29 | #define cmuls(dre, dim, are, aim, bre, bim) \ 30 | do { \ 31 | int32_t tre; \ 32 | (tre) = (int32_t)(((int64_t)(are) * (int64_t)(bre) - \ 33 | (int64_t)(aim) * (int64_t)(bim)) >> \ 34 | 31); \ 35 | (dim) = (int32_t)(((int64_t)(are) * (int64_t)(bim) + \ 36 | (int64_t)(aim) * (int64_t)(bre)) >> \ 37 | 31); \ 38 | (dre) = tre; \ 39 | } while (0) 40 | #endif 41 | -------------------------------------------------------------------------------- /src/lib/mult_sarm_gcc.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Fractional multiply */ 4 | #if __ARM_ARCH >= 6 5 | #define mul(x, y) \ 6 | ({ \ 7 | register int32_t result; \ 8 | asm("smmul %0, %2, %1" : "=r"(result) : "r"(x), "r"(y)); \ 9 | result; \ 10 | }) 11 | #else 12 | #define mul(x, y) \ 13 | ({ \ 14 | register int32_t result; \ 15 | asm("smull r3, %0, %2, %1" : "=r"(result) : "r"(x), "r"(y) : "r3"); \ 16 | result; \ 17 | }) 18 | #endif 19 | 20 | /* Fractional multiply with single bit left shift. */ 21 | #define muls(x, y) \ 22 | ({ \ 23 | register int32_t result; \ 24 | asm("smull r3, %0, %2, %1\n\t" \ 25 | "movs r3, r3, lsl #1\n\t" \ 26 | "adc %0, %0, %0" \ 27 | : "=r"(result) \ 28 | : "r"(x), "r"(y) \ 29 | : "r3", "cc"); \ 30 | result; \ 31 | }) 32 | 33 | #if __ARM_ARCH >= 6 34 | #define mulr(x, y) \ 35 | ({ \ 36 | register int32_t result; \ 37 | asm("smmulr %0, %2, %1" : "=r"(result) : "r"(x), "r"(y)); \ 38 | result; \ 39 | }) 40 | #else 41 | #define mulr(x, y) \ 42 | ({ \ 43 | register int32_t result; \ 44 | asm("smull r3, %0, %2, %1\n\t" \ 45 | "adds r3, r3, #0x80000000\n\t" \ 46 | "adc %0, %0, #0" \ 47 | : "=r"(result) \ 48 | : "r"(x), "r"(y) \ 49 | : "r3", "cc"); \ 50 | result; \ 51 | }) 52 | #endif 53 | 54 | #define mulsr(x, y) \ 55 | ({ \ 56 | register int32_t result; \ 57 | asm("smull r3, %0, %1, %2\n\t" \ 58 | "movs r3, r3, lsl #1\n\t" \ 59 | "adc %0, %0, %0\n\t" \ 60 | "adds r3, r3, #0x80000000\n\t" \ 61 | "adc %0, %0, #0" \ 62 | : "=r"(result) \ 63 | : "r"(x), "r"(y) \ 64 | : "r3", "cc"); \ 65 | result; \ 66 | }) 67 | 68 | #define mul0(hi, lo, a, b) \ 69 | asm("smull %0, %1, %2, %3" : "=r"(lo), "=r"(hi) : "r"(a), "r"(b)) 70 | 71 | #define muladd(hi, lo, a, b) \ 72 | asm("smlal %0, %1, %2, %3" : "+r"(lo), "+r"(hi) : "r"(a), "r"(b)) 73 | 74 | #define mulsub(hi, lo, a, b) \ 75 | asm("smlal %0, %1, %2, %3" : "+r"(lo), "+r"(hi) : "r"(a), "r"(-(b))) 76 | 77 | #define mulz(hi, lo) 78 | 79 | #define cmuls(dre, dim, are, aim, bre, bim) \ 80 | do { \ 81 | register int32_t tre, tim; \ 82 | asm("smull r3, %0, %2, %4\n\t" \ 83 | "smlal r3, %0, %3, %5\n\t" \ 84 | "movs r3, r3, lsl #1\n\t" \ 85 | "adc %0, %0, %0\n\t" \ 86 | "smull r3, %1, %2, %6\n\t" \ 87 | "smlal r3, %1, %4, %3\n\t" \ 88 | "movs r3, r3, lsl #1\n\t" \ 89 | "adc %1, %1, %1\n\t" \ 90 | : "=&r"(tre), "=&r"(tim) \ 91 | : "r"(are), "r"(aim), "r"(bre), "r"(-(bim)), "r"(bim) \ 92 | : "r3", "cc"); \ 93 | dre = tre; \ 94 | dim = tim; \ 95 | } while (0) 96 | 97 | #if __ARM_ARCH >= 6 98 | static inline uint32_t SWAB32(uint32_t x) { 99 | asm("rev %0, %1" : "=r"(x) : "r"(x)); 100 | return x; 101 | } 102 | #define SWAB32 SWAB32 103 | #endif 104 | -------------------------------------------------------------------------------- /src/lib/reservoir.c: -------------------------------------------------------------------------------- 1 | /* reservoir.c 2 | * Layer3 bit reservoir: Described in C.1.5.4.2.2 of the IS 3 | */ 4 | 5 | #include "reservoir.h" 6 | #include "bitstream.h" 7 | #include "huffman.h" 8 | #include "l3bitstream.h" 9 | #include "l3loop.h" 10 | #include "layer3.h" 11 | #include "types.h" 12 | 13 | /* 14 | * shine_max_reservoir_bits: 15 | * ------------ 16 | * Called at the beginning of each granule to get the max bit 17 | * allowance for the current granule based on reservoir size 18 | * and perceptual entropy. 19 | */ 20 | int shine_max_reservoir_bits(double *pe, shine_global_config *config) { 21 | int more_bits, max_bits, add_bits, over_bits; 22 | int mean_bits = config->mean_bits; 23 | 24 | mean_bits /= config->wave.channels; 25 | max_bits = mean_bits; 26 | 27 | if (max_bits > 4095) 28 | max_bits = 4095; 29 | if (!config->ResvMax) 30 | return max_bits; 31 | 32 | more_bits = *pe * 3.1 - mean_bits; 33 | add_bits = 0; 34 | if (more_bits > 100) { 35 | int frac = (config->ResvSize * 6) / 10; 36 | 37 | if (frac < more_bits) 38 | add_bits = frac; 39 | else 40 | add_bits = more_bits; 41 | } 42 | over_bits = config->ResvSize - ((config->ResvMax << 3) / 10) - add_bits; 43 | if (over_bits > 0) 44 | add_bits += over_bits; 45 | 46 | max_bits += add_bits; 47 | if (max_bits > 4095) 48 | max_bits = 4095; 49 | return max_bits; 50 | } 51 | 52 | /* 53 | * shine_ResvAdjust: 54 | * ----------- 55 | * Called after a granule's bit allocation. Readjusts the size of 56 | * the reservoir to reflect the granule's usage. 57 | */ 58 | void shine_ResvAdjust(gr_info *gi, shine_global_config *config) { 59 | config->ResvSize += 60 | (config->mean_bits / config->wave.channels) - gi->part2_3_length; 61 | } 62 | 63 | /* 64 | * shine_ResvFrameEnd: 65 | * ------------- 66 | * Called after all granules in a frame have been allocated. Makes sure 67 | * that the reservoir size is within limits, possibly by adding stuffing 68 | * bits. Note that stuffing bits are added by increasing a granule's 69 | * part2_3_length. The bitstream formatter will detect this and write the 70 | * appropriate stuffing bits to the bitstream. 71 | */ 72 | void shine_ResvFrameEnd(shine_global_config *config) { 73 | gr_info *gi; 74 | int gr, ch, ancillary_pad, stuffingBits; 75 | int over_bits; 76 | shine_side_info_t *l3_side = &config->side_info; 77 | 78 | ancillary_pad = 0; 79 | 80 | /* just in case mean_bits is odd, this is necessary... */ 81 | if ((config->wave.channels == 2) && (config->mean_bits & 1)) 82 | config->ResvSize += 1; 83 | 84 | over_bits = config->ResvSize - config->ResvMax; 85 | if (over_bits < 0) 86 | over_bits = 0; 87 | 88 | config->ResvSize -= over_bits; 89 | stuffingBits = over_bits + ancillary_pad; 90 | 91 | /* we must be byte aligned */ 92 | if ((over_bits = config->ResvSize % 8)) { 93 | stuffingBits += over_bits; 94 | config->ResvSize -= over_bits; 95 | } 96 | 97 | if (stuffingBits) { 98 | /* 99 | * plan a: put all into the first granule 100 | * This was preferred by someone designing a 101 | * real-time decoder... 102 | */ 103 | gi = (gr_info *)&(l3_side->gr[0].ch[0]); 104 | 105 | if (gi->part2_3_length + stuffingBits < 4095) 106 | gi->part2_3_length += stuffingBits; 107 | else { 108 | /* plan b: distribute throughout the granules */ 109 | for (gr = 0; gr < config->mpeg.granules_per_frame; gr++) 110 | for (ch = 0; ch < config->wave.channels; ch++) { 111 | int extraBits, bitsThisGr; 112 | gr_info *gi = (gr_info *)&(l3_side->gr[gr].ch[ch]); 113 | if (!stuffingBits) 114 | break; 115 | extraBits = 4095 - gi->part2_3_length; 116 | bitsThisGr = extraBits < stuffingBits ? extraBits : stuffingBits; 117 | gi->part2_3_length += bitsThisGr; 118 | stuffingBits -= bitsThisGr; 119 | } 120 | /* 121 | * If any stuffing bits remain, we elect to spill them 122 | * into ancillary data. The bitstream formatter will do this if 123 | * l3side->resvDrain is set 124 | */ 125 | l3_side->resvDrain = stuffingBits; 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/lib/reservoir.h: -------------------------------------------------------------------------------- 1 | #ifndef RESERVOIR_H 2 | #define RESERVOIR_H 3 | 4 | #include "types.h" 5 | 6 | void shine_ResvFrameBegin(int frameLength, shine_global_config *config); 7 | int shine_max_reservoir_bits(double *pe, shine_global_config *config); 8 | void shine_ResvAdjust(gr_info *gi, shine_global_config *config); 9 | void shine_ResvFrameEnd(shine_global_config *config); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/lib/tables.c: -------------------------------------------------------------------------------- 1 | /* tables.c 2 | * 3 | * Here are MPEG1 Table B.8 and MPEG2 Table B.1 -- Layer III scalefactor bands. 4 | * Index into this using a method such as: 5 | * idx = fr_ps->header->sampling_frequency + (fr_ps->header->version * 3) 6 | */ 7 | 8 | #include "tables.h" 9 | 10 | const int shine_slen1_tab[16] = {0, 0, 0, 0, 3, 1, 1, 1, 11 | 2, 2, 2, 3, 3, 3, 4, 4}; 12 | const int shine_slen2_tab[16] = {0, 1, 2, 3, 0, 1, 2, 3, 13 | 1, 2, 3, 1, 2, 3, 2, 3}; 14 | 15 | /* Valid samplerates and bitrates. */ 16 | const int samplerates[9] = { 17 | 44100, 48000, 32000, /* MPEG-I */ 18 | 22050, 24000, 16000, /* MPEG-II */ 19 | 11025, 12000, 8000 /* MPEG-2.5 */ 20 | }; 21 | 22 | const int bitrates[16][4] = { 23 | /* MPEG version: 24 | * 2.5, reserved, II, I */ 25 | {-1, -1, -1, -1}, {8, -1, 8, 32}, {16, -1, 16, 40}, 26 | {24, -1, 24, 48}, {32, -1, 32, 56}, {40, -1, 40, 64}, 27 | {48, -1, 48, 80}, {56, -1, 56, 96}, {64, -1, 64, 112}, 28 | {-1, -1, 80, 128}, {-1, -1, 96, 160}, {-1, -1, 112, 192}, 29 | {-1, -1, 128, 224}, {-1, -1, 144, 256}, {-1, -1, 160, 320}, 30 | {-1, -1, -1, -1}}; 31 | 32 | const int shine_scale_fact_band_index[9][23] = { 33 | /* MPEG-I */ 34 | /* Table B.8.b: 44.1 kHz */ 35 | {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, 36 | 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576}, 37 | /* Table B.8.c: 48 kHz */ 38 | {0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, 39 | 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576}, 40 | /* Table B.8.a: 32 kHz */ 41 | {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, 42 | 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576}, 43 | /* MPEG-II */ 44 | /* Table B.2.b: 22.05 kHz */ 45 | {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 46 | 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576}, 47 | /* Table B.2.c: 24 kHz */ 48 | {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 49 | 114, 136, 162, 194, 232, 278, 330, 394, 464, 540, 576}, 50 | /* Table B.2.a: 16 kHz */ 51 | {0, 6, 12, 18, 24, 30, 36, 44, 45, 66, 80, 96, 52 | 116, 140, 168, 200, 238, 248, 336, 396, 464, 522, 576}, 53 | 54 | /* MPEG-2.5 */ 55 | /* 11.025 kHz */ 56 | {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 57 | 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576}, 58 | /* 12 kHz */ 59 | {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, 60 | 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576}, 61 | /* MPEG-2.5 8 kHz */ 62 | {0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, 63 | 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576}, 64 | }; 65 | 66 | /* note. 0.035781 is shine_enwindow maximum value */ 67 | /* scale and convert to fixed point before storing */ 68 | #define SHINE_EW(x) (int32_t)((double)(x)*0x7fffffff) 69 | #define SHINE_EW2(a, b) SHINE_EW(a), SHINE_EW(b) 70 | #define SHINE_EW10(a, b, c, d, e, f, g, h, i, j) \ 71 | SHINE_EW2(a, b), SHINE_EW2(c, d), SHINE_EW2(e, f), SHINE_EW2(g, h), \ 72 | SHINE_EW2(i, j) 73 | 74 | const int32_t shine_enwindow[] = { 75 | SHINE_EW10(0.000000, -0.000000, -0.000000, -0.000000, -0.000000, -0.000000, 76 | -0.000000, -0.000001, -0.000001, -0.000001), 77 | SHINE_EW10(-0.000001, -0.000001, -0.000001, -0.000002, -0.000002, -0.000002, 78 | -0.000002, -0.000003, -0.000003, -0.000003), 79 | SHINE_EW10(-0.000004, -0.000004, -0.000005, -0.000005, -0.000006, -0.000007, 80 | -0.000008, -0.000008, -0.000009, -0.000010), 81 | SHINE_EW10(-0.000011, -0.000012, -0.000014, -0.000015, -0.000017, -0.000018, 82 | -0.000020, -0.000021, -0.000023, -0.000025), 83 | SHINE_EW10(-0.000028, -0.000030, -0.000032, -0.000035, -0.000038, -0.000041, 84 | -0.000043, -0.000046, -0.000050, -0.000053), 85 | SHINE_EW10(-0.000056, -0.000060, -0.000063, -0.000066, -0.000070, -0.000073, 86 | -0.000077, -0.000081, -0.000084, -0.000087), 87 | SHINE_EW10(-0.000091, -0.000093, -0.000096, -0.000099, 0.000102, 0.000104, 88 | 0.000106, 0.000107, 0.000108, 0.000109), 89 | SHINE_EW10(0.000109, 0.000108, 0.000107, 0.000105, 0.000103, 0.000099, 90 | 0.000095, 0.000090, 0.000084, 0.000078), 91 | SHINE_EW10(0.000070, 0.000061, 0.000051, 0.000040, 0.000027, 0.000014, 92 | -0.000001, -0.000017, -0.000034, -0.000053), 93 | SHINE_EW10(-0.000073, -0.000094, -0.000116, -0.000140, -0.000165, -0.000191, 94 | -0.000219, -0.000247, -0.000277, -0.000308), 95 | SHINE_EW10(-0.000339, -0.000371, -0.000404, -0.000438, -0.000473, -0.000507, 96 | -0.000542, -0.000577, -0.000612, -0.000647), 97 | SHINE_EW10(-0.000681, -0.000714, -0.000747, -0.000779, -0.000810, -0.000839, 98 | -0.000866, -0.000892, -0.000915, -0.000936), 99 | SHINE_EW10(-0.000954, -0.000969, -0.000981, -0.000989, -0.000994, -0.000995, 100 | -0.000992, -0.000984, 0.000971, 0.000954), 101 | SHINE_EW10(0.000931, 0.000903, 0.000869, 0.000829, 0.000784, 0.000732, 102 | 0.000674, 0.000610, 0.000539, 0.000463), 103 | SHINE_EW10(0.000379, 0.000288, 0.000192, 0.000088, -0.000021, -0.000137, 104 | -0.000260, -0.000388, -0.000522, -0.000662), 105 | SHINE_EW10(-0.000807, -0.000957, -0.001111, -0.001270, -0.001432, -0.001598, 106 | -0.001767, -0.001937, -0.002110, -0.002283), 107 | SHINE_EW10(-0.002457, -0.002631, -0.002803, -0.002974, -0.003142, -0.003307, 108 | -0.003467, -0.003623, -0.003772, -0.003914), 109 | SHINE_EW10(-0.004049, -0.004175, -0.004291, -0.004396, -0.004490, -0.004570, 110 | -0.004638, -0.004691, -0.004728, -0.004749), 111 | SHINE_EW10(-0.004752, -0.004737, -0.004703, -0.004649, -0.004574, -0.004477, 112 | -0.004358, -0.004215, -0.004049, -0.003859), 113 | SHINE_EW10(-0.003643, -0.003402, 0.003135, 0.002841, 0.002522, 0.002175, 114 | 0.001801, 0.001400, 0.000971, 0.000516), 115 | SHINE_EW10(0.000033, -0.000476, -0.001012, -0.001574, -0.002162, -0.002774, 116 | -0.003411, -0.004072, -0.004756, -0.005462), 117 | SHINE_EW10(-0.006189, -0.006937, -0.007703, -0.008487, -0.009288, -0.010104, 118 | -0.010933, -0.011775, -0.012628, -0.013489), 119 | SHINE_EW10(-0.014359, -0.015234, -0.016113, -0.016994, -0.017876, -0.018757, 120 | -0.019634, -0.020507, -0.021372, -0.022229), 121 | SHINE_EW10(-0.023074, -0.023907, -0.024725, -0.025527, -0.026311, -0.027074, 122 | -0.027815, -0.028533, -0.029225, -0.029890), 123 | SHINE_EW10(-0.030527, -0.031133, -0.031707, -0.032248, -0.032755, -0.033226, 124 | -0.033660, -0.034056, -0.034413, -0.034730), 125 | SHINE_EW10(-0.035007, -0.035242, -0.035435, -0.035586, -0.035694, -0.035759, 126 | 0.035781, 0.035759, 0.035694, 0.035586), 127 | SHINE_EW10(0.035435, 0.035242, 0.035007, 0.034730, 0.034413, 0.034056, 128 | 0.033660, 0.033226, 0.032755, 0.032248), 129 | SHINE_EW10(0.031707, 0.031133, 0.030527, 0.029890, 0.029225, 0.028533, 130 | 0.027815, 0.027074, 0.026311, 0.025527), 131 | SHINE_EW10(0.024725, 0.023907, 0.023074, 0.022229, 0.021372, 0.020507, 132 | 0.019634, 0.018757, 0.017876, 0.016994), 133 | SHINE_EW10(0.016113, 0.015234, 0.014359, 0.013489, 0.012628, 0.011775, 134 | 0.010933, 0.010104, 0.009288, 0.008487), 135 | SHINE_EW10(0.007703, 0.006937, 0.006189, 0.005462, 0.004756, 0.004072, 136 | 0.003411, 0.002774, 0.002162, 0.001574), 137 | SHINE_EW10(0.001012, 0.000476, -0.000033, -0.000516, -0.000971, -0.001400, 138 | -0.001801, -0.002175, -0.002522, -0.002841), 139 | SHINE_EW10(0.003135, 0.003402, 0.003643, 0.003859, 0.004049, 0.004215, 140 | 0.004358, 0.004477, 0.004574, 0.004649), 141 | SHINE_EW10(0.004703, 0.004737, 0.004752, 0.004749, 0.004728, 0.004691, 142 | 0.004638, 0.004570, 0.004490, 0.004396), 143 | SHINE_EW10(0.004291, 0.004175, 0.004049, 0.003914, 0.003772, 0.003623, 144 | 0.003467, 0.003307, 0.003142, 0.002974), 145 | SHINE_EW10(0.002803, 0.002631, 0.002457, 0.002283, 0.002110, 0.001937, 146 | 0.001767, 0.001598, 0.001432, 0.001270), 147 | SHINE_EW10(0.001111, 0.000957, 0.000807, 0.000662, 0.000522, 0.000388, 148 | 0.000260, 0.000137, 0.000021, -0.000088), 149 | SHINE_EW10(-0.000192, -0.000288, -0.000379, -0.000463, -0.000539, -0.000610, 150 | -0.000674, -0.000732, -0.000784, -0.000829), 151 | SHINE_EW10(-0.000869, -0.000903, -0.000931, -0.000954, 0.000971, 0.000984, 152 | 0.000992, 0.000995, 0.000994, 0.000989), 153 | SHINE_EW10(0.000981, 0.000969, 0.000954, 0.000936, 0.000915, 0.000892, 154 | 0.000866, 0.000839, 0.000810, 0.000779), 155 | SHINE_EW10(0.000747, 0.000714, 0.000681, 0.000647, 0.000612, 0.000577, 156 | 0.000542, 0.000507, 0.000473, 0.000438), 157 | SHINE_EW10(0.000404, 0.000371, 0.000339, 0.000308, 0.000277, 0.000247, 158 | 0.000219, 0.000191, 0.000165, 0.000140), 159 | SHINE_EW10(0.000116, 0.000094, 0.000073, 0.000053, 0.000034, 0.000017, 160 | 0.000001, -0.000014, -0.000027, -0.000040), 161 | SHINE_EW10(-0.000051, -0.000061, -0.000070, -0.000078, -0.000084, -0.000090, 162 | -0.000095, -0.000099, -0.000103, -0.000105), 163 | SHINE_EW10(-0.000107, -0.000108, -0.000109, -0.000109, -0.000108, -0.000107, 164 | -0.000106, -0.000104, 0.000102, 0.000099), 165 | SHINE_EW10(0.000096, 0.000093, 0.000091, 0.000087, 0.000084, 0.000081, 166 | 0.000077, 0.000073, 0.000070, 0.000066), 167 | SHINE_EW10(0.000063, 0.000060, 0.000056, 0.000053, 0.000050, 0.000046, 168 | 0.000043, 0.000041, 0.000038, 0.000035), 169 | SHINE_EW10(0.000032, 0.000030, 0.000028, 0.000025, 0.000023, 0.000021, 170 | 0.000020, 0.000018, 0.000017, 0.000015), 171 | SHINE_EW10(0.000014, 0.000012, 0.000011, 0.000010, 0.000009, 0.000008, 172 | 0.000008, 0.000007, 0.000006, 0.000005), 173 | SHINE_EW10(0.000005, 0.000004, 0.000004, 0.000003, 0.000003, 0.000003, 174 | 0.000002, 0.000002, 0.000002, 0.000002), 175 | SHINE_EW10(0.000001, 0.000001, 0.000001, 0.000001, 0.000001, 0.000001, 176 | 0.000000, 0.000000, 0.000000, 0.000000), 177 | SHINE_EW2(0.000000, 0.000000)}; 178 | -------------------------------------------------------------------------------- /src/lib/tables.h: -------------------------------------------------------------------------------- 1 | #ifndef TABLES_H 2 | #define TABLES_H 3 | 4 | #include "types.h" 5 | 6 | extern const int shine_slen1_tab[16]; 7 | extern const int shine_slen2_tab[16]; 8 | 9 | extern const int samplerates[9]; 10 | extern const int bitrates[16][4]; 11 | 12 | extern const int shine_scale_fact_band_index[9][23]; 13 | extern const int32_t shine_enwindow[]; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /src/lib/types.h: -------------------------------------------------------------------------------- 1 | #ifndef PRIV_TYPES_H 2 | #define PRIV_TYPES_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #define GRANULE_SIZE 576 11 | 12 | #include "bitstream.h" 13 | 14 | /* Include arch-specific instructions, 15 | * when defined. */ 16 | #if defined(__mips__) && (__mips == 32) 17 | #include "mult_mips_gcc.h" 18 | #elif defined(__arm__) && !defined(__thumb__) 19 | #include "mult_sarm_gcc.h" 20 | #endif 21 | 22 | /* Include and define generic instructions, 23 | * when not already defined above. */ 24 | #include "mult_noarch_gcc.h" 25 | 26 | #ifndef SWAB32 27 | #if defined(__GNUC__) && \ 28 | (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 2)) 29 | #define SWAB32(x) __builtin_bswap32(x) 30 | #else 31 | #define SWAB32(x) \ 32 | (((unsigned int)(x) >> 24) | (((unsigned int)(x) >> 8) & 0xff00) | \ 33 | (((unsigned int)(x)&0xff00) << 8) | ((unsigned int)(x) << 24)) 34 | #endif 35 | #endif 36 | 37 | /* #define DEBUG if you want the library to dump info to stdout */ 38 | 39 | #define PI 3.14159265358979 40 | #define PI4 0.78539816339745 41 | #define PI12 0.26179938779915 42 | #define PI36 0.087266462599717 43 | #define PI64 0.049087385212 44 | #define SQRT2 1.41421356237 45 | #define LN2 0.69314718 46 | #define LN_TO_LOG10 0.2302585093 47 | #define BLKSIZE 1024 48 | #define HAN_SIZE 512 /* for loop unrolling, require that HAN_SIZE%8==0 */ 49 | #define SCALE_BLOCK 12 50 | #define SCALE_RANGE 64 51 | #define SCALE 32768 52 | #define SBLIMIT 32 53 | 54 | #ifndef MAX_CHANNELS 55 | #define MAX_CHANNELS 2 56 | #endif 57 | 58 | #ifndef MAX_GRANULES 59 | #define MAX_GRANULES 2 60 | #endif 61 | 62 | typedef struct { 63 | int channels; 64 | int samplerate; 65 | } priv_shine_wave_t; 66 | 67 | typedef struct { 68 | int version; 69 | int layer; 70 | int granules_per_frame; 71 | int mode; /* + */ /* Stereo mode */ 72 | int bitr; /* + */ /* Must conform to known bitrate - see Main.c */ 73 | int emph; /* + */ /* De-emphasis */ 74 | int padding; 75 | int bits_per_frame; 76 | int bits_per_slot; 77 | double frac_slots_per_frame; 78 | double slot_lag; 79 | int whole_slots_per_frame; 80 | int bitrate_index; /* + */ /* See Main.c and Layer3.c */ 81 | int samplerate_index; /* + */ /* See Main.c and Layer3.c */ 82 | int crc; 83 | int ext; 84 | int mode_ext; 85 | int copyright; /* + */ 86 | int original; /* + */ 87 | } priv_shine_mpeg_t; 88 | 89 | typedef struct { 90 | int32_t *xr; /* magnitudes of the spectral values */ 91 | int32_t xrsq[GRANULE_SIZE]; /* xr squared */ 92 | int32_t xrabs[GRANULE_SIZE]; /* xr absolute */ 93 | int32_t xrmax; /* maximum of xrabs array */ 94 | int32_t en_tot[MAX_GRANULES]; /* gr */ 95 | int32_t en[MAX_GRANULES][21]; 96 | int32_t xm[MAX_GRANULES][21]; 97 | int32_t xrmaxl[MAX_GRANULES]; 98 | double steptab[128]; /* 2**(-x/4) for x = -127..0 */ 99 | int32_t steptabi[128]; /* 2**(-x/4) for x = -127..0 */ 100 | int int2idx[10000]; /* x**(3/4) for x = 0..9999 */ 101 | } l3loop_t; 102 | 103 | typedef struct { 104 | int32_t cos_l[18][36]; 105 | } mdct_t; 106 | 107 | typedef struct { 108 | int off[MAX_CHANNELS]; 109 | int32_t fl[SBLIMIT][64]; 110 | int32_t x[MAX_CHANNELS][HAN_SIZE]; 111 | } subband_t; 112 | 113 | /* Side information */ 114 | typedef struct { 115 | unsigned part2_3_length; 116 | unsigned big_values; 117 | unsigned count1; 118 | unsigned global_gain; 119 | unsigned scalefac_compress; 120 | unsigned table_select[3]; 121 | unsigned region0_count; 122 | unsigned region1_count; 123 | unsigned preflag; 124 | unsigned scalefac_scale; 125 | unsigned count1table_select; 126 | unsigned part2_length; 127 | unsigned sfb_lmax; 128 | unsigned address1; 129 | unsigned address2; 130 | unsigned address3; 131 | int quantizerStepSize; 132 | unsigned slen[4]; 133 | } gr_info; 134 | 135 | typedef struct { 136 | unsigned private_bits; 137 | int resvDrain; 138 | unsigned scfsi[MAX_CHANNELS][4]; 139 | struct { 140 | struct { 141 | gr_info tt; 142 | } ch[MAX_CHANNELS]; 143 | } gr[MAX_GRANULES]; 144 | } shine_side_info_t; 145 | 146 | typedef struct { 147 | double l[MAX_GRANULES][MAX_CHANNELS][21]; 148 | } shine_psy_ratio_t; 149 | 150 | typedef struct { 151 | double l[MAX_GRANULES][MAX_CHANNELS][21]; 152 | } shine_psy_xmin_t; 153 | 154 | typedef struct { 155 | int32_t l[MAX_GRANULES][MAX_CHANNELS][22]; /* [cb] */ 156 | int32_t s[MAX_GRANULES][MAX_CHANNELS][13][3]; /* [window][cb] */ 157 | } shine_scalefac_t; 158 | 159 | typedef struct shine_global_flags { 160 | priv_shine_wave_t wave; 161 | priv_shine_mpeg_t mpeg; 162 | bitstream_t bs; 163 | shine_side_info_t side_info; 164 | int sideinfo_len; 165 | int mean_bits; 166 | shine_psy_ratio_t ratio; 167 | shine_scalefac_t scalefactor; 168 | int16_t *buffer[MAX_CHANNELS]; 169 | double pe[MAX_CHANNELS][MAX_GRANULES]; 170 | int l3_enc[MAX_CHANNELS][MAX_GRANULES][GRANULE_SIZE]; 171 | int32_t l3_sb_sample[MAX_CHANNELS][MAX_GRANULES + 1][18][SBLIMIT]; 172 | int32_t mdct_freq[MAX_CHANNELS][MAX_GRANULES][GRANULE_SIZE]; 173 | int ResvSize; 174 | int ResvMax; 175 | l3loop_t l3loop; 176 | mdct_t mdct; 177 | subband_t subband; 178 | } shine_global_config; 179 | 180 | #endif 181 | --------------------------------------------------------------------------------