├── 60-ioschedulers.rules ├── LICENSE ├── Makefile ├── README.md ├── alsa.h ├── aplay+.c ├── aplay+.ipynb ├── aplay+.spec ├── dr_flac.h ├── dr_mp3.h ├── dr_wav.h ├── kbhit.h ├── logo.jpeg ├── logo ├── logo_01.jpeg ├── logo_02.jpeg ├── logo_03.jpeg ├── logo_04.jpeg ├── logo_05.jpeg ├── logo_06.jpeg ├── logo_07.jpeg ├── logo_08.jpeg ├── logo_09.jpeg └── logo_10.jpeg ├── ls.h ├── minimp3.h ├── parg.h ├── random.h ├── regexp.h ├── stb_vorbis.h ├── uaac.h └── uwma.h /60-ioschedulers.rules: -------------------------------------------------------------------------------- 1 | # scheduler for non rotational, SSD 2 | ACTION=="add|change", KERNEL=="sd[a-z]|mmcblk[0-9]*", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none" 3 | # scheduler for rotational, HDD 4 | ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq" 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Yuichiro Nakada 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ©2017-2025 YUICHIRO NAKADA 2 | 3 | PROGRAM = $(patsubst %.c,%,$(wildcard *.c)) 4 | 5 | ifneq (, $(shell which clang)) 6 | CC = clang 7 | endif 8 | ifneq (, $(shell which icc)) 9 | CC = icc 10 | endif 11 | CFLAGS = -Os -ffunction-sections -fdata-sections -funroll-loops -finline-functions -ftree-vectorize 12 | #CFLAGS = -Os -ffunction-sections -fdata-sections -funroll-loops -finline-functions -ftree-vectorize -march=native 13 | LDFLAGS = -lasound -lm -Wl,-s -Wl,--gc-sections 14 | #LDFLAGS = -lasound -lm -Wl,-s -Wl,-dead_strip 15 | 16 | .PHONY: all 17 | all: $(PROGRAM) 18 | 19 | $(PROGRAM): % : %.o 20 | $(CC) $< -o $@ $(LDFLAGS) 21 | 22 | %.o : %.c $(HEAD) 23 | $(CC) $(CFLAGS) -c $(@F:.o=.c) -o $@ 24 | 25 | .PHONY: clean 26 | clean: 27 | $(RM) $(PROGRAM) $(OBJS) _depend.inc 28 | 29 | .PHONY: depend 30 | depend: $(OBJS:.o=.c) 31 | -@ $(RM) _depend.inc 32 | -@ for i in $^; do cpp -MM $$i | sed "s/\ [_a-zA-Z0-9][_a-zA-Z0-9]*\.c//g" >> _depend.inc; done 33 | 34 | -include _depend.inc 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🎶 **aplay+**: A Simple and High-Quality Audio Player 2 | 3 | ![GitHub Repo stars](https://img.shields.io/github/stars/yui0/aplay-?style=social) 4 | ![GitHub code size in bytes](https://img.shields.io/github/languages/code-size/yui0/aplay-) 5 | ![Lines of code](https://img.shields.io/tokei/lines/github/yui0/aplay-) 6 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/yui0/aplay-)](https://github.com/yui0/aplay-/releases) 7 | [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE) 8 | 9 | 🎧 **Enjoy BitPerfect audio playback with simplicity and precision!** 10 | 11 | ![Logo](logo.jpeg) 12 | 13 | ## 💿 Supported File Formats 14 | aplay+ supports a variety of popular audio formats: 15 | - 🌟 **FLAC**: High-quality lossless compression 16 | - 🌊 **WAV**: Uncompressed audio with crystal-clear quality 17 | - 🎶 **MP3**: The most commonly used compressed format 18 | - 🎵 **Ogg Vorbis**: Great compression with excellent sound 19 | - 📱 **AAC (mp4/m4a)**: Widely used in iPhones and YouTube 20 | 21 | ## 🔧 How to build 22 | 23 | ### Build Online 24 | - Build easily with Google Colab: 25 | - [Build with Colab](aplay%2B.ipynb)    Open In Colab 26 | 27 | ### Build Locally 28 | 1. Install required libraries: 29 | ```bash 30 | # dnf install alsa-lib-devel 31 | $ make 32 | ``` 33 | 34 | 2. Clone the repository and build: 35 | ```bash 36 | git clone https://github.com/yui0/aplay-.git 37 | cd aplay- 38 | make 39 | ``` 40 | 41 | ## 🌸 How to use 42 | 43 | ### Basic Commands 44 | ```bash 45 | $ ./aplay+ -h 46 | Usage: ./aplay+ [options] dir 47 | 48 | Options: 49 | -h Print this help message 50 | -d Specify ALSA device [e.g., default hw:0,0 plughw:0,0...] 51 | -f Use 32-bit floating-point playback 52 | -r Recursively search directories 53 | -x Enable random playback 54 | -s Search files with a regex 55 | -t Specify file type (e.g., flac, mp3, wma...) 56 | -p Optimize for Linux platforms 57 | ``` 58 | 59 | ### Examples 60 | - 🔀 **Random playback**: 61 | ```bash 62 | $ ./aplay+ -rx . 63 | ``` 64 | - 🎤 **Search for a specific artist**: 65 | ```bash 66 | $ ./aplay+ -rx -d hw:7,0 /Music/ -s ZARD 67 | ``` 68 | - 🎹 **Exclude instrumentals from playback**: 69 | ```bash 70 | $ ./aplay+ -rfx -d hw:7,0 /Music/ -s '^(?!.*nstrumental).*$' 71 | ``` 72 | 73 | ## 🌟 Linux Optimization Settings 74 | 75 | ### 🚀 Optimize Disk I/O 76 | Add the following to your `sysctl.conf`: 77 | ```conf 78 | vm.dirty_ratio = 40 79 | vm.dirty_background_ratio = 10 80 | vm.dirty_expire_centisecs = 3000 81 | vm.dirty_writeback_centisecs = 500 82 | #dev.hpet.max-user-freq = 3072 83 | vm.overcommit_memory = 1 84 | ``` 85 | Apply changes: 86 | ```bash 87 | sysctl -p 88 | ``` 89 | 90 | ### ⚙️ Adjust Scheduler Settings 91 | Optimize SSDs and HDDs with the following script: 92 | ```bash 93 | #!/bin/sh 94 | #cat /sys/block/sd*/queue/scheduler 95 | for FILE in /sys/block/sd*/queue/scheduler 96 | do 97 | [ -f $FILE ] || continue 98 | echo -n none > $FILE 99 | done 100 | ``` 101 | 102 | ### 💨 Set CPU Performance Mode 103 | Use this script to switch CPU governor to "performance": 104 | ```bash 105 | #!/bin/sh 106 | #cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 107 | for CPUFREQ in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 108 | do 109 | [ -f $CPUFREQ ] || continue 110 | echo -n performance > $CPUFREQ 111 | done 112 | ``` 113 | 114 | ### I/O scheduler 115 | ```60-ioschedulers.rules 116 | # scheduler for non rotational, SSD 117 | ACTION=="add|change", KERNEL=="sd[a-z]|mmcblk[0-9]*", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none" 118 | # scheduler for rotational, HDD 119 | ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq" 120 | ``` 121 | 122 | fstrim -v / 123 | 124 | ### Timer 125 | 126 | ``` 127 | #cat /sys/devices/system/clocksource/clocksource0/current_clocksource 128 | echo tsc > /sys/devices/system/clocksource/clocksource0/current_clocksource 129 | ``` 130 | 131 | ulimit -a 132 | 133 | ## 📖 References 134 | 135 | - [stb](https://github.com/nothings/stb) 136 | - [dr_libs](https://github.com/mackron/dr_libs) 137 | - [mini_al](https://github.com/dr-soft/mini_al) 138 | - [minilibs/regex](https://github.com/ccxvii/minilibs) 139 | - [parg](https://github.com/jibsen/parg) 140 | - [Related Blog Posts](https://pulseaudio.blog.fc2.com/blog-entry-1.html) 141 | - https://kazuhira-r.hatenablog.com/entry/2021/05/22/210532 142 | - https://github.com/nothings/single_file_libs 143 | 144 | 🎵 **Experience perfect audio playback with aplay+! Start your music journey today!** 145 | -------------------------------------------------------------------------------- /alsa.h: -------------------------------------------------------------------------------- 1 | /* public domain Simple, Minimalistic, Audio library for ALSA 2 | * ©2017,2020 Yuichiro Nakada 3 | * 4 | * Basic usage: 5 | * AUDIO a; 6 | * AUDIO_init(&a, "plughw:PCH,0", 48000, 2, 32, 1, 0); // device, 48000 samplerate, 2 channels, 32 frame 7 | * ... 8 | * int f = AUDIO_frame(&a); // audio data in a.buffer 9 | * ... 10 | * AUDIO_close(&a); 11 | * 12 | * */ 13 | 14 | // Use the newer ALSA API 15 | #define ALSA_PCM_NEW_HW_PARAMS_API 16 | #include 17 | 18 | typedef struct { 19 | snd_pcm_t *handle; 20 | snd_pcm_uframes_t frames; 21 | char *buffer; 22 | int size; 23 | } AUDIO; 24 | 25 | int AUDIO_init(AUDIO *thiz, char *dev, unsigned int freq, int ch, int frames, int flag, int format) 26 | { 27 | // Open PCM device. 28 | int rc = snd_pcm_open(&thiz->handle, dev, flag ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, 0); 29 | if (rc < 0) { 30 | fprintf(stderr, "unable to open pcm device '%s' (%s)\n", dev, snd_strerror(rc)); 31 | return 1; 32 | } 33 | 34 | // Allocate a hardware parameters object. 35 | snd_pcm_hw_params_t *params; 36 | snd_pcm_hw_params_alloca(¶ms); 37 | 38 | // Fill it in with default values. 39 | snd_pcm_hw_params_any(thiz->handle, params); 40 | 41 | // Set the desired hardware parameters. 42 | // Interleaved mode 43 | rc = snd_pcm_hw_params_set_access(thiz->handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); 44 | if (rc < 0) { 45 | fprintf(stderr, "cannot set access type (%s)\n", snd_strerror(rc)); 46 | snd_pcm_drain(thiz->handle); 47 | snd_pcm_close(thiz->handle); 48 | return 1; 49 | } 50 | 51 | // Signed 16-bit little-endian format 52 | rc = snd_pcm_hw_params_set_format(thiz->handle, params, format ? format : SND_PCM_FORMAT_S16_LE); 53 | if (rc < 0) { 54 | fprintf(stderr, "cannot set sample format (%s)\n", snd_strerror(rc)); 55 | snd_pcm_drain(thiz->handle); 56 | snd_pcm_close(thiz->handle); 57 | return 1; 58 | } 59 | 60 | // Channels 61 | rc = snd_pcm_hw_params_set_channels(thiz->handle, params, ch); 62 | if (rc < 0) { 63 | fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(rc)); 64 | snd_pcm_drain(thiz->handle); 65 | snd_pcm_close(thiz->handle); 66 | return 1; 67 | } 68 | 69 | // 44100 bits/second sampling rate (CD quality) 70 | int dir; 71 | rc = snd_pcm_hw_params_set_rate_near(thiz->handle, params, &freq, &dir); 72 | if (rc < 0) { 73 | fprintf(stderr, "cannot set sample rate (%s)\n", snd_strerror(rc)); 74 | snd_pcm_drain(thiz->handle); 75 | snd_pcm_close(thiz->handle); 76 | return 1; 77 | } 78 | 79 | // Set period size to 32 frames. 80 | thiz->frames = frames; 81 | snd_pcm_hw_params_set_period_size_near(thiz->handle, params, &thiz->frames, &dir); 82 | 83 | // Write the parameters to the driver 84 | rc = snd_pcm_hw_params(thiz->handle, params); 85 | if (rc < 0) { 86 | fprintf(stderr, "unable to set parameters (%s)\n", snd_strerror(rc)); 87 | snd_pcm_drain(thiz->handle); 88 | snd_pcm_close(thiz->handle); 89 | return 1; 90 | } 91 | 92 | // Use a buffer large enough to hold one period 93 | snd_pcm_hw_params_get_period_size(params, &thiz->frames, &dir); 94 | // thiz->size = thiz->frames * 2 * ch; /* 2 bytes/sample, 2 channels */ 95 | thiz->size = thiz->frames * 4 * ch; /* 4 bytes/sample, 2 channels */ 96 | thiz->buffer = (char*)malloc(thiz->size); 97 | 98 | snd_pcm_hw_params_get_period_time(params, &freq, &dir); 99 | return 0; 100 | } 101 | 102 | int AUDIO_frame(AUDIO *thiz) 103 | { 104 | int rc = snd_pcm_readi(thiz->handle, thiz->buffer, thiz->frames); 105 | if (rc == -EPIPE) { 106 | // EPIPE means overrun 107 | fprintf(stderr, "overrun occurred\n"); 108 | snd_pcm_prepare(thiz->handle); 109 | } else if (rc < 0) { 110 | fprintf(stderr, "read failed (%s)\n", snd_strerror(rc)); 111 | } else if (rc != (int)thiz->frames) { 112 | fprintf(stderr, "short read, read %d frames\n", rc); 113 | } 114 | return rc; 115 | } 116 | 117 | int AUDIO_play(AUDIO *thiz, char *data, int frames) 118 | { 119 | int rc = snd_pcm_writei(thiz->handle, data, frames); 120 | if (rc == -EPIPE) { 121 | // EPIPE means overrun 122 | fprintf(stderr, "overrun occurred\n"); 123 | snd_pcm_recover(thiz->handle, rc, 0); 124 | //snd_pcm_prepare(thiz->handle); 125 | } else if (rc < 0) { 126 | fprintf(stderr, "write failed (%s)\n", snd_strerror(rc)); 127 | } else if (rc != frames) { 128 | fprintf(stderr, "short write, write %d/%d frames\n", rc, (int)thiz->frames); 129 | } 130 | return rc; 131 | } 132 | 133 | int AUDIO_play0(AUDIO *thiz) 134 | { 135 | return AUDIO_play(thiz, thiz->buffer, thiz->frames); 136 | } 137 | 138 | void AUDIO_wait(AUDIO *thiz, int msec) 139 | { 140 | snd_pcm_wait(thiz->handle, msec); 141 | } 142 | 143 | void AUDIO_close(AUDIO *thiz) 144 | { 145 | snd_pcm_drain(thiz->handle); 146 | snd_pcm_close(thiz->handle); 147 | free(thiz->buffer); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /aplay+.c: -------------------------------------------------------------------------------- 1 | // ©2017-2022 Yuichiro Nakada 2 | // clang -Os -o aplay+ aplay+.c -lasound 3 | 4 | #include 5 | #include 6 | 7 | #include "alsa.h" 8 | #define DR_FLAC_IMPLEMENTATION 9 | #include "dr_flac.h" 10 | #define DR_WAV_IMPLEMENTATION 11 | #include "dr_wav.h" 12 | #define DR_MP3_IMPLEMENTATION 13 | #ifdef DR_MP3_IMPLEMENTATION 14 | #include "dr_mp3.h" 15 | #else 16 | #include "minimp3.h" 17 | #endif 18 | //#define HELIX_FEATURE_AUDIO_CODEC_AAC_SBR 19 | #define AAC_ENABLE_SBR 20 | #include "uaac.h" 21 | #include "uwma.h" 22 | #include "stb_vorbis.h" 23 | 24 | #define PARG_IMPLEMENTATION 25 | #include "parg.h" 26 | #include "regexp.h" 27 | 28 | #include "random.h" 29 | #include "ls.h" 30 | #include "kbhit.h" 31 | int cmd; 32 | int key(AUDIO *a) 33 | { 34 | /* int c = readch(); 35 | cmd = c; 36 | if (!c) return 0;*/ 37 | if (!kbhit()) return 0; 38 | int c = cmd = getchar(); 39 | 40 | printf("%x\n", c); 41 | if (c==0x20) { 42 | snd_pcm_pause(a->handle, 1); 43 | do { 44 | usleep(1000); // us 45 | //} while (!readch()); 46 | } while (!kbhit()); 47 | getchar(); // clear 48 | cmd = 0; 49 | //fseek(stdin, 0, SEEK_END); 50 | snd_pcm_pause(a->handle, 0); 51 | snd_pcm_prepare(a->handle); 52 | return 0; 53 | } 54 | 55 | return c; 56 | } 57 | 58 | //char *dev = "default"; // "plughw:0,0" 59 | char *dev = "hw:0,0"; // BitPerfect 60 | 61 | #define USE_FLOAT32 128 62 | #define FRAMES 32 63 | 64 | void play_wav(char *name, int format) 65 | { 66 | drwav wav; 67 | if (drwav_init_file(&wav, name, NULL)) { 68 | printf("%dHz %dch\n", wav.sampleRate, wav.channels); 69 | 70 | AUDIO a; 71 | if (AUDIO_init(&a, dev, wav.sampleRate, wav.channels, FRAMES, 1, format)) return; 72 | 73 | uint64_t (*func)(drwav* pWav, drflac_uint64 framesToRead, void* pBufferOut); 74 | if (format) { 75 | func = (uint64_t (*)(drwav *, drflac_uint64, void *))drwav_read_pcm_frames_f32; 76 | printf(" with FLOAT 32bit\n"); 77 | } else { 78 | func = (uint64_t (*)(drwav *, drflac_uint64, void *))drwav_read_pcm_frames_s16; 79 | } 80 | 81 | int c = 0; 82 | printf("\e[?25l"); 83 | size_t n; // numberOfSamplesActuallyDecoded 84 | // while ((n = drwav_read_pcm_frames_s16(&wav, a.frames, (drwav_int16*)a.buffer)) > 0) { 85 | while ((n = func(&wav, a.frames, (drwav_int16*)a.buffer)) > 0) { 86 | if (n!=a.frames) printf("!"); 87 | AUDIO_play0(&a); 88 | AUDIO_wait(&a, 100); 89 | if (key(&a)) break; 90 | 91 | printf("\r%d/%llu", c, wav.totalPCMFrameCount /*/ wav.channels*/); 92 | c += n; 93 | } 94 | 95 | AUDIO_close(&a); 96 | drwav_uninit(&wav); 97 | } 98 | } 99 | 100 | void play_flac(char *name, int format) 101 | { 102 | drflac *flac = drflac_open_file(name, NULL); 103 | printf("%dHz %dbit %dch\n", flac->sampleRate, flac->bitsPerSample, flac->channels); 104 | 105 | AUDIO a; 106 | if (AUDIO_init(&a, dev, flac->sampleRate, flac->channels, FRAMES, 1, format)) return; 107 | 108 | if (flac) { 109 | uint64_t (*func)(drflac* pFlac, drflac_uint64 framesToRead, void* pBufferOut); 110 | if (format) { 111 | func = (uint64_t (*)(drflac *, drflac_uint64, void *))drflac_read_pcm_frames_f32; 112 | printf(" with FLOAT 32bit\n"); 113 | } else { 114 | func = (uint64_t (*)(drflac *, drflac_uint64, void *))drflac_read_pcm_frames_s16; 115 | } 116 | 117 | int c = 0; 118 | printf("\e[?25l"); 119 | size_t n; // numberOfSamplesActuallyDecoded 120 | // while ((n = drflac_read_pcm_frames_s16(flac, a.frames, (drflac_int16*)a.buffer)) > 0) { 121 | // while ((n = drflac_read_pcm_frames_f32(flac, a.frames, (float*)a.buffer)) > 0) { 122 | while ((n = func(flac, a.frames, (void*)a.buffer)) > 0) { 123 | AUDIO_play0(&a); 124 | AUDIO_wait(&a, 100); 125 | if (key(&a)) break; 126 | 127 | printf("\r%d/%llu", c, flac->totalPCMFrameCount); 128 | //c += a.frames; 129 | c += n; 130 | } 131 | printf("\e[?25h"); 132 | } 133 | 134 | AUDIO_close(&a); 135 | drflac_close(flac); 136 | } 137 | #if 0 138 | void sr(double *a, int sa, double *b, int sb, int f, double *diff/*sb*2*/, double lambda/*1.0-2.0*/); 139 | void play_flac(char *name) 140 | { 141 | drflac *flac = drflac_open_file(name, NULL); 142 | printf("%dHz %dbit %dch (Upscaling to 192kHz)\n", flac->sampleRate, flac->bitsPerSample, flac->channels); 143 | 144 | AUDIO a; 145 | // if (AUDIO_init(&a, dev, flac->sampleRate, flac->channels, FRAMES, 1)) return; 146 | if (AUDIO_init(&a, dev, /*flac->sampleRate*/192000, flac->channels, FRAMES, 1)) return; 147 | 148 | // int size = a.frames; 149 | int size = a.frames * flac->sampleRate / 192000.0; 150 | double data[a.frames*2]; 151 | double diff[size*2]; 152 | double f64[size*2]; 153 | int32_t d32[size*2]; // in 154 | int16_t *d16 = (int16_t*)a.buffer; // out 155 | 156 | if (flac) { 157 | int c = 0; 158 | printf("\e[?25l"); 159 | size_t n; // numberOfSamplesActuallyDecoded 160 | while ((n = drflac_read_pcm_frames_s32(flac, size, d32)) > 0) { 161 | for (int i=0; i>16; 165 | // d16[i*2+1] = d32[i*2+1]>>16; 166 | // f64[i*2] = d32[i*2] / 2147483648.0; 167 | // f64[i*2+1] = d32[i*2+1] / 2147483648.0; 168 | 169 | f64[i*2] = d32[i*2]; 170 | f64[i*2+1] = d32[i*2+1]; 171 | } 172 | sr(data, a.frames, f64, size, 1, diff, 1.0); 173 | for (int i=0; itotalPCMFrameCount); 186 | c += n; 187 | } 188 | printf("\e[?25h"); 189 | } 190 | 191 | AUDIO_close(&a); 192 | drflac_close(flac); 193 | } 194 | #endif 195 | 196 | void *preload(char *name, int *len) 197 | { 198 | int fd = open(name, O_RDONLY); 199 | if (fd < 0) { 200 | printf("Error: cannot open `%s`\n", name); 201 | return 0; 202 | } 203 | *len = lseek(fd, 0, SEEK_END); 204 | void *p = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0); 205 | close(fd); 206 | return p; 207 | } 208 | #ifdef DR_MP3_IMPLEMENTATION 209 | int play_mp3(char *name, int format) 210 | { 211 | drmp3 mp3; 212 | if (!drmp3_init_file(&mp3, name, NULL)) { 213 | printf("Error: not a valid MP3 audio file!\n"); 214 | return 1; 215 | } 216 | 217 | printf("%dHz %dch\n", mp3.sampleRate, mp3.channels); 218 | AUDIO a; 219 | if (AUDIO_init(&a, dev, mp3.sampleRate, mp3.channels, FRAMES, 1, format)) { 220 | return 1; 221 | } 222 | 223 | uint64_t (*func)(drmp3*, drflac_uint64, void*); 224 | if (format) { 225 | func = (uint64_t (*)(drmp3 *, drflac_uint64, void *))drmp3_read_pcm_frames_f32; 226 | printf(" with FLOAT 32bit\n"); 227 | } else { 228 | func = (uint64_t (*)(drmp3 *, drflac_uint64, void *))drmp3_read_pcm_frames_s16; 229 | } 230 | 231 | int totalPCMFrameCount = drmp3_get_pcm_frame_count(&mp3); 232 | int c = 0; 233 | printf("\e[?25l"); 234 | size_t n; 235 | while ((n = func(&mp3, a.frames, (drmp3_int16*)a.buffer)) > 0) { 236 | AUDIO_play0(&a); 237 | AUDIO_wait(&a, 100); 238 | if (key(&a)) break; 239 | 240 | printf("\r%d/%d", c, totalPCMFrameCount); 241 | c += n; 242 | } 243 | printf("\e[?25h"); 244 | 245 | AUDIO_close(&a); 246 | drmp3_uninit(&mp3); 247 | return 0; 248 | } 249 | #else 250 | int play_mp3(char *name, int format) 251 | { 252 | short sample_buf[MP3_MAX_SAMPLES_PER_FRAME]; 253 | int len; 254 | void *file_data = preload(name, &len); 255 | unsigned char *stream_pos = (unsigned char *)file_data; 256 | int bytes_left = len - 100; 257 | 258 | mp3_info_t info; 259 | mp3_decoder_t mp3 = mp3_create(); 260 | int frame_size = mp3_decode(mp3, stream_pos, bytes_left, sample_buf, &info); 261 | if (!frame_size) { 262 | printf("Error: not a valid MP3 audio file!\n"); 263 | return 1; 264 | } 265 | 266 | printf("%dHz %dch\n", info.sample_rate, info.channels); 267 | AUDIO a; 268 | if (AUDIO_init(&a, dev, info.sample_rate, info.channels, FRAMES, 1, 0)) { 269 | return 1; 270 | } 271 | 272 | int c = 0; 273 | printf("\e[?25l"); 274 | while ((bytes_left >= 0) && (frame_size > 0) && !key(&a)) { 275 | printf("\r%d", c); 276 | 277 | stream_pos += frame_size; 278 | bytes_left -= frame_size; 279 | AUDIO_play(&a, (char*)sample_buf, info.audio_bytes/2/info.channels); 280 | AUDIO_wait(&a, 100); 281 | 282 | c += frame_size; 283 | frame_size = mp3_decode(mp3, stream_pos, bytes_left, sample_buf, NULL); 284 | } 285 | printf("\e[?25h"); 286 | 287 | AUDIO_close(&a); 288 | mp3_free(mp3); 289 | munmap(file_data, len); 290 | return 0; 291 | } 292 | #endif 293 | 294 | void play_ogg(char *name) 295 | { 296 | int n, num_c, error; 297 | //short *outputs; 298 | short outputs[FRAMES*2*100]; 299 | 300 | stb_vorbis *v = stb_vorbis_open_filename(name, &error, NULL); 301 | //if (!v) stb_fatal("Couldn't open {%s}", name); 302 | printf("%dHz %dch\n", v->sample_rate, v->channels); 303 | 304 | AUDIO a; 305 | if (AUDIO_init(&a, dev, v->sample_rate, v->channels, FRAMES*2, 1, 0)) { 306 | stb_vorbis_close(v); 307 | return; 308 | } 309 | 310 | int c = 0; 311 | printf("\e[?25l"); 312 | //while ((n = stb_vorbis_get_frame_short(v, 1, &outputs, FRAMES))) { 313 | while ((n = stb_vorbis_get_frame_short_interleaved(v, v->channels, outputs, FRAMES*100))) { 314 | printf("\r%d", c); 315 | c += n; 316 | AUDIO_play(&a, (char*)outputs, n); 317 | AUDIO_wait(&a, 100); 318 | if (key(&a)) break; 319 | } 320 | printf("\e[?25h"); 321 | 322 | AUDIO_close(&a); 323 | stb_vorbis_close(v); 324 | } 325 | 326 | int play_wma(char *name) 327 | { 328 | void *file_data; 329 | unsigned char *stream_pos; 330 | short *sample_buf = malloc(MAX_CODED_SUPERFRAME_SIZE *sizeof(short)); 331 | int bytes_left; 332 | 333 | int fd = open(name, O_RDONLY); 334 | if (fd < 0) { 335 | printf("Error: cannot open `%s`\n", name); 336 | return 1; 337 | } 338 | 339 | int len = lseek(fd, 0, SEEK_END); 340 | file_data = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0); 341 | stream_pos = (unsigned char *) file_data; 342 | bytes_left = len;// - 100; 343 | 344 | CodecContext cc; 345 | wma_decode_init_fixed(&cc); 346 | printf("%dHz %dch\n", cc.sample_rate, cc.channels); 347 | AUDIO a; 348 | if (AUDIO_init(&a, dev, cc.sample_rate, cc.channels, FRAMES, 1, 0)) { 349 | return 1; 350 | } 351 | 352 | int c = 0; 353 | printf("\e[?25l"); 354 | while ((bytes_left >= 0) && !key(&a)) { 355 | int size; 356 | int frame_size = wma_decode_superframe(&cc, stream_pos, &size, (uint8_t*)sample_buf, MAX_CODED_SUPERFRAME_SIZE); 357 | stream_pos += frame_size; 358 | bytes_left -= frame_size; 359 | AUDIO_play(&a, (char*)sample_buf, size/cc.channels); 360 | AUDIO_wait(&a, 100); 361 | 362 | printf("\r%d", c); 363 | c += frame_size; 364 | } 365 | printf("\e[?25h"); 366 | 367 | AUDIO_close(&a); 368 | wma_decode_end(&cc); 369 | munmap(file_data, len); 370 | close(fd); 371 | free(sample_buf); 372 | return 0; 373 | } 374 | 375 | int play_aac(char *name) 376 | { 377 | unsigned char *file_data; 378 | unsigned char *stream_pos; 379 | short sample_buf[AAC_BUF_SIZE*2]; 380 | int bytes_left; 381 | 382 | int fd = open(name, O_RDONLY); 383 | if (fd < 0) { 384 | printf("Error: cannot open `%s`\n", name); 385 | return 1; 386 | } 387 | 388 | int samplerate, channels; 389 | file_data = uaac_extract_aac(fd, &bytes_left, &samplerate, &channels); 390 | if (!file_data) { 391 | printf("Error: cannot read AAC data\n"); 392 | return 1; 393 | } 394 | stream_pos = file_data; 395 | 396 | AACFrameInfo info; 397 | memset(&info, 0, sizeof(AACFrameInfo)); 398 | info.nChans = channels; 399 | info.sampRateCore = samplerate; 400 | info.profile = AAC_PROFILE_LC; 401 | HAACDecoder aac = AACInitDecoder(); 402 | AACSetRawBlockParams(aac, 0, &info); 403 | 404 | printf("%dHz %dch\n", info.sampRateCore, info.nChans); 405 | AUDIO a; 406 | if (AUDIO_init(&a, dev, /*info.sampRateCore*/44100, info.nChans, FRAMES, 1, 0)) { 407 | // if (AUDIO_init(&a, dev, info.sampRateCore, info.nChans, FRAMES, 1)) { 408 | return 1; 409 | } 410 | 411 | printf("\e[?25l"); 412 | while ((bytes_left >= 0) && !key(&a)) { 413 | int r = AACDecode(aac, &stream_pos, &bytes_left, sample_buf); 414 | printf("\r%d %d", (int)(stream_pos-file_data), bytes_left); 415 | // int sbr = ((AACDecInfo*)aac)->sbrEnabled ? 2 : 1; 416 | // printf(" %d", sbr); 417 | if (!r) { 418 | AACGetLastFrameInfo(aac, &info); 419 | AUDIO_play(&a, (char*)sample_buf, AAC_MAX_NSAMPS); 420 | // AUDIO_play(&a, (char*)sample_buf, info.outputSamps/info.nChans/sbr); 421 | AUDIO_wait(&a, 100); 422 | } else { 423 | int nextSync = AACFindSyncWord(stream_pos, bytes_left); 424 | printf("\nAAC decode error %d\n", r); 425 | break; 426 | } 427 | } 428 | printf("\e[?25h"); 429 | 430 | AUDIO_close(&a); 431 | AACFreeDecoder(aac); 432 | free(file_data); 433 | close(fd); 434 | return 0; 435 | } 436 | 437 | void play_dir(char *name, char *type, char *regexp, int flag) 438 | { 439 | char path[1024], ext[10]; 440 | int num, back=0; 441 | int format = flag & USE_FLOAT32 ? SND_PCM_FORMAT_FLOAT_LE : 0; 442 | 443 | LS_LIST *ls = ls_dir(name, flag, &num); 444 | for (int i=0; i Specify ALSA device [e.g., default hw:0,0 plughw:0,0...]\n" 513 | "-f Use 32-bit floating-point playback\n" 514 | "-r Recursively search directories\n" 515 | "-x Enable random playback\n" 516 | "-s Search files with a regex\n" 517 | "-t Specify file type (e.g., flac, mp3, wma...)\n" 518 | "-p Optimize for Linux platforms\n" 519 | "\n", 520 | argv[0]); 521 | } 522 | 523 | int main(int argc, char *argv[]) 524 | { 525 | int flag = 0; 526 | char *dir = "."; 527 | char *type = 0; 528 | char *regexp = 0; 529 | struct parg_state ps; 530 | int c; 531 | int clock = 0; 532 | 533 | parg_init(&ps); 534 | while ((c = parg_getopt(&ps, argc, argv, "hd:frxs:t:p")) != -1) { 535 | switch (c) { 536 | case 1: 537 | dir = (char*)ps.optarg; 538 | break; 539 | case 'd': 540 | dev = (char*)ps.optarg; 541 | break; 542 | case 'f': 543 | flag |= USE_FLOAT32; 544 | break; 545 | case 'r': 546 | flag |= LS_RECURSIVE; 547 | break; 548 | case 'x': 549 | flag |= LS_RANDOM; 550 | break; 551 | case 's': 552 | regexp = (char*)ps.optarg; 553 | printf("Search with '%s'.\n", regexp); 554 | break; 555 | case 't': 556 | type = (char*)ps.optarg; 557 | break; 558 | case 'p': 559 | { 560 | // use tsc timer 561 | // cat /sys/devices/system/clocksource/clocksource0/available_clocksource 562 | FILE *fp = fopen("/sys/devices/system/clocksource/clocksource0/current_clocksource", "w"); 563 | fprintf(fp, "tsc"); 564 | fclose(fp); 565 | 566 | // Setting CPU clock to performance 567 | set_cpu("performance"); 568 | clock = 1; 569 | } 570 | break; 571 | case 'h': 572 | //default: 573 | usage(stderr, argc, argv); 574 | return 1; 575 | } 576 | } 577 | 578 | // init_keyboard(); 579 | play_dir(dir, type, regexp, flag); 580 | // close_keyboard(); 581 | 582 | if (clock) set_cpu("ondemand"); 583 | 584 | return 0; 585 | } 586 | -------------------------------------------------------------------------------- /aplay+.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "language_info": { 13 | "name": "python" 14 | } 15 | }, 16 | "cells": [ 17 | { 18 | "cell_type": "code", 19 | "execution_count": null, 20 | "metadata": { 21 | "id": "OarKXVee_u8Z" 22 | }, 23 | "outputs": [], 24 | "source": [ 25 | "%%bash\n", 26 | "\n", 27 | "sudo dpkg --configure -a\n", 28 | "\n", 29 | "# Add package repository\n", 30 | "sudo apt-get install -y gpg-agent wget\n", 31 | "wget -qO - https://repositories.intel.com/graphics/intel-graphics.key | sudo apt-key add -\n", 32 | "sudo apt-add-repository 'deb [arch=amd64] https://repositories.intel.com/graphics/ubuntu focal main'\n", 33 | "\n", 34 | "# Install run-time packages\n", 35 | "sudo apt-get update\n", 36 | "sudo apt-get install intel-opencl-icd intel-level-zero-gpu level-zero intel-media-va-driver-non-free libmfx1\n", 37 | "\n", 38 | "# OPTIONAL: Install developer packages\n", 39 | "sudo apt-get install libigc-dev intel-igc-cm libigdfcl-dev libigfxcmrt-dev level-zero-dev" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "source": [ 45 | "%%bash\n", 46 | "\n", 47 | "#cd /tmp\n", 48 | "#wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB\n", 49 | "#sudo apt-key add GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB\n", 50 | "#rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB\n", 51 | "#\n", 52 | "#echo \"deb https://apt.repos.intel.com/oneapi all main\" | sudo tee /etc/apt/sources.list.d/oneAPI.list\n", 53 | "#sudo apt update\n", 54 | "\n", 55 | "wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null\n", 56 | "echo \"deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main\" | sudo tee /etc/apt/sources.list.d/oneAPI.list\n", 57 | "sudo apt update" 58 | ], 59 | "metadata": { 60 | "id": "WlxIwl4gDVNl" 61 | }, 62 | "execution_count": null, 63 | "outputs": [] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "source": [ 68 | "%%bash\n", 69 | "sudo apt install intel-basekit\n", 70 | "sudo apt install intel-hpckit" 71 | ], 72 | "metadata": { 73 | "id": "MJgfzYMRDbLS" 74 | }, 75 | "execution_count": null, 76 | "outputs": [] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "source": [ 81 | "%%bash\n", 82 | "source /opt/intel/oneapi/setvars.sh\n", 83 | "icx --version\n", 84 | "#icc --version" 85 | ], 86 | "metadata": { 87 | "id": "n2ktRElMGaV7" 88 | }, 89 | "execution_count": null, 90 | "outputs": [] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "source": [ 95 | "%%bash\n", 96 | "apt install rpm\n", 97 | "apt install libasound2-dev" 98 | ], 99 | "metadata": { 100 | "id": "hzFGwaVwG6Ev" 101 | }, 102 | "execution_count": null, 103 | "outputs": [] 104 | }, 105 | { 106 | "cell_type": "code", 107 | "source": [ 108 | "%%bash\n", 109 | "source /opt/intel/oneapi/setvars.sh\n", 110 | "cd\n", 111 | "rm -rf aplay*\n", 112 | "git clone https://github.com/yui0/aplay-.git\n", 113 | "pushd aplay-\n", 114 | "#which icc\n", 115 | "#CC=icc make\n", 116 | "which icx\n", 117 | "CC=icx make\n", 118 | "popd\n", 119 | "mv aplay- aplay+-0.9\n", 120 | "tar cvjf aplay+-0.9.tar.bz2 aplay+-0.9\n", 121 | "rpmbuild -ta aplay+-0.9.tar.bz2 --nodeps\n", 122 | "mv /root/rpmbuild/SRPMS/aplay+-*.src.rpm /content\n", 123 | "mv /root/rpmbuild/RPMS/x86_64/aplay+-*.x86_64.rpm /content" 124 | ], 125 | "metadata": { 126 | "id": "o2yPMvAvHS-I" 127 | }, 128 | "execution_count": null, 129 | "outputs": [] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "source": [ 134 | "!curl bashupload.com -T aplay+-0.9-b1.x86_64.rpm" 135 | ], 136 | "metadata": { 137 | "id": "NlUnOD5j0bh9" 138 | }, 139 | "execution_count": null, 140 | "outputs": [] 141 | } 142 | ] 143 | } -------------------------------------------------------------------------------- /aplay+.spec: -------------------------------------------------------------------------------- 1 | %define name aplay+ 2 | %define version 0.9 3 | %define release b2 4 | 5 | Name: %{name} 6 | Summary: a simple BitPerfect player 7 | Version: %{version} 8 | Release: %{release} 9 | License: GPL 10 | Group: Applications/Multimedia 11 | Source: %{name}-%{version}.tar.bz2 12 | Buildroot: %{_tmppath}/%{name}-%{version} 13 | BuildRequires: alsa-lib-devel 14 | 15 | %description 16 | a simple BitPerfect player 17 | 18 | %prep 19 | %setup -q 20 | 21 | %build 22 | make 23 | 24 | %install 25 | mkdir -p %{buildroot}/usr/bin 26 | strip aplay+ 27 | install -m 755 aplay+ %{buildroot}/usr/bin 28 | 29 | %clean 30 | [ -n "%{buildroot}" -a "%{buildroot}" != / ] && rm -rf %{buildroot} 31 | rm -rf $RPM_BUILD_DIR/%{name}-%{version} 32 | 33 | %files 34 | %defattr (-,root,root) 35 | /usr/bin/* 36 | 37 | %changelog 38 | * Tue Mar 12 2019 Yuichiro Nakada 39 | - Create for Berry Linux 40 | -------------------------------------------------------------------------------- /kbhit.h: -------------------------------------------------------------------------------- 1 | /* public domain Simple, Minimalistic, kbhit function 2 | * ©2022 Yuichiro Nakada 3 | * */ 4 | 5 | #include 6 | #include 7 | 8 | int kbhit() 9 | { 10 | static const int STDIN = 0; 11 | static int initialized = 0; 12 | 13 | if (!initialized) { 14 | // Use termios to turn off line buffering 15 | struct termios term; 16 | tcgetattr(STDIN, &term); 17 | term.c_lflag &= ~ICANON; 18 | tcsetattr(STDIN, TCSANOW, &term); 19 | setbuf(stdin, NULL); 20 | initialized = 1; 21 | } 22 | 23 | int bytesWaiting; 24 | ioctl(STDIN, FIONREAD, &bytesWaiting); 25 | return bytesWaiting; 26 | } 27 | 28 | #if 0 29 | 30 | #if 0 31 | #include 32 | static struct termios t_old, t_new; 33 | void initTermios(int echo) 34 | { 35 | tcgetattr(0, &t_old); 36 | t_new = t_old; 37 | t_new.c_lflag &= ~ICANON; // disable buffered i/o 38 | if (echo) { 39 | t_new.c_lflag |= ECHO; // set echo mode 40 | } else { 41 | t_new.c_lflag &= ~ECHO; // set no echo mode 42 | } 43 | tcsetattr(0, TCSANOW, &t_new); 44 | } 45 | void resetTermios() 46 | { 47 | tcsetattr(0, TCSANOW, &t_old); 48 | } 49 | int getch_(int echo) 50 | { 51 | char ch; 52 | initTermios(echo); 53 | ch = getchar(); 54 | resetTermios(); 55 | return ch; 56 | } 57 | // Read 1 character without echo 58 | int _getch() 59 | { 60 | return getch_(0); 61 | } 62 | // Read 1 character with echo 63 | int _getche() 64 | { 65 | return getch_(1); 66 | } 67 | 68 | #define readch _getch 69 | #define init_keyboard() 70 | #define close_keyboard() 71 | 72 | #else 73 | #include 74 | #include // for read() 75 | 76 | static struct termios initial_settings, new_settings; 77 | //static int peek_character = -1; 78 | 79 | void init_keyboard() 80 | { 81 | tcgetattr(0, &initial_settings); 82 | new_settings = initial_settings; 83 | new_settings.c_lflag &= ~(ECHO | ECHONL | ICANON); 84 | new_settings.c_cc[VMIN] = 0; 85 | new_settings.c_cc[VTIME] = 0; 86 | 87 | // new_settings.c_iflag &= ~ICRNL; // ! \r -> \n 88 | // new_settings.c_oflag &= ~ONLCR; // ! \n -> \r 89 | new_settings.c_lflag &= ~ISIG; // ignore signal 90 | 91 | new_settings.c_iflag &= ~IXOFF; // control c-s, c-q [input] 92 | new_settings.c_iflag &= ~IXON; // control c-s, c-q [output] 93 | 94 | tcsetattr(0, TCSANOW, &new_settings); 95 | } 96 | 97 | void close_keyboard() 98 | { 99 | tcsetattr(0, TCSANOW, &initial_settings); 100 | } 101 | 102 | #define GETCH_BUF_LEN 256 103 | int getch2_len; 104 | unsigned char getch2_buf[GETCH_BUF_LEN]; 105 | 106 | /*int kbhit() 107 | { 108 | unsigned char ch; 109 | int nread; 110 | 111 | if (peek_character != -1) { 112 | return 1; 113 | } 114 | 115 | new_settings.c_cc[VMIN]=0; 116 | tcsetattr(0, TCSANOW, &new_settings); 117 | nread = read(0, &ch, 1); 118 | new_settings.c_cc[VMIN]=1; 119 | tcsetattr(0, TCSANOW, &new_settings); 120 | 121 | if (nread == 1) { 122 | peek_character = ch; 123 | return 1; 124 | } 125 | 126 | return 0; 127 | }*/ 128 | 129 | int readch() 130 | { 131 | /* char ch; 132 | 133 | if (peek_character != -1) { 134 | ch = peek_character; 135 | peek_character = -1; 136 | return ch; 137 | } 138 | read(0, &ch, 1); 139 | 140 | return ch;*/ 141 | 142 | unsigned char ch; 143 | read(0, &ch, 1); 144 | return ch; 145 | 146 | // https://raw.githubusercontent.com/larsmagne/mplayer/master/osdep/getch2.c 147 | /* int retval = read(0, &getch2_buf[getch2_len], GETCH_BUF_LEN-getch2_len); 148 | if (retval < 1) return 0; 149 | return getch2_buf[0];*/ 150 | /*getch2_len += retval; 151 | 152 | while (getch2_len > 0 && (getch2_len > 1 || getch2_buf[0] != 27)) { 153 | int i, len, code; 154 | len = 1; 155 | code = getch2_buf[0]; 156 | 157 | getch2_len -= len; 158 | for (i=0; i 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | //#define RANDOM_DEVICE "/dev/random" 21 | #define RANDOM_DEVICE "/dev/urandom" 22 | int urandom; 23 | void urandom_init() 24 | { 25 | urandom = open(RANDOM_DEVICE, O_RDONLY); 26 | if (urandom<0) { 27 | fprintf(stderr, "Failed to open %s\n", RANDOM_DEVICE); 28 | exit(EXIT_FAILURE); 29 | } 30 | } 31 | uint32_t urandom_number() 32 | { 33 | uint32_t c; 34 | read(urandom, &c, sizeof(c)); 35 | return c; 36 | } 37 | void urandom_end() 38 | { 39 | close(urandom); 40 | } 41 | /*static FILE *urandom; 42 | inline void urandom_init() 43 | { 44 | urandom = fopen(RANDOM_DEVICE, "rb"); 45 | if (urandom == NULL) { 46 | fprintf(stderr, "Failed to open %s\n", RANDOM_DEVICE); 47 | exit(EXIT_FAILURE); 48 | } 49 | } 50 | inline int urandom_number() 51 | { 52 | return fgetc(urandom); 53 | } 54 | inline void urandom_end() 55 | { 56 | fclose(urandom); 57 | }*/ 58 | 59 | #define LS_RECURSIVE 1 60 | #define LS_RANDOM 2 61 | 62 | typedef struct { 63 | int count, dir; 64 | char d_name[PATH_MAX]; 65 | } LS_LIST; 66 | 67 | int ls_count_dir(char *dir, int flag) 68 | { 69 | DIR *dp; 70 | struct dirent *entry; 71 | struct stat statbuf; 72 | 73 | if (!(dp = opendir(dir))) { 74 | perror("opendir"); 75 | printf("%s\n", dir); 76 | return 0; 77 | } 78 | char *cpath = getcwd(0, 0); 79 | chdir(dir); 80 | 81 | int i=0; 82 | while ((entry = readdir(dp))) { 83 | if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) continue; 84 | 85 | if (flag & LS_RECURSIVE) { 86 | stat(entry->d_name, &statbuf); 87 | if (S_ISDIR(statbuf.st_mode)) { 88 | char path[PATH_MAX]; 89 | sprintf(path, "%s/%s", dir, entry->d_name); 90 | i += ls_count_dir(path, flag); 91 | continue; // dir (no count) 92 | } 93 | } 94 | 95 | i++; 96 | } 97 | //printf("%s => %d\n", dir, i); 98 | 99 | closedir(dp); 100 | chdir(cpath); 101 | free(cpath); 102 | 103 | return i; 104 | } 105 | 106 | int ls_seek_dir(char *dir, LS_LIST *ls, int flag, int n) 107 | { 108 | DIR *dp; 109 | struct dirent *entry; 110 | struct stat statbuf; 111 | char buf[PATH_MAX]; 112 | 113 | if (!(dp = opendir(dir))) { 114 | perror("opendir"); 115 | printf("%s\n", dir); 116 | return 0; 117 | } 118 | char *cpath = getcwd(0, 0); 119 | chdir(dir); 120 | 121 | int i=0; 122 | while ((entry = readdir(dp))) { 123 | if (!strcmp(".", entry->d_name) || !strcmp("..", entry->d_name)) continue; 124 | 125 | sprintf(buf, "%s/%s", dir, entry->d_name); 126 | strcpy((ls+i)->d_name, buf); 127 | 128 | stat(entry->d_name, &statbuf); 129 | if (S_ISDIR(statbuf.st_mode)) { // dir (no count) 130 | (ls+i)->count = 0; // dir 131 | (ls+i)->dir = ++n; 132 | 133 | //if (flag & LS_RECURSIVE) i += ls_seek_dir(buf, ls+i+1, flag); 134 | if (flag & LS_RECURSIVE) i += ls_seek_dir(buf, ls+i, flag, n); 135 | } else { 136 | i++; 137 | (ls+i)->count = i; // count in dir 138 | (ls+i)->dir = n; 139 | } 140 | } 141 | 142 | closedir(dp); 143 | chdir(cpath); 144 | free(cpath); 145 | 146 | return i; 147 | } 148 | 149 | int ls_comp_func(const void *a, const void *b) 150 | { 151 | return (strcmp((char*)(((LS_LIST*)a)->d_name), (char*)(((LS_LIST*)b)->d_name))); 152 | } 153 | 154 | LS_LIST *ls_dir(char *_dir, int flag, int *num) 155 | { 156 | char dir[PATH_MAX+1]; 157 | realpath(_dir, dir); 158 | 159 | int n = ls_count_dir(dir, flag)+1; // FIXME: +1 ?? 160 | if (!n) { 161 | fprintf(stderr, "No file found in %s\n", dir); 162 | return 0; 163 | } 164 | 165 | LS_LIST *ls = (LS_LIST *)calloc(n, sizeof(LS_LIST)); 166 | if (!ls) { 167 | perror("calloc"); 168 | return 0; 169 | } 170 | 171 | if (!ls_seek_dir(dir, ls, flag, 0)) return 0; 172 | 173 | if (flag & LS_RANDOM) { 174 | #ifdef RANDOM_H 175 | // xor128_init(time(NULL)); 176 | urandom_init(); 177 | #else 178 | srand(time(NULL)); 179 | #endif 180 | for (int i=n-1; i>=0; i--) { // Fisher-Yates shuffle 181 | #ifdef RANDOM_H 182 | // int a = frand() * n; 183 | int a = (urandom_number() / 4294967295.0)*n; 184 | // int a = (prand32() / 4294967295.0)*n; 185 | #else 186 | int a = (rand() / RAND_MAX)*n; 187 | #endif 188 | LS_LIST b = ls[i]; 189 | ls[i] = ls[a]; 190 | ls[a] = b; 191 | } 192 | #ifdef RANDOM_H 193 | urandom_end(); 194 | #endif 195 | } else { 196 | qsort(ls, n, sizeof(LS_LIST), ls_comp_func); 197 | } 198 | 199 | *num = n; 200 | return ls; 201 | } 202 | 203 | #include 204 | char *findExt(char *path) 205 | { 206 | static char ext[10]; 207 | char *e = &ext[9]; 208 | *e-- = 0; 209 | int len = strlen(path)-1; 210 | for (int i=len; i>len-9; i--) { 211 | if (path[i] == '.' ) break; 212 | *e-- = tolower(path[i]); 213 | } 214 | return e+1; 215 | } 216 | 217 | #if 0 218 | int main(int argc, char *argv[]) 219 | { 220 | int num = 0; 221 | LS_LIST *ls = ls_dir(argv[1], LS_RECURSIVE, &num); 222 | for (int i=0; i 34 | 35 | #define MP3_MAX_SAMPLES_PER_FRAME (1152*2) 36 | typedef struct _mp3_info { 37 | int sample_rate; 38 | int channels; 39 | int audio_bytes; // generated amount of audio per frame 40 | } mp3_info_t; 41 | typedef void* mp3_decoder_t; 42 | extern mp3_decoder_t mp3_create(void); 43 | extern int mp3_decode(mp3_decoder_t *dec, void *buf, int bytes, signed short *out, mp3_info_t *info); 44 | extern void mp3_done(mp3_decoder_t *dec); 45 | #define mp3_free(dec) do { mp3_done(dec); dec = NULL; } while(0) 46 | size_t strlen(const char *s); 47 | #define out(text) write(1, (const void *) text, strlen(text)) 48 | 49 | #define MP3_FRAME_SIZE 1152 50 | #define MP3_MAX_CODED_FRAME_SIZE 1792 51 | #define MP3_MAX_CHANNELS 2 52 | #define SBLIMIT 32 53 | 54 | #define MP3_STEREO 0 55 | #define MP3_JSTEREO 1 56 | #define MP3_DUAL 2 57 | #define MP3_MONO 3 58 | 59 | #define SAME_HEADER_MASK \ 60 | (0xffe00000 | (3 << 17) | (0xf << 12) | (3 << 10) | (3 << 19)) 61 | 62 | #define FRAC_BITS 15 63 | #define WFRAC_BITS 14 64 | 65 | #define OUT_MAX (32767) 66 | #define OUT_MIN (-32768) 67 | #define OUT_SHIFT (WFRAC_BITS + FRAC_BITS - 15) 68 | 69 | #define MODE_EXT_MS_STEREO 2 70 | #define MODE_EXT_I_STEREO 1 71 | 72 | #define FRAC_ONE (1 << FRAC_BITS) 73 | #define FIX(a) ((int)((a) * FRAC_ONE)) 74 | #define FIXR(a) ((int)((a) * FRAC_ONE + 0.5)) 75 | #define FRAC_RND(a) (((a) + (FRAC_ONE/2)) >> FRAC_BITS) 76 | #define FIXHR(a) ((int)((a) * (1LL<<32) + 0.5)) 77 | 78 | #ifndef _MSC_VER 79 | #define MULL(a,b) (((int64_t)(a) * (int64_t)(b)) >> FRAC_BITS) 80 | #define MULH(a,b) (((int64_t)(a) * (int64_t)(b)) >> 32) 81 | #else 82 | static INLINE int MULL(int a, int b) 83 | { 84 | int res; 85 | __asm { 86 | mov eax, a 87 | imul b 88 | shr eax, 15 89 | shl edx, 17 90 | or eax, edx 91 | mov res, eax 92 | } 93 | return res; 94 | } 95 | static INLINE int MULH(int a, int b) 96 | { 97 | int res; 98 | __asm { 99 | mov eax, a 100 | imul b 101 | mov res, edx 102 | } 103 | return res; 104 | } 105 | #endif 106 | #define MULS(ra, rb) ((ra) * (rb)) 107 | 108 | #define ISQRT2 FIXR(0.70710678118654752440) 109 | 110 | #define HEADER_SIZE 4 111 | #define BACKSTEP_SIZE 512 112 | #define EXTRABYTES 24 113 | 114 | #define VLC_TYPE int16_t 115 | 116 | //////////////////////////////////////////////////////////////////////////////// 117 | 118 | struct _granule; 119 | 120 | typedef struct _bitstream { 121 | const uint8_t *buffer, *buffer_end; 122 | int index; 123 | int size_in_bits; 124 | } bitstream_t; 125 | 126 | typedef struct _vlc { 127 | int bits; 128 | VLC_TYPE (*table)[2]; ///< code, bits 129 | int table_size, table_allocated; 130 | } vlc_t; 131 | 132 | typedef struct _mp3_context { 133 | uint8_t last_buf[2*BACKSTEP_SIZE + EXTRABYTES]; 134 | int last_buf_size; 135 | int frame_size; 136 | uint32_t free_format_next_header; 137 | int error_protection; 138 | int sample_rate; 139 | int sample_rate_index; 140 | int bit_rate; 141 | bitstream_t gb; 142 | bitstream_t in_gb; 143 | int nb_channels; 144 | int mode; 145 | int mode_ext; 146 | int lsf; 147 | int16_t synth_buf[MP3_MAX_CHANNELS][512 * 2]; 148 | int synth_buf_offset[MP3_MAX_CHANNELS]; 149 | int32_t sb_samples[MP3_MAX_CHANNELS][36][SBLIMIT]; 150 | int32_t mdct_buf[MP3_MAX_CHANNELS][SBLIMIT * 18]; 151 | int dither_state; 152 | } mp3_context_t; 153 | 154 | typedef struct _granule { 155 | uint8_t scfsi; 156 | int part2_3_length; 157 | int big_values; 158 | int global_gain; 159 | int scalefac_compress; 160 | uint8_t block_type; 161 | uint8_t switch_point; 162 | int table_select[3]; 163 | int subblock_gain[3]; 164 | uint8_t scalefac_scale; 165 | uint8_t count1table_select; 166 | int region_size[3]; 167 | int preflag; 168 | int short_start, long_end; 169 | uint8_t scale_factors[40]; 170 | int32_t sb_hybrid[SBLIMIT * 18]; 171 | } granule_t; 172 | 173 | typedef struct _huff_table { 174 | int xsize; 175 | const uint8_t *bits; 176 | const uint16_t *codes; 177 | } huff_table_t; 178 | 179 | static vlc_t huff_vlc[16]; 180 | static vlc_t huff_quad_vlc[2]; 181 | static uint16_t band_index_long[9][23]; 182 | #define TABLE_4_3_SIZE (8191 + 16)*4 183 | static int8_t *table_4_3_exp; 184 | static uint32_t *table_4_3_value; 185 | static uint32_t exp_table[512]; 186 | static uint32_t expval_table[512][16]; 187 | static int32_t is_table[2][16]; 188 | static int32_t is_table_lsf[2][2][16]; 189 | static int32_t csa_table[8][4]; 190 | static float csa_table_float[8][4]; 191 | static int32_t mdct_win[8][36]; 192 | static int16_t window[512]; 193 | 194 | //////////////////////////////////////////////////////////////////////////////// 195 | 196 | static const uint16_t mp3_bitrate_tab[2][15] = { 197 | {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 }, 198 | {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160} 199 | }; 200 | 201 | static const uint16_t mp3_freq_tab[3] = { 44100, 48000, 32000 }; 202 | 203 | static const int32_t mp3_enwindow[257] = { 204 | 0, -1, -1, -1, -1, -1, -1, -2, 205 | -2, -2, -2, -3, -3, -4, -4, -5, 206 | -5, -6, -7, -7, -8, -9, -10, -11, 207 | -13, -14, -16, -17, -19, -21, -24, -26, 208 | -29, -31, -35, -38, -41, -45, -49, -53, 209 | -58, -63, -68, -73, -79, -85, -91, -97, 210 | -104, -111, -117, -125, -132, -139, -147, -154, 211 | -161, -169, -176, -183, -190, -196, -202, -208, 212 | 213, 218, 222, 225, 227, 228, 228, 227, 213 | 224, 221, 215, 208, 200, 189, 177, 163, 214 | 146, 127, 106, 83, 57, 29, -2, -36, 215 | -72, -111, -153, -197, -244, -294, -347, -401, 216 | -459, -519, -581, -645, -711, -779, -848, -919, 217 | -991, -1064, -1137, -1210, -1283, -1356, -1428, -1498, 218 | -1567, -1634, -1698, -1759, -1817, -1870, -1919, -1962, 219 | -2001, -2032, -2057, -2075, -2085, -2087, -2080, -2063, 220 | 2037, 2000, 1952, 1893, 1822, 1739, 1644, 1535, 221 | 1414, 1280, 1131, 970, 794, 605, 402, 185, 222 | -45, -288, -545, -814, -1095, -1388, -1692, -2006, 223 | -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788, 224 | -5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597, 225 | -7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585, 226 | -9727, -9838, -9916, -9959, -9966, -9935, -9863, -9750, 227 | -9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134, 228 | 6574, 5959, 5288, 4561, 3776, 2935, 2037, 1082, 229 | 70, -998, -2122, -3300, -4533, -5818, -7154, -8540, 230 | -9975,-11455,-12980,-14548,-16155,-17799,-19478,-21189, 231 | -22929,-24694,-26482,-28289,-30112,-31947,-33791,-35640, 232 | -37489,-39336,-41176,-43006,-44821,-46617,-48390,-50137, 233 | -51853,-53534,-55178,-56778,-58333,-59838,-61289,-62684, 234 | -64019,-65290,-66494,-67629,-68692,-69679,-70590,-71420, 235 | -72169,-72835,-73415,-73908,-74313,-74630,-74856,-74992, 236 | 75038, 237 | }; 238 | 239 | static const uint8_t slen_table[2][16] = { 240 | { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 }, 241 | { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 }, 242 | }; 243 | 244 | static const uint8_t lsf_nsf_table[6][3][4] = { 245 | { { 6, 5, 5, 5 }, { 9, 9, 9, 9 }, { 6, 9, 9, 9 } }, 246 | { { 6, 5, 7, 3 }, { 9, 9, 12, 6 }, { 6, 9, 12, 6 } }, 247 | { { 11, 10, 0, 0 }, { 18, 18, 0, 0 }, { 15, 18, 0, 0 } }, 248 | { { 7, 7, 7, 0 }, { 12, 12, 12, 0 }, { 6, 15, 12, 0 } }, 249 | { { 6, 6, 6, 3 }, { 12, 9, 9, 6 }, { 6, 12, 9, 6 } }, 250 | { { 8, 8, 5, 0 }, { 15, 12, 9, 0 }, { 6, 18, 9, 0 } }, 251 | }; 252 | 253 | static const uint16_t mp3_huffcodes_1[4] = { 254 | 0x0001, 0x0001, 0x0001, 0x0000, 255 | }; 256 | 257 | static const uint8_t mp3_huffbits_1[4] = { 258 | 1, 3, 2, 3, 259 | }; 260 | 261 | static const uint16_t mp3_huffcodes_2[9] = { 262 | 0x0001, 0x0002, 0x0001, 0x0003, 0x0001, 0x0001, 0x0003, 0x0002, 263 | 0x0000, 264 | }; 265 | 266 | static const uint8_t mp3_huffbits_2[9] = { 267 | 1, 3, 6, 3, 3, 5, 5, 5, 268 | 6, 269 | }; 270 | 271 | static const uint16_t mp3_huffcodes_3[9] = { 272 | 0x0003, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0002, 273 | 0x0000, 274 | }; 275 | 276 | static const uint8_t mp3_huffbits_3[9] = { 277 | 2, 2, 6, 3, 2, 5, 5, 5, 278 | 6, 279 | }; 280 | 281 | static const uint16_t mp3_huffcodes_5[16] = { 282 | 0x0001, 0x0002, 0x0006, 0x0005, 0x0003, 0x0001, 0x0004, 0x0004, 283 | 0x0007, 0x0005, 0x0007, 0x0001, 0x0006, 0x0001, 0x0001, 0x0000, 284 | }; 285 | 286 | static const uint8_t mp3_huffbits_5[16] = { 287 | 1, 3, 6, 7, 3, 3, 6, 7, 288 | 6, 6, 7, 8, 7, 6, 7, 8, 289 | }; 290 | 291 | static const uint16_t mp3_huffcodes_6[16] = { 292 | 0x0007, 0x0003, 0x0005, 0x0001, 0x0006, 0x0002, 0x0003, 0x0002, 293 | 0x0005, 0x0004, 0x0004, 0x0001, 0x0003, 0x0003, 0x0002, 0x0000, 294 | }; 295 | 296 | static const uint8_t mp3_huffbits_6[16] = { 297 | 3, 3, 5, 7, 3, 2, 4, 5, 298 | 4, 4, 5, 6, 6, 5, 6, 7, 299 | }; 300 | 301 | static const uint16_t mp3_huffcodes_7[36] = { 302 | 0x0001, 0x0002, 0x000a, 0x0013, 0x0010, 0x000a, 0x0003, 0x0003, 303 | 0x0007, 0x000a, 0x0005, 0x0003, 0x000b, 0x0004, 0x000d, 0x0011, 304 | 0x0008, 0x0004, 0x000c, 0x000b, 0x0012, 0x000f, 0x000b, 0x0002, 305 | 0x0007, 0x0006, 0x0009, 0x000e, 0x0003, 0x0001, 0x0006, 0x0004, 306 | 0x0005, 0x0003, 0x0002, 0x0000, 307 | }; 308 | 309 | static const uint8_t mp3_huffbits_7[36] = { 310 | 1, 3, 6, 8, 8, 9, 3, 4, 311 | 6, 7, 7, 8, 6, 5, 7, 8, 312 | 8, 9, 7, 7, 8, 9, 9, 9, 313 | 7, 7, 8, 9, 9, 10, 8, 8, 314 | 9, 10, 10, 10, 315 | }; 316 | 317 | static const uint16_t mp3_huffcodes_8[36] = { 318 | 0x0003, 0x0004, 0x0006, 0x0012, 0x000c, 0x0005, 0x0005, 0x0001, 319 | 0x0002, 0x0010, 0x0009, 0x0003, 0x0007, 0x0003, 0x0005, 0x000e, 320 | 0x0007, 0x0003, 0x0013, 0x0011, 0x000f, 0x000d, 0x000a, 0x0004, 321 | 0x000d, 0x0005, 0x0008, 0x000b, 0x0005, 0x0001, 0x000c, 0x0004, 322 | 0x0004, 0x0001, 0x0001, 0x0000, 323 | }; 324 | 325 | static const uint8_t mp3_huffbits_8[36] = { 326 | 2, 3, 6, 8, 8, 9, 3, 2, 327 | 4, 8, 8, 8, 6, 4, 6, 8, 328 | 8, 9, 8, 8, 8, 9, 9, 10, 329 | 8, 7, 8, 9, 10, 10, 9, 8, 330 | 9, 9, 11, 11, 331 | }; 332 | 333 | static const uint16_t mp3_huffcodes_9[36] = { 334 | 0x0007, 0x0005, 0x0009, 0x000e, 0x000f, 0x0007, 0x0006, 0x0004, 335 | 0x0005, 0x0005, 0x0006, 0x0007, 0x0007, 0x0006, 0x0008, 0x0008, 336 | 0x0008, 0x0005, 0x000f, 0x0006, 0x0009, 0x000a, 0x0005, 0x0001, 337 | 0x000b, 0x0007, 0x0009, 0x0006, 0x0004, 0x0001, 0x000e, 0x0004, 338 | 0x0006, 0x0002, 0x0006, 0x0000, 339 | }; 340 | 341 | static const uint8_t mp3_huffbits_9[36] = { 342 | 3, 3, 5, 6, 8, 9, 3, 3, 343 | 4, 5, 6, 8, 4, 4, 5, 6, 344 | 7, 8, 6, 5, 6, 7, 7, 8, 345 | 7, 6, 7, 7, 8, 9, 8, 7, 346 | 8, 8, 9, 9, 347 | }; 348 | 349 | static const uint16_t mp3_huffcodes_10[64] = { 350 | 0x0001, 0x0002, 0x000a, 0x0017, 0x0023, 0x001e, 0x000c, 0x0011, 351 | 0x0003, 0x0003, 0x0008, 0x000c, 0x0012, 0x0015, 0x000c, 0x0007, 352 | 0x000b, 0x0009, 0x000f, 0x0015, 0x0020, 0x0028, 0x0013, 0x0006, 353 | 0x000e, 0x000d, 0x0016, 0x0022, 0x002e, 0x0017, 0x0012, 0x0007, 354 | 0x0014, 0x0013, 0x0021, 0x002f, 0x001b, 0x0016, 0x0009, 0x0003, 355 | 0x001f, 0x0016, 0x0029, 0x001a, 0x0015, 0x0014, 0x0005, 0x0003, 356 | 0x000e, 0x000d, 0x000a, 0x000b, 0x0010, 0x0006, 0x0005, 0x0001, 357 | 0x0009, 0x0008, 0x0007, 0x0008, 0x0004, 0x0004, 0x0002, 0x0000, 358 | }; 359 | 360 | static const uint8_t mp3_huffbits_10[64] = { 361 | 1, 3, 6, 8, 9, 9, 9, 10, 362 | 3, 4, 6, 7, 8, 9, 8, 8, 363 | 6, 6, 7, 8, 9, 10, 9, 9, 364 | 7, 7, 8, 9, 10, 10, 9, 10, 365 | 8, 8, 9, 10, 10, 10, 10, 10, 366 | 9, 9, 10, 10, 11, 11, 10, 11, 367 | 8, 8, 9, 10, 10, 10, 11, 11, 368 | 9, 8, 9, 10, 10, 11, 11, 11, 369 | }; 370 | 371 | static const uint16_t mp3_huffcodes_11[64] = { 372 | 0x0003, 0x0004, 0x000a, 0x0018, 0x0022, 0x0021, 0x0015, 0x000f, 373 | 0x0005, 0x0003, 0x0004, 0x000a, 0x0020, 0x0011, 0x000b, 0x000a, 374 | 0x000b, 0x0007, 0x000d, 0x0012, 0x001e, 0x001f, 0x0014, 0x0005, 375 | 0x0019, 0x000b, 0x0013, 0x003b, 0x001b, 0x0012, 0x000c, 0x0005, 376 | 0x0023, 0x0021, 0x001f, 0x003a, 0x001e, 0x0010, 0x0007, 0x0005, 377 | 0x001c, 0x001a, 0x0020, 0x0013, 0x0011, 0x000f, 0x0008, 0x000e, 378 | 0x000e, 0x000c, 0x0009, 0x000d, 0x000e, 0x0009, 0x0004, 0x0001, 379 | 0x000b, 0x0004, 0x0006, 0x0006, 0x0006, 0x0003, 0x0002, 0x0000, 380 | }; 381 | 382 | static const uint8_t mp3_huffbits_11[64] = { 383 | 2, 3, 5, 7, 8, 9, 8, 9, 384 | 3, 3, 4, 6, 8, 8, 7, 8, 385 | 5, 5, 6, 7, 8, 9, 8, 8, 386 | 7, 6, 7, 9, 8, 10, 8, 9, 387 | 8, 8, 8, 9, 9, 10, 9, 10, 388 | 8, 8, 9, 10, 10, 11, 10, 11, 389 | 8, 7, 7, 8, 9, 10, 10, 10, 390 | 8, 7, 8, 9, 10, 10, 10, 10, 391 | }; 392 | 393 | static const uint16_t mp3_huffcodes_12[64] = { 394 | 0x0009, 0x0006, 0x0010, 0x0021, 0x0029, 0x0027, 0x0026, 0x001a, 395 | 0x0007, 0x0005, 0x0006, 0x0009, 0x0017, 0x0010, 0x001a, 0x000b, 396 | 0x0011, 0x0007, 0x000b, 0x000e, 0x0015, 0x001e, 0x000a, 0x0007, 397 | 0x0011, 0x000a, 0x000f, 0x000c, 0x0012, 0x001c, 0x000e, 0x0005, 398 | 0x0020, 0x000d, 0x0016, 0x0013, 0x0012, 0x0010, 0x0009, 0x0005, 399 | 0x0028, 0x0011, 0x001f, 0x001d, 0x0011, 0x000d, 0x0004, 0x0002, 400 | 0x001b, 0x000c, 0x000b, 0x000f, 0x000a, 0x0007, 0x0004, 0x0001, 401 | 0x001b, 0x000c, 0x0008, 0x000c, 0x0006, 0x0003, 0x0001, 0x0000, 402 | }; 403 | 404 | static const uint8_t mp3_huffbits_12[64] = { 405 | 4, 3, 5, 7, 8, 9, 9, 9, 406 | 3, 3, 4, 5, 7, 7, 8, 8, 407 | 5, 4, 5, 6, 7, 8, 7, 8, 408 | 6, 5, 6, 6, 7, 8, 8, 8, 409 | 7, 6, 7, 7, 8, 8, 8, 9, 410 | 8, 7, 8, 8, 8, 9, 8, 9, 411 | 8, 7, 7, 8, 8, 9, 9, 10, 412 | 9, 8, 8, 9, 9, 9, 9, 10, 413 | }; 414 | 415 | static const uint16_t mp3_huffcodes_13[256] = { 416 | 0x0001, 0x0005, 0x000e, 0x0015, 0x0022, 0x0033, 0x002e, 0x0047, 417 | 0x002a, 0x0034, 0x0044, 0x0034, 0x0043, 0x002c, 0x002b, 0x0013, 418 | 0x0003, 0x0004, 0x000c, 0x0013, 0x001f, 0x001a, 0x002c, 0x0021, 419 | 0x001f, 0x0018, 0x0020, 0x0018, 0x001f, 0x0023, 0x0016, 0x000e, 420 | 0x000f, 0x000d, 0x0017, 0x0024, 0x003b, 0x0031, 0x004d, 0x0041, 421 | 0x001d, 0x0028, 0x001e, 0x0028, 0x001b, 0x0021, 0x002a, 0x0010, 422 | 0x0016, 0x0014, 0x0025, 0x003d, 0x0038, 0x004f, 0x0049, 0x0040, 423 | 0x002b, 0x004c, 0x0038, 0x0025, 0x001a, 0x001f, 0x0019, 0x000e, 424 | 0x0023, 0x0010, 0x003c, 0x0039, 0x0061, 0x004b, 0x0072, 0x005b, 425 | 0x0036, 0x0049, 0x0037, 0x0029, 0x0030, 0x0035, 0x0017, 0x0018, 426 | 0x003a, 0x001b, 0x0032, 0x0060, 0x004c, 0x0046, 0x005d, 0x0054, 427 | 0x004d, 0x003a, 0x004f, 0x001d, 0x004a, 0x0031, 0x0029, 0x0011, 428 | 0x002f, 0x002d, 0x004e, 0x004a, 0x0073, 0x005e, 0x005a, 0x004f, 429 | 0x0045, 0x0053, 0x0047, 0x0032, 0x003b, 0x0026, 0x0024, 0x000f, 430 | 0x0048, 0x0022, 0x0038, 0x005f, 0x005c, 0x0055, 0x005b, 0x005a, 431 | 0x0056, 0x0049, 0x004d, 0x0041, 0x0033, 0x002c, 0x002b, 0x002a, 432 | 0x002b, 0x0014, 0x001e, 0x002c, 0x0037, 0x004e, 0x0048, 0x0057, 433 | 0x004e, 0x003d, 0x002e, 0x0036, 0x0025, 0x001e, 0x0014, 0x0010, 434 | 0x0035, 0x0019, 0x0029, 0x0025, 0x002c, 0x003b, 0x0036, 0x0051, 435 | 0x0042, 0x004c, 0x0039, 0x0036, 0x0025, 0x0012, 0x0027, 0x000b, 436 | 0x0023, 0x0021, 0x001f, 0x0039, 0x002a, 0x0052, 0x0048, 0x0050, 437 | 0x002f, 0x003a, 0x0037, 0x0015, 0x0016, 0x001a, 0x0026, 0x0016, 438 | 0x0035, 0x0019, 0x0017, 0x0026, 0x0046, 0x003c, 0x0033, 0x0024, 439 | 0x0037, 0x001a, 0x0022, 0x0017, 0x001b, 0x000e, 0x0009, 0x0007, 440 | 0x0022, 0x0020, 0x001c, 0x0027, 0x0031, 0x004b, 0x001e, 0x0034, 441 | 0x0030, 0x0028, 0x0034, 0x001c, 0x0012, 0x0011, 0x0009, 0x0005, 442 | 0x002d, 0x0015, 0x0022, 0x0040, 0x0038, 0x0032, 0x0031, 0x002d, 443 | 0x001f, 0x0013, 0x000c, 0x000f, 0x000a, 0x0007, 0x0006, 0x0003, 444 | 0x0030, 0x0017, 0x0014, 0x0027, 0x0024, 0x0023, 0x0035, 0x0015, 445 | 0x0010, 0x0017, 0x000d, 0x000a, 0x0006, 0x0001, 0x0004, 0x0002, 446 | 0x0010, 0x000f, 0x0011, 0x001b, 0x0019, 0x0014, 0x001d, 0x000b, 447 | 0x0011, 0x000c, 0x0010, 0x0008, 0x0001, 0x0001, 0x0000, 0x0001, 448 | }; 449 | 450 | static const uint8_t mp3_huffbits_13[256] = { 451 | 1, 4, 6, 7, 8, 9, 9, 10, 452 | 9, 10, 11, 11, 12, 12, 13, 13, 453 | 3, 4, 6, 7, 8, 8, 9, 9, 454 | 9, 9, 10, 10, 11, 12, 12, 12, 455 | 6, 6, 7, 8, 9, 9, 10, 10, 456 | 9, 10, 10, 11, 11, 12, 13, 13, 457 | 7, 7, 8, 9, 9, 10, 10, 10, 458 | 10, 11, 11, 11, 11, 12, 13, 13, 459 | 8, 7, 9, 9, 10, 10, 11, 11, 460 | 10, 11, 11, 12, 12, 13, 13, 14, 461 | 9, 8, 9, 10, 10, 10, 11, 11, 462 | 11, 11, 12, 11, 13, 13, 14, 14, 463 | 9, 9, 10, 10, 11, 11, 11, 11, 464 | 11, 12, 12, 12, 13, 13, 14, 14, 465 | 10, 9, 10, 11, 11, 11, 12, 12, 466 | 12, 12, 13, 13, 13, 14, 16, 16, 467 | 9, 8, 9, 10, 10, 11, 11, 12, 468 | 12, 12, 12, 13, 13, 14, 15, 15, 469 | 10, 9, 10, 10, 11, 11, 11, 13, 470 | 12, 13, 13, 14, 14, 14, 16, 15, 471 | 10, 10, 10, 11, 11, 12, 12, 13, 472 | 12, 13, 14, 13, 14, 15, 16, 17, 473 | 11, 10, 10, 11, 12, 12, 12, 12, 474 | 13, 13, 13, 14, 15, 15, 15, 16, 475 | 11, 11, 11, 12, 12, 13, 12, 13, 476 | 14, 14, 15, 15, 15, 16, 16, 16, 477 | 12, 11, 12, 13, 13, 13, 14, 14, 478 | 14, 14, 14, 15, 16, 15, 16, 16, 479 | 13, 12, 12, 13, 13, 13, 15, 14, 480 | 14, 17, 15, 15, 15, 17, 16, 16, 481 | 12, 12, 13, 14, 14, 14, 15, 14, 482 | 15, 15, 16, 16, 19, 18, 19, 16, 483 | }; 484 | 485 | static const uint16_t mp3_huffcodes_15[256] = { 486 | 0x0007, 0x000c, 0x0012, 0x0035, 0x002f, 0x004c, 0x007c, 0x006c, 487 | 0x0059, 0x007b, 0x006c, 0x0077, 0x006b, 0x0051, 0x007a, 0x003f, 488 | 0x000d, 0x0005, 0x0010, 0x001b, 0x002e, 0x0024, 0x003d, 0x0033, 489 | 0x002a, 0x0046, 0x0034, 0x0053, 0x0041, 0x0029, 0x003b, 0x0024, 490 | 0x0013, 0x0011, 0x000f, 0x0018, 0x0029, 0x0022, 0x003b, 0x0030, 491 | 0x0028, 0x0040, 0x0032, 0x004e, 0x003e, 0x0050, 0x0038, 0x0021, 492 | 0x001d, 0x001c, 0x0019, 0x002b, 0x0027, 0x003f, 0x0037, 0x005d, 493 | 0x004c, 0x003b, 0x005d, 0x0048, 0x0036, 0x004b, 0x0032, 0x001d, 494 | 0x0034, 0x0016, 0x002a, 0x0028, 0x0043, 0x0039, 0x005f, 0x004f, 495 | 0x0048, 0x0039, 0x0059, 0x0045, 0x0031, 0x0042, 0x002e, 0x001b, 496 | 0x004d, 0x0025, 0x0023, 0x0042, 0x003a, 0x0034, 0x005b, 0x004a, 497 | 0x003e, 0x0030, 0x004f, 0x003f, 0x005a, 0x003e, 0x0028, 0x0026, 498 | 0x007d, 0x0020, 0x003c, 0x0038, 0x0032, 0x005c, 0x004e, 0x0041, 499 | 0x0037, 0x0057, 0x0047, 0x0033, 0x0049, 0x0033, 0x0046, 0x001e, 500 | 0x006d, 0x0035, 0x0031, 0x005e, 0x0058, 0x004b, 0x0042, 0x007a, 501 | 0x005b, 0x0049, 0x0038, 0x002a, 0x0040, 0x002c, 0x0015, 0x0019, 502 | 0x005a, 0x002b, 0x0029, 0x004d, 0x0049, 0x003f, 0x0038, 0x005c, 503 | 0x004d, 0x0042, 0x002f, 0x0043, 0x0030, 0x0035, 0x0024, 0x0014, 504 | 0x0047, 0x0022, 0x0043, 0x003c, 0x003a, 0x0031, 0x0058, 0x004c, 505 | 0x0043, 0x006a, 0x0047, 0x0036, 0x0026, 0x0027, 0x0017, 0x000f, 506 | 0x006d, 0x0035, 0x0033, 0x002f, 0x005a, 0x0052, 0x003a, 0x0039, 507 | 0x0030, 0x0048, 0x0039, 0x0029, 0x0017, 0x001b, 0x003e, 0x0009, 508 | 0x0056, 0x002a, 0x0028, 0x0025, 0x0046, 0x0040, 0x0034, 0x002b, 509 | 0x0046, 0x0037, 0x002a, 0x0019, 0x001d, 0x0012, 0x000b, 0x000b, 510 | 0x0076, 0x0044, 0x001e, 0x0037, 0x0032, 0x002e, 0x004a, 0x0041, 511 | 0x0031, 0x0027, 0x0018, 0x0010, 0x0016, 0x000d, 0x000e, 0x0007, 512 | 0x005b, 0x002c, 0x0027, 0x0026, 0x0022, 0x003f, 0x0034, 0x002d, 513 | 0x001f, 0x0034, 0x001c, 0x0013, 0x000e, 0x0008, 0x0009, 0x0003, 514 | 0x007b, 0x003c, 0x003a, 0x0035, 0x002f, 0x002b, 0x0020, 0x0016, 515 | 0x0025, 0x0018, 0x0011, 0x000c, 0x000f, 0x000a, 0x0002, 0x0001, 516 | 0x0047, 0x0025, 0x0022, 0x001e, 0x001c, 0x0014, 0x0011, 0x001a, 517 | 0x0015, 0x0010, 0x000a, 0x0006, 0x0008, 0x0006, 0x0002, 0x0000, 518 | }; 519 | 520 | static const uint8_t mp3_huffbits_15[256] = { 521 | 3, 4, 5, 7, 7, 8, 9, 9, 522 | 9, 10, 10, 11, 11, 11, 12, 13, 523 | 4, 3, 5, 6, 7, 7, 8, 8, 524 | 8, 9, 9, 10, 10, 10, 11, 11, 525 | 5, 5, 5, 6, 7, 7, 8, 8, 526 | 8, 9, 9, 10, 10, 11, 11, 11, 527 | 6, 6, 6, 7, 7, 8, 8, 9, 528 | 9, 9, 10, 10, 10, 11, 11, 11, 529 | 7, 6, 7, 7, 8, 8, 9, 9, 530 | 9, 9, 10, 10, 10, 11, 11, 11, 531 | 8, 7, 7, 8, 8, 8, 9, 9, 532 | 9, 9, 10, 10, 11, 11, 11, 12, 533 | 9, 7, 8, 8, 8, 9, 9, 9, 534 | 9, 10, 10, 10, 11, 11, 12, 12, 535 | 9, 8, 8, 9, 9, 9, 9, 10, 536 | 10, 10, 10, 10, 11, 11, 11, 12, 537 | 9, 8, 8, 9, 9, 9, 9, 10, 538 | 10, 10, 10, 11, 11, 12, 12, 12, 539 | 9, 8, 9, 9, 9, 9, 10, 10, 540 | 10, 11, 11, 11, 11, 12, 12, 12, 541 | 10, 9, 9, 9, 10, 10, 10, 10, 542 | 10, 11, 11, 11, 11, 12, 13, 12, 543 | 10, 9, 9, 9, 10, 10, 10, 10, 544 | 11, 11, 11, 11, 12, 12, 12, 13, 545 | 11, 10, 9, 10, 10, 10, 11, 11, 546 | 11, 11, 11, 11, 12, 12, 13, 13, 547 | 11, 10, 10, 10, 10, 11, 11, 11, 548 | 11, 12, 12, 12, 12, 12, 13, 13, 549 | 12, 11, 11, 11, 11, 11, 11, 11, 550 | 12, 12, 12, 12, 13, 13, 12, 13, 551 | 12, 11, 11, 11, 11, 11, 11, 12, 552 | 12, 12, 12, 12, 13, 13, 13, 13, 553 | }; 554 | 555 | static const uint16_t mp3_huffcodes_16[256] = { 556 | 0x0001, 0x0005, 0x000e, 0x002c, 0x004a, 0x003f, 0x006e, 0x005d, 557 | 0x00ac, 0x0095, 0x008a, 0x00f2, 0x00e1, 0x00c3, 0x0178, 0x0011, 558 | 0x0003, 0x0004, 0x000c, 0x0014, 0x0023, 0x003e, 0x0035, 0x002f, 559 | 0x0053, 0x004b, 0x0044, 0x0077, 0x00c9, 0x006b, 0x00cf, 0x0009, 560 | 0x000f, 0x000d, 0x0017, 0x0026, 0x0043, 0x003a, 0x0067, 0x005a, 561 | 0x00a1, 0x0048, 0x007f, 0x0075, 0x006e, 0x00d1, 0x00ce, 0x0010, 562 | 0x002d, 0x0015, 0x0027, 0x0045, 0x0040, 0x0072, 0x0063, 0x0057, 563 | 0x009e, 0x008c, 0x00fc, 0x00d4, 0x00c7, 0x0183, 0x016d, 0x001a, 564 | 0x004b, 0x0024, 0x0044, 0x0041, 0x0073, 0x0065, 0x00b3, 0x00a4, 565 | 0x009b, 0x0108, 0x00f6, 0x00e2, 0x018b, 0x017e, 0x016a, 0x0009, 566 | 0x0042, 0x001e, 0x003b, 0x0038, 0x0066, 0x00b9, 0x00ad, 0x0109, 567 | 0x008e, 0x00fd, 0x00e8, 0x0190, 0x0184, 0x017a, 0x01bd, 0x0010, 568 | 0x006f, 0x0036, 0x0034, 0x0064, 0x00b8, 0x00b2, 0x00a0, 0x0085, 569 | 0x0101, 0x00f4, 0x00e4, 0x00d9, 0x0181, 0x016e, 0x02cb, 0x000a, 570 | 0x0062, 0x0030, 0x005b, 0x0058, 0x00a5, 0x009d, 0x0094, 0x0105, 571 | 0x00f8, 0x0197, 0x018d, 0x0174, 0x017c, 0x0379, 0x0374, 0x0008, 572 | 0x0055, 0x0054, 0x0051, 0x009f, 0x009c, 0x008f, 0x0104, 0x00f9, 573 | 0x01ab, 0x0191, 0x0188, 0x017f, 0x02d7, 0x02c9, 0x02c4, 0x0007, 574 | 0x009a, 0x004c, 0x0049, 0x008d, 0x0083, 0x0100, 0x00f5, 0x01aa, 575 | 0x0196, 0x018a, 0x0180, 0x02df, 0x0167, 0x02c6, 0x0160, 0x000b, 576 | 0x008b, 0x0081, 0x0043, 0x007d, 0x00f7, 0x00e9, 0x00e5, 0x00db, 577 | 0x0189, 0x02e7, 0x02e1, 0x02d0, 0x0375, 0x0372, 0x01b7, 0x0004, 578 | 0x00f3, 0x0078, 0x0076, 0x0073, 0x00e3, 0x00df, 0x018c, 0x02ea, 579 | 0x02e6, 0x02e0, 0x02d1, 0x02c8, 0x02c2, 0x00df, 0x01b4, 0x0006, 580 | 0x00ca, 0x00e0, 0x00de, 0x00da, 0x00d8, 0x0185, 0x0182, 0x017d, 581 | 0x016c, 0x0378, 0x01bb, 0x02c3, 0x01b8, 0x01b5, 0x06c0, 0x0004, 582 | 0x02eb, 0x00d3, 0x00d2, 0x00d0, 0x0172, 0x017b, 0x02de, 0x02d3, 583 | 0x02ca, 0x06c7, 0x0373, 0x036d, 0x036c, 0x0d83, 0x0361, 0x0002, 584 | 0x0179, 0x0171, 0x0066, 0x00bb, 0x02d6, 0x02d2, 0x0166, 0x02c7, 585 | 0x02c5, 0x0362, 0x06c6, 0x0367, 0x0d82, 0x0366, 0x01b2, 0x0000, 586 | 0x000c, 0x000a, 0x0007, 0x000b, 0x000a, 0x0011, 0x000b, 0x0009, 587 | 0x000d, 0x000c, 0x000a, 0x0007, 0x0005, 0x0003, 0x0001, 0x0003, 588 | }; 589 | 590 | static const uint8_t mp3_huffbits_16[256] = { 591 | 1, 4, 6, 8, 9, 9, 10, 10, 592 | 11, 11, 11, 12, 12, 12, 13, 9, 593 | 3, 4, 6, 7, 8, 9, 9, 9, 594 | 10, 10, 10, 11, 12, 11, 12, 8, 595 | 6, 6, 7, 8, 9, 9, 10, 10, 596 | 11, 10, 11, 11, 11, 12, 12, 9, 597 | 8, 7, 8, 9, 9, 10, 10, 10, 598 | 11, 11, 12, 12, 12, 13, 13, 10, 599 | 9, 8, 9, 9, 10, 10, 11, 11, 600 | 11, 12, 12, 12, 13, 13, 13, 9, 601 | 9, 8, 9, 9, 10, 11, 11, 12, 602 | 11, 12, 12, 13, 13, 13, 14, 10, 603 | 10, 9, 9, 10, 11, 11, 11, 11, 604 | 12, 12, 12, 12, 13, 13, 14, 10, 605 | 10, 9, 10, 10, 11, 11, 11, 12, 606 | 12, 13, 13, 13, 13, 15, 15, 10, 607 | 10, 10, 10, 11, 11, 11, 12, 12, 608 | 13, 13, 13, 13, 14, 14, 14, 10, 609 | 11, 10, 10, 11, 11, 12, 12, 13, 610 | 13, 13, 13, 14, 13, 14, 13, 11, 611 | 11, 11, 10, 11, 12, 12, 12, 12, 612 | 13, 14, 14, 14, 15, 15, 14, 10, 613 | 12, 11, 11, 11, 12, 12, 13, 14, 614 | 14, 14, 14, 14, 14, 13, 14, 11, 615 | 12, 12, 12, 12, 12, 13, 13, 13, 616 | 13, 15, 14, 14, 14, 14, 16, 11, 617 | 14, 12, 12, 12, 13, 13, 14, 14, 618 | 14, 16, 15, 15, 15, 17, 15, 11, 619 | 13, 13, 11, 12, 14, 14, 13, 14, 620 | 14, 15, 16, 15, 17, 15, 14, 11, 621 | 9, 8, 8, 9, 9, 10, 10, 10, 622 | 11, 11, 11, 11, 11, 11, 11, 8, 623 | }; 624 | 625 | static const uint16_t mp3_huffcodes_24[256] = { 626 | 0x000f, 0x000d, 0x002e, 0x0050, 0x0092, 0x0106, 0x00f8, 0x01b2, 627 | 0x01aa, 0x029d, 0x028d, 0x0289, 0x026d, 0x0205, 0x0408, 0x0058, 628 | 0x000e, 0x000c, 0x0015, 0x0026, 0x0047, 0x0082, 0x007a, 0x00d8, 629 | 0x00d1, 0x00c6, 0x0147, 0x0159, 0x013f, 0x0129, 0x0117, 0x002a, 630 | 0x002f, 0x0016, 0x0029, 0x004a, 0x0044, 0x0080, 0x0078, 0x00dd, 631 | 0x00cf, 0x00c2, 0x00b6, 0x0154, 0x013b, 0x0127, 0x021d, 0x0012, 632 | 0x0051, 0x0027, 0x004b, 0x0046, 0x0086, 0x007d, 0x0074, 0x00dc, 633 | 0x00cc, 0x00be, 0x00b2, 0x0145, 0x0137, 0x0125, 0x010f, 0x0010, 634 | 0x0093, 0x0048, 0x0045, 0x0087, 0x007f, 0x0076, 0x0070, 0x00d2, 635 | 0x00c8, 0x00bc, 0x0160, 0x0143, 0x0132, 0x011d, 0x021c, 0x000e, 636 | 0x0107, 0x0042, 0x0081, 0x007e, 0x0077, 0x0072, 0x00d6, 0x00ca, 637 | 0x00c0, 0x00b4, 0x0155, 0x013d, 0x012d, 0x0119, 0x0106, 0x000c, 638 | 0x00f9, 0x007b, 0x0079, 0x0075, 0x0071, 0x00d7, 0x00ce, 0x00c3, 639 | 0x00b9, 0x015b, 0x014a, 0x0134, 0x0123, 0x0110, 0x0208, 0x000a, 640 | 0x01b3, 0x0073, 0x006f, 0x006d, 0x00d3, 0x00cb, 0x00c4, 0x00bb, 641 | 0x0161, 0x014c, 0x0139, 0x012a, 0x011b, 0x0213, 0x017d, 0x0011, 642 | 0x01ab, 0x00d4, 0x00d0, 0x00cd, 0x00c9, 0x00c1, 0x00ba, 0x00b1, 643 | 0x00a9, 0x0140, 0x012f, 0x011e, 0x010c, 0x0202, 0x0179, 0x0010, 644 | 0x014f, 0x00c7, 0x00c5, 0x00bf, 0x00bd, 0x00b5, 0x00ae, 0x014d, 645 | 0x0141, 0x0131, 0x0121, 0x0113, 0x0209, 0x017b, 0x0173, 0x000b, 646 | 0x029c, 0x00b8, 0x00b7, 0x00b3, 0x00af, 0x0158, 0x014b, 0x013a, 647 | 0x0130, 0x0122, 0x0115, 0x0212, 0x017f, 0x0175, 0x016e, 0x000a, 648 | 0x028c, 0x015a, 0x00ab, 0x00a8, 0x00a4, 0x013e, 0x0135, 0x012b, 649 | 0x011f, 0x0114, 0x0107, 0x0201, 0x0177, 0x0170, 0x016a, 0x0006, 650 | 0x0288, 0x0142, 0x013c, 0x0138, 0x0133, 0x012e, 0x0124, 0x011c, 651 | 0x010d, 0x0105, 0x0200, 0x0178, 0x0172, 0x016c, 0x0167, 0x0004, 652 | 0x026c, 0x012c, 0x0128, 0x0126, 0x0120, 0x011a, 0x0111, 0x010a, 653 | 0x0203, 0x017c, 0x0176, 0x0171, 0x016d, 0x0169, 0x0165, 0x0002, 654 | 0x0409, 0x0118, 0x0116, 0x0112, 0x010b, 0x0108, 0x0103, 0x017e, 655 | 0x017a, 0x0174, 0x016f, 0x016b, 0x0168, 0x0166, 0x0164, 0x0000, 656 | 0x002b, 0x0014, 0x0013, 0x0011, 0x000f, 0x000d, 0x000b, 0x0009, 657 | 0x0007, 0x0006, 0x0004, 0x0007, 0x0005, 0x0003, 0x0001, 0x0003, 658 | }; 659 | 660 | static const uint8_t mp3_huffbits_24[256] = { 661 | 4, 4, 6, 7, 8, 9, 9, 10, 662 | 10, 11, 11, 11, 11, 11, 12, 9, 663 | 4, 4, 5, 6, 7, 8, 8, 9, 664 | 9, 9, 10, 10, 10, 10, 10, 8, 665 | 6, 5, 6, 7, 7, 8, 8, 9, 666 | 9, 9, 9, 10, 10, 10, 11, 7, 667 | 7, 6, 7, 7, 8, 8, 8, 9, 668 | 9, 9, 9, 10, 10, 10, 10, 7, 669 | 8, 7, 7, 8, 8, 8, 8, 9, 670 | 9, 9, 10, 10, 10, 10, 11, 7, 671 | 9, 7, 8, 8, 8, 8, 9, 9, 672 | 9, 9, 10, 10, 10, 10, 10, 7, 673 | 9, 8, 8, 8, 8, 9, 9, 9, 674 | 9, 10, 10, 10, 10, 10, 11, 7, 675 | 10, 8, 8, 8, 9, 9, 9, 9, 676 | 10, 10, 10, 10, 10, 11, 11, 8, 677 | 10, 9, 9, 9, 9, 9, 9, 9, 678 | 9, 10, 10, 10, 10, 11, 11, 8, 679 | 10, 9, 9, 9, 9, 9, 9, 10, 680 | 10, 10, 10, 10, 11, 11, 11, 8, 681 | 11, 9, 9, 9, 9, 10, 10, 10, 682 | 10, 10, 10, 11, 11, 11, 11, 8, 683 | 11, 10, 9, 9, 9, 10, 10, 10, 684 | 10, 10, 10, 11, 11, 11, 11, 8, 685 | 11, 10, 10, 10, 10, 10, 10, 10, 686 | 10, 10, 11, 11, 11, 11, 11, 8, 687 | 11, 10, 10, 10, 10, 10, 10, 10, 688 | 11, 11, 11, 11, 11, 11, 11, 8, 689 | 12, 10, 10, 10, 10, 10, 10, 11, 690 | 11, 11, 11, 11, 11, 11, 11, 8, 691 | 8, 7, 7, 7, 7, 7, 7, 7, 692 | 7, 7, 7, 8, 8, 8, 8, 4, 693 | }; 694 | 695 | static const huff_table_t mp3_huff_tables[16] = { 696 | { 1, NULL, NULL }, 697 | { 2, mp3_huffbits_1, mp3_huffcodes_1 }, 698 | { 3, mp3_huffbits_2, mp3_huffcodes_2 }, 699 | { 3, mp3_huffbits_3, mp3_huffcodes_3 }, 700 | { 4, mp3_huffbits_5, mp3_huffcodes_5 }, 701 | { 4, mp3_huffbits_6, mp3_huffcodes_6 }, 702 | { 6, mp3_huffbits_7, mp3_huffcodes_7 }, 703 | { 6, mp3_huffbits_8, mp3_huffcodes_8 }, 704 | { 6, mp3_huffbits_9, mp3_huffcodes_9 }, 705 | { 8, mp3_huffbits_10, mp3_huffcodes_10 }, 706 | { 8, mp3_huffbits_11, mp3_huffcodes_11 }, 707 | { 8, mp3_huffbits_12, mp3_huffcodes_12 }, 708 | { 16, mp3_huffbits_13, mp3_huffcodes_13 }, 709 | { 16, mp3_huffbits_15, mp3_huffcodes_15 }, 710 | { 16, mp3_huffbits_16, mp3_huffcodes_16 }, 711 | { 16, mp3_huffbits_24, mp3_huffcodes_24 }, 712 | }; 713 | 714 | static const uint8_t mp3_huff_data[32][2] = { 715 | { 0, 0 }, 716 | { 1, 0 }, 717 | { 2, 0 }, 718 | { 3, 0 }, 719 | { 0, 0 }, 720 | { 4, 0 }, 721 | { 5, 0 }, 722 | { 6, 0 }, 723 | { 7, 0 }, 724 | { 8, 0 }, 725 | { 9, 0 }, 726 | { 10, 0 }, 727 | { 11, 0 }, 728 | { 12, 0 }, 729 | { 0, 0 }, 730 | { 13, 0 }, 731 | { 14, 1 }, 732 | { 14, 2 }, 733 | { 14, 3 }, 734 | { 14, 4 }, 735 | { 14, 6 }, 736 | { 14, 8 }, 737 | { 14, 10 }, 738 | { 14, 13 }, 739 | { 15, 4 }, 740 | { 15, 5 }, 741 | { 15, 6 }, 742 | { 15, 7 }, 743 | { 15, 8 }, 744 | { 15, 9 }, 745 | { 15, 11 }, 746 | { 15, 13 }, 747 | }; 748 | 749 | static const uint8_t mp3_quad_codes[2][16] = { 750 | { 1, 5, 4, 5, 6, 5, 4, 4, 7, 3, 6, 0, 7, 2, 3, 1, }, 751 | { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, }, 752 | }; 753 | 754 | static const uint8_t mp3_quad_bits[2][16] = { 755 | { 1, 4, 4, 5, 4, 6, 5, 6, 4, 5, 5, 6, 5, 6, 6, 6, }, 756 | { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, }, 757 | }; 758 | 759 | static const uint8_t band_size_long[9][22] = { 760 | { 761 | 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, 762 | 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158, 763 | }, /* 44100 */ 764 | { 765 | 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, 766 | 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192, 767 | }, /* 48000 */ 768 | { 769 | 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, 770 | 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26, 771 | }, /* 32000 */ 772 | { 773 | 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 774 | 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, 775 | }, /* 22050 */ 776 | { 777 | 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 778 | 18, 22, 26, 32, 38, 46, 52, 64, 70, 76, 36, 779 | }, /* 24000 */ 780 | { 781 | 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 782 | 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, 783 | }, /* 16000 */ 784 | { 785 | 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 786 | 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, 787 | }, /* 11025 */ 788 | { 789 | 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, 790 | 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, 791 | }, /* 12000 */ 792 | { 793 | 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, 794 | 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2, 795 | }, /* 8000 */ 796 | }; 797 | 798 | static const uint8_t band_size_short[9][13] = { 799 | { 4, 4, 4, 4, 6, 8, 10, 12, 14, 18, 22, 30, 56, }, /* 44100 */ 800 | { 4, 4, 4, 4, 6, 6, 10, 12, 14, 16, 20, 26, 66, }, /* 48000 */ 801 | { 4, 4, 4, 4, 6, 8, 12, 16, 20, 26, 34, 42, 12, }, /* 32000 */ 802 | { 4, 4, 4, 6, 6, 8, 10, 14, 18, 26, 32, 42, 18, }, /* 22050 */ 803 | { 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 32, 44, 12, }, /* 24000 */ 804 | { 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 16000 */ 805 | { 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 11025 */ 806 | { 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 12000 */ 807 | { 8, 8, 8, 12, 16, 20, 24, 28, 36, 2, 2, 2, 26, }, /* 8000 */ 808 | }; 809 | 810 | static const uint8_t mp3_pretab[2][22] = { 811 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 812 | { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 }, 813 | }; 814 | 815 | static const float ci_table[8] = { 816 | -0.6f, -0.535f, -0.33f, -0.185f, -0.095f, -0.041f, -0.0142f, -0.0037f, 817 | }; 818 | 819 | #define C1 FIXHR(0.98480775301220805936/2) 820 | #define C2 FIXHR(0.93969262078590838405/2) 821 | #define C3 FIXHR(0.86602540378443864676/2) 822 | #define C4 FIXHR(0.76604444311897803520/2) 823 | #define C5 FIXHR(0.64278760968653932632/2) 824 | #define C6 FIXHR(0.5/2) 825 | #define C7 FIXHR(0.34202014332566873304/2) 826 | #define C8 FIXHR(0.17364817766693034885/2) 827 | 828 | static const int icos36[9] = { 829 | FIXR(0.50190991877167369479), 830 | FIXR(0.51763809020504152469), //0 831 | FIXR(0.55168895948124587824), 832 | FIXR(0.61038729438072803416), 833 | FIXR(0.70710678118654752439), //1 834 | FIXR(0.87172339781054900991), 835 | FIXR(1.18310079157624925896), 836 | FIXR(1.93185165257813657349), //2 837 | FIXR(5.73685662283492756461), 838 | }; 839 | 840 | static const int icos36h[9] = { 841 | FIXHR(0.50190991877167369479/2), 842 | FIXHR(0.51763809020504152469/2), //0 843 | FIXHR(0.55168895948124587824/2), 844 | FIXHR(0.61038729438072803416/2), 845 | FIXHR(0.70710678118654752439/2), //1 846 | FIXHR(0.87172339781054900991/2), 847 | FIXHR(1.18310079157624925896/4), 848 | FIXHR(1.93185165257813657349/4), //2 849 | // FIXHR(5.73685662283492756461), 850 | }; 851 | 852 | //////////////////////////////////////////////////////////////////////////////// 853 | 854 | static INLINE int unaligned32_be(const uint8_t *p) 855 | { 856 | return (((p[0]<<8) | p[1])<<16) | (p[2]<<8) | (p[3]); 857 | } 858 | 859 | #define MIN_CACHE_BITS 25 860 | 861 | #define NEG_SSR32(a,s) ((( int32_t)(a))>>(32-(s))) 862 | #define NEG_USR32(a,s) (((uint32_t)(a))>>(32-(s))) 863 | 864 | #define OPEN_READER(name, gb) \ 865 | int name##_index= (gb)->index;\ 866 | int name##_cache= 0;\ 867 | 868 | #define CLOSE_READER(name, gb)\ 869 | (gb)->index= name##_index;\ 870 | 871 | #define UPDATE_CACHE(name, gb)\ 872 | name##_cache= unaligned32_be(&((gb)->buffer[name##_index>>3])) << (name##_index&0x07); \ 873 | 874 | #define SKIP_CACHE(name, gb, num)\ 875 | name##_cache <<= (num); 876 | 877 | #define SKIP_COUNTER(name, gb, num)\ 878 | name##_index += (num);\ 879 | 880 | #define SKIP_BITS(name, gb, num)\ 881 | {\ 882 | SKIP_CACHE(name, gb, num)\ 883 | SKIP_COUNTER(name, gb, num)\ 884 | }\ 885 | 886 | #define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) 887 | #define LAST_SKIP_CACHE(name, gb, num) ; 888 | 889 | #define SHOW_UBITS(name, gb, num)\ 890 | NEG_USR32(name##_cache, num) 891 | 892 | #define SHOW_SBITS(name, gb, num)\ 893 | NEG_SSR32(name##_cache, num) 894 | 895 | #define GET_CACHE(name, gb)\ 896 | ((uint32_t)name##_cache) 897 | 898 | static INLINE int get_bits_count(bitstream_t *s) 899 | { 900 | return s->index; 901 | } 902 | 903 | static INLINE void skip_bits_long(bitstream_t *s, int n) 904 | { 905 | s->index += n; 906 | } 907 | #define skip_bits skip_bits_long 908 | 909 | static void init_get_bits(bitstream_t *s, const uint8_t *buffer, int bit_size) 910 | { 911 | int buffer_size= (bit_size+7)>>3; 912 | if (buffer_size < 0 || bit_size < 0) { 913 | buffer_size = bit_size = 0; 914 | buffer = NULL; 915 | } 916 | s->buffer= buffer; 917 | s->size_in_bits= bit_size; 918 | s->buffer_end= buffer + buffer_size; 919 | s->index=0; 920 | } 921 | 922 | static INLINE unsigned int _get_bits(bitstream_t *s, int n) 923 | { 924 | register int tmp; 925 | OPEN_READER(re, s) 926 | UPDATE_CACHE(re, s) 927 | tmp= SHOW_UBITS(re, s, n); 928 | LAST_SKIP_BITS(re, s, n) 929 | CLOSE_READER(re, s) 930 | return tmp; 931 | } 932 | 933 | static INLINE int get_bitsz(bitstream_t *s, int n) 934 | { 935 | if (n == 0) { 936 | return 0; 937 | } else { 938 | return _get_bits(s, n); 939 | } 940 | } 941 | 942 | static INLINE unsigned int get_bits1(bitstream_t *s) 943 | { 944 | int index= s->index; 945 | uint8_t result= s->buffer[ index>>3 ]; 946 | result<<= (index&0x07); 947 | result>>= 8 - 1; 948 | index++; 949 | s->index= index; 950 | return result; 951 | } 952 | 953 | static INLINE void align_get_bits(bitstream_t *s) 954 | { 955 | int n= (-get_bits_count(s)) & 7; 956 | if (n) { 957 | skip_bits(s, n); 958 | } 959 | } 960 | 961 | #define GET_DATA(v, table, i, wrap, size) \ 962 | {\ 963 | const uint8_t *ptr = (const uint8_t *)table + i * wrap;\ 964 | switch(size) {\ 965 | case 1:\ 966 | v = *(const uint8_t *)ptr;\ 967 | break;\ 968 | case 2:\ 969 | v = *(const uint16_t *)ptr;\ 970 | break;\ 971 | default:\ 972 | v = *(const uint32_t *)ptr;\ 973 | break;\ 974 | }\ 975 | } 976 | 977 | static INLINE int alloc_table(vlc_t *vlc, int size) 978 | { 979 | int index; 980 | index = vlc->table_size; 981 | vlc->table_size += size; 982 | if (vlc->table_size > vlc->table_allocated) { 983 | vlc->table_allocated += (1 << vlc->bits); 984 | vlc->table = realloc(vlc->table, sizeof(VLC_TYPE) * 2 * vlc->table_allocated); 985 | if (!vlc->table) { 986 | return -1; 987 | } 988 | } 989 | return index; 990 | } 991 | 992 | static int build_table( 993 | vlc_t *vlc, int table_nb_bits, 994 | int nb_codes, 995 | const void *bits, int bits_wrap, int bits_size, 996 | const void *codes, int codes_wrap, int codes_size, 997 | uint32_t code_prefix, int n_prefix 998 | ) 999 | { 1000 | int i, j, k, n, table_size, table_index, nb, n1, index, code_prefix2; 1001 | uint32_t code; 1002 | VLC_TYPE (*table)[2]; 1003 | 1004 | table_size = 1 << table_nb_bits; 1005 | table_index = alloc_table(vlc, table_size); 1006 | if (table_index < 0) { 1007 | return -1; 1008 | } 1009 | table = &vlc->table[table_index]; 1010 | 1011 | for (i=0; i> n; 1024 | if (n > 0 && code_prefix2 == code_prefix) { 1025 | if (n <= table_nb_bits) { 1026 | j = (code << (table_nb_bits - n)) & (table_size - 1); 1027 | nb = 1 << (table_nb_bits - n); 1028 | for (k=0; k> n) & ((1 << table_nb_bits) - 1); 1039 | n1 = -table[j][1]; //bits 1040 | if (n > n1) { 1041 | n1 = n; 1042 | } 1043 | table[j][1] = -n1; //bits 1044 | } 1045 | } 1046 | } 1047 | for (i=0; i table_nb_bits) { 1052 | n = table_nb_bits; 1053 | table[i][1] = -n; //bits 1054 | } 1055 | index = build_table(vlc, n, nb_codes, 1056 | bits, bits_wrap, bits_size, 1057 | codes, codes_wrap, codes_size, 1058 | (code_prefix << table_nb_bits) | i, 1059 | n_prefix + table_nb_bits); 1060 | if (index < 0) { 1061 | return -1; 1062 | } 1063 | table = &vlc->table[table_index]; 1064 | table[i][0] = index; //code 1065 | } 1066 | } 1067 | return table_index; 1068 | } 1069 | 1070 | static INLINE int init_vlc( 1071 | vlc_t *vlc, int nb_bits, int nb_codes, 1072 | const void *bits, int bits_wrap, int bits_size, 1073 | const void *codes, int codes_wrap, int codes_size 1074 | ) 1075 | { 1076 | vlc->bits = nb_bits; 1077 | if (build_table(vlc, nb_bits, nb_codes, 1078 | bits, bits_wrap, bits_size, 1079 | codes, codes_wrap, codes_size, 1080 | 0, 0) < 0) { 1081 | free(vlc->table); 1082 | return -1; 1083 | } 1084 | return 0; 1085 | } 1086 | 1087 | #define GET_VLC(code, name, gb, table, bits, max_depth)\ 1088 | {\ 1089 | int n, index, nb_bits;\ 1090 | \ 1091 | index= SHOW_UBITS(name, gb, bits);\ 1092 | code = table[index][0];\ 1093 | n = table[index][1];\ 1094 | \ 1095 | if(max_depth > 1 && n < 0){\ 1096 | LAST_SKIP_BITS(name, gb, bits)\ 1097 | UPDATE_CACHE(name, gb)\ 1098 | \ 1099 | nb_bits = -n;\ 1100 | \ 1101 | index= SHOW_UBITS(name, gb, nb_bits) + code;\ 1102 | code = table[index][0];\ 1103 | n = table[index][1];\ 1104 | if(max_depth > 2 && n < 0){\ 1105 | LAST_SKIP_BITS(name, gb, nb_bits)\ 1106 | UPDATE_CACHE(name, gb)\ 1107 | \ 1108 | nb_bits = -n;\ 1109 | \ 1110 | index= SHOW_UBITS(name, gb, nb_bits) + code;\ 1111 | code = table[index][0];\ 1112 | n = table[index][1];\ 1113 | }\ 1114 | }\ 1115 | SKIP_BITS(name, gb, n)\ 1116 | } 1117 | 1118 | static INLINE int get_vlc2(bitstream_t *s, VLC_TYPE (*table)[2], int bits, int max_depth) 1119 | { 1120 | int code; 1121 | 1122 | OPEN_READER(re, s) 1123 | UPDATE_CACHE(re, s) 1124 | 1125 | GET_VLC(code, re, s, table, bits, max_depth) 1126 | 1127 | CLOSE_READER(re, s) 1128 | return code; 1129 | } 1130 | 1131 | static void switch_buffer(mp3_context_t *s, int *pos, int *end_pos, int *end_pos2) 1132 | { 1133 | if (s->in_gb.buffer && *pos >= s->gb.size_in_bits) { 1134 | s->gb= s->in_gb; 1135 | s->in_gb.buffer=NULL; 1136 | skip_bits_long(&s->gb, *pos - *end_pos); 1137 | *end_pos2= 1138 | *end_pos= *end_pos2 + get_bits_count(&s->gb) - *pos; 1139 | *pos= get_bits_count(&s->gb); 1140 | } 1141 | } 1142 | 1143 | //////////////////////////////////////////////////////////////////////////////// 1144 | 1145 | static INLINE int mp3_check_header(uint32_t header) 1146 | { 1147 | /* header */ 1148 | if ((header & 0xffe00000) != 0xffe00000) { 1149 | return -1; 1150 | } 1151 | /* layer check */ 1152 | if ((header & (3<<17)) != (1 << 17)) { 1153 | return -1; 1154 | } 1155 | /* bit rate */ 1156 | if ((header & (0xf<<12)) == 0xf<<12) { 1157 | return -1; 1158 | } 1159 | /* frequency */ 1160 | if ((header & (3<<10)) == 3<<10) { 1161 | return -1; 1162 | } 1163 | return 0; 1164 | } 1165 | 1166 | 1167 | static void lsf_sf_expand( 1168 | int *slen, int sf, int n1, int n2, int n3 1169 | ) 1170 | { 1171 | if (n3) { 1172 | slen[3] = sf % n3; 1173 | sf /= n3; 1174 | } else { 1175 | slen[3] = 0; 1176 | } 1177 | if (n2) { 1178 | slen[2] = sf % n2; 1179 | sf /= n2; 1180 | } else { 1181 | slen[2] = 0; 1182 | } 1183 | slen[1] = sf % n1; 1184 | sf /= n1; 1185 | slen[0] = sf; 1186 | } 1187 | 1188 | static INLINE int l3_unscale(int value, int exponent) 1189 | { 1190 | unsigned int m; 1191 | int e; 1192 | 1193 | e = table_4_3_exp [4*value + (exponent&3)]; 1194 | m = table_4_3_value[4*value + (exponent&3)]; 1195 | e -= (exponent >> 2); 1196 | if (e > 31) { 1197 | return 0; 1198 | } 1199 | m = (m + (1 << (e-1))) >> e; 1200 | 1201 | return m; 1202 | } 1203 | 1204 | static INLINE int round_sample(int *sum) 1205 | { 1206 | int sum1; 1207 | sum1 = (*sum) >> OUT_SHIFT; 1208 | *sum &= (1< OUT_MAX) { 1212 | sum1 = OUT_MAX; 1213 | } 1214 | return sum1; 1215 | } 1216 | 1217 | static void exponents_from_scale_factors( 1218 | mp3_context_t *s, granule_t *g, int16_t *exponents 1219 | ) 1220 | { 1221 | const uint8_t *bstab, *pretab; 1222 | int len, i, j, k, l, v0, shift, gain, gains[3]; 1223 | int16_t *exp_ptr; 1224 | 1225 | exp_ptr = exponents; 1226 | gain = g->global_gain - 210; 1227 | shift = g->scalefac_scale + 1; 1228 | 1229 | bstab = band_size_long[s->sample_rate_index]; 1230 | pretab = mp3_pretab[g->preflag]; 1231 | for (i=0; ilong_end; i++) { 1232 | v0 = gain - ((g->scale_factors[i] + pretab[i]) << shift) + 400; 1233 | len = bstab[i]; 1234 | for (j=len; j>0; j--) { 1235 | *exp_ptr++ = v0; 1236 | } 1237 | } 1238 | 1239 | if (g->short_start < 13) { 1240 | bstab = band_size_short[s->sample_rate_index]; 1241 | gains[0] = gain - (g->subblock_gain[0] << 3); 1242 | gains[1] = gain - (g->subblock_gain[1] << 3); 1243 | gains[2] = gain - (g->subblock_gain[2] << 3); 1244 | k = g->long_end; 1245 | for (i=g->short_start; i<13; i++) { 1246 | len = bstab[i]; 1247 | for (l=0; l<3; l++) { 1248 | v0 = gains[l] - (g->scale_factors[k++] << shift) + 400; 1249 | for (j=len; j>0; j--) { 1250 | *exp_ptr++ = v0; 1251 | } 1252 | } 1253 | } 1254 | } 1255 | } 1256 | 1257 | static void reorder_block(mp3_context_t *s, granule_t *g) 1258 | { 1259 | int i, j, len; 1260 | int32_t *ptr, *dst, *ptr1; 1261 | int32_t tmp[576]; 1262 | 1263 | if (g->block_type != 2) { 1264 | return; 1265 | } 1266 | 1267 | if (g->switch_point) { 1268 | if (s->sample_rate_index != 8) { 1269 | ptr = g->sb_hybrid + 36; 1270 | } else { 1271 | ptr = g->sb_hybrid + 48; 1272 | } 1273 | } else { 1274 | ptr = g->sb_hybrid; 1275 | } 1276 | 1277 | for (i=g->short_start; i<13; i++) { 1278 | len = band_size_short[s->sample_rate_index][i]; 1279 | ptr1 = ptr; 1280 | dst = tmp; 1281 | for (j=len; j>0; j--) { 1282 | *dst++ = ptr[0*len]; 1283 | *dst++ = ptr[1*len]; 1284 | *dst++ = ptr[2*len]; 1285 | ptr++; 1286 | } 1287 | ptr+=2*len; 1288 | memcpy(ptr1, tmp, len * 3 * sizeof(*ptr1)); 1289 | } 1290 | } 1291 | 1292 | static void compute_antialias(mp3_context_t *s, granule_t *g) 1293 | { 1294 | int32_t *ptr, *csa; 1295 | int n, i; 1296 | 1297 | /* we antialias only "long" bands */ 1298 | if (g->block_type == 2) { 1299 | if (!g->switch_point) { 1300 | return; 1301 | } 1302 | /* XXX: check this for 8000Hz case */ 1303 | n = 1; 1304 | } else { 1305 | n = SBLIMIT - 1; 1306 | } 1307 | 1308 | ptr = g->sb_hybrid + 18; 1309 | for (i = n; i > 0; i--) { 1310 | int tmp0, tmp1, tmp2; 1311 | csa = &csa_table[0][0]; 1312 | #define INT_AA(j) \ 1313 | tmp0 = ptr[-1-j];\ 1314 | tmp1 = ptr[ j];\ 1315 | tmp2= MULH(tmp0 + tmp1, csa[0+4*j]);\ 1316 | ptr[-1-j] = 4*(tmp2 - MULH(tmp1, csa[2+4*j]));\ 1317 | ptr[ j] = 4*(tmp2 + MULH(tmp0, csa[3+4*j])); 1318 | 1319 | INT_AA(0) 1320 | INT_AA(1) 1321 | INT_AA(2) 1322 | INT_AA(3) 1323 | INT_AA(4) 1324 | INT_AA(5) 1325 | INT_AA(6) 1326 | INT_AA(7) 1327 | 1328 | ptr += 18; 1329 | } 1330 | } 1331 | 1332 | static void compute_stereo( 1333 | mp3_context_t *s, granule_t *g0, granule_t *g1 1334 | ) 1335 | { 1336 | int i, j, k, l; 1337 | int32_t v1, v2; 1338 | int sf_max, tmp0, tmp1, sf, len, non_zero_found; 1339 | int32_t (*is_tab)[16]; 1340 | int32_t *tab0, *tab1; 1341 | int non_zero_found_short[3]; 1342 | 1343 | if (s->mode_ext & MODE_EXT_I_STEREO) { 1344 | if (!s->lsf) { 1345 | is_tab = is_table; 1346 | sf_max = 7; 1347 | } else { 1348 | is_tab = is_table_lsf[g1->scalefac_compress & 1]; 1349 | sf_max = 16; 1350 | } 1351 | 1352 | tab0 = g0->sb_hybrid + 576; 1353 | tab1 = g1->sb_hybrid + 576; 1354 | 1355 | non_zero_found_short[0] = 0; 1356 | non_zero_found_short[1] = 0; 1357 | non_zero_found_short[2] = 0; 1358 | k = (13 - g1->short_start) * 3 + g1->long_end - 3; 1359 | for (i = 12; i >= g1->short_start; i--) { 1360 | /* for last band, use previous scale factor */ 1361 | if (i != 11) { 1362 | k -= 3; 1363 | } 1364 | len = band_size_short[s->sample_rate_index][i]; 1365 | for (l=2; l>=0; l--) { 1366 | tab0 -= len; 1367 | tab1 -= len; 1368 | if (!non_zero_found_short[l]) { 1369 | /* test if non zero band. if so, stop doing i-stereo */ 1370 | for (j=0; jscale_factors[k + l]; 1377 | if (sf >= sf_max) { 1378 | goto found1; 1379 | } 1380 | 1381 | v1 = is_tab[0][sf]; 1382 | v2 = is_tab[1][sf]; 1383 | for (j=0; jmode_ext & MODE_EXT_MS_STEREO) { 1391 | /* lower part of the spectrum : do ms stereo 1392 | if enabled */ 1393 | for (j=0; jlong_end - 1; i >= 0; i--) { 1409 | len = band_size_long[s->sample_rate_index][i]; 1410 | tab0 -= len; 1411 | tab1 -= len; 1412 | /* test if non zero band. if so, stop doing i-stereo */ 1413 | if (!non_zero_found) { 1414 | for (j=0; jscale_factors[k]; 1423 | if (sf >= sf_max) { 1424 | goto found2; 1425 | } 1426 | v1 = is_tab[0][sf]; 1427 | v2 = is_tab[1][sf]; 1428 | for (j=0; jmode_ext & MODE_EXT_MS_STEREO) { 1436 | /* lower part of the spectrum : do ms stereo 1437 | if enabled */ 1438 | for (j=0; jmode_ext & MODE_EXT_MS_STEREO) { 1448 | /* ms stereo ONLY */ 1449 | /* NOTE: the 1/sqrt(2) normalization factor is included in the 1450 | global gain */ 1451 | tab0 = g0->sb_hybrid; 1452 | tab1 = g1->sb_hybrid; 1453 | for (i=0; i<576; i++) { 1454 | tmp0 = tab0[i]; 1455 | tmp1 = tab1[i]; 1456 | tab0[i] = tmp0 + tmp1; 1457 | tab1[i] = tmp0 - tmp1; 1458 | } 1459 | } 1460 | } 1461 | 1462 | static int huffman_decode( 1463 | mp3_context_t *s, granule_t *g, int16_t *exponents, int end_pos2 1464 | ) 1465 | { 1466 | int s_index; 1467 | int i; 1468 | int last_pos, bits_left; 1469 | vlc_t *vlc; 1470 | int end_pos= s->gb.size_in_bits; 1471 | if (end_pos2 < end_pos) { 1472 | end_pos = end_pos2; 1473 | } 1474 | 1475 | /* low frequencies (called big values) */ 1476 | s_index = 0; 1477 | for (i=0; i<3; i++) { 1478 | int j, k, l, linbits; 1479 | j = g->region_size[i]; 1480 | if (j == 0) { 1481 | continue; 1482 | } 1483 | /* select vlc table */ 1484 | k = g->table_select[i]; 1485 | l = mp3_huff_data[k][0]; 1486 | linbits = mp3_huff_data[k][1]; 1487 | vlc = &huff_vlc[l]; 1488 | 1489 | if (!l) { 1490 | memset(&g->sb_hybrid[s_index], 0, sizeof(*g->sb_hybrid)*2*j); 1491 | s_index += 2*j; 1492 | continue; 1493 | } 1494 | 1495 | /* read huffcode and compute each couple */ 1496 | for (; j>0; j--) { 1497 | int exponent, x, y, v; 1498 | int pos= get_bits_count(&s->gb); 1499 | 1500 | if (pos >= end_pos) { 1501 | switch_buffer(s, &pos, &end_pos, &end_pos2); 1502 | if (pos >= end_pos) { 1503 | break; 1504 | } 1505 | } 1506 | y = get_vlc2(&s->gb, vlc->table, 7, 3); 1507 | 1508 | if (!y) { 1509 | g->sb_hybrid[s_index ] = 1510 | g->sb_hybrid[s_index+1] = 0; 1511 | s_index += 2; 1512 | continue; 1513 | } 1514 | 1515 | exponent= exponents[s_index]; 1516 | 1517 | if (y&16) { 1518 | x = y >> 5; 1519 | y = y & 0x0f; 1520 | if (x < 15) { 1521 | v = expval_table[ exponent ][ x ]; 1522 | } else { 1523 | x += get_bitsz(&s->gb, linbits); 1524 | v = l3_unscale(x, exponent); 1525 | } 1526 | if (get_bits1(&s->gb)) { 1527 | v = -v; 1528 | } 1529 | g->sb_hybrid[s_index] = v; 1530 | if (y < 15) { 1531 | v = expval_table[ exponent ][ y ]; 1532 | } else { 1533 | y += get_bitsz(&s->gb, linbits); 1534 | v = l3_unscale(y, exponent); 1535 | } 1536 | if (get_bits1(&s->gb)) { 1537 | v = -v; 1538 | } 1539 | g->sb_hybrid[s_index+1] = v; 1540 | } else { 1541 | x = y >> 5; 1542 | y = y & 0x0f; 1543 | x += y; 1544 | if (x < 15) { 1545 | v = expval_table[ exponent ][ x ]; 1546 | } else { 1547 | x += get_bitsz(&s->gb, linbits); 1548 | v = l3_unscale(x, exponent); 1549 | } 1550 | if (get_bits1(&s->gb)) { 1551 | v = -v; 1552 | } 1553 | g->sb_hybrid[s_index+!!y] = v; 1554 | g->sb_hybrid[s_index+ !y] = 0; 1555 | } 1556 | s_index+=2; 1557 | } 1558 | } 1559 | 1560 | /* high frequencies */ 1561 | vlc = &huff_quad_vlc[g->count1table_select]; 1562 | last_pos=0; 1563 | while (s_index <= 572) { 1564 | int pos, code; 1565 | pos = get_bits_count(&s->gb); 1566 | if (pos >= end_pos) { 1567 | if (pos > end_pos2 && last_pos) { 1568 | /* some encoders generate an incorrect size for this 1569 | part. We must go back into the data */ 1570 | s_index -= 4; 1571 | skip_bits_long(&s->gb, last_pos - pos); 1572 | break; 1573 | } 1574 | switch_buffer(s, &pos, &end_pos, &end_pos2); 1575 | if (pos >= end_pos) { 1576 | break; 1577 | } 1578 | } 1579 | last_pos= pos; 1580 | 1581 | code = get_vlc2(&s->gb, vlc->table, vlc->bits, 1); 1582 | g->sb_hybrid[s_index+0]= 1583 | g->sb_hybrid[s_index+1]= 1584 | g->sb_hybrid[s_index+2]= 1585 | g->sb_hybrid[s_index+3]= 0; 1586 | while (code) { 1587 | const static int idxtab[16]= {3,3,2,2,1,1,1,1,0,0,0,0,0,0,0,0}; 1588 | int v; 1589 | int pos= s_index+idxtab[code]; 1590 | code ^= 8>>idxtab[code]; 1591 | v = exp_table[ exponents[pos] ]; 1592 | if (get_bits1(&s->gb)) { 1593 | v = -v; 1594 | } 1595 | g->sb_hybrid[pos] = v; 1596 | } 1597 | s_index+=4; 1598 | } 1599 | memset(&g->sb_hybrid[s_index], 0, sizeof(*g->sb_hybrid)*(576 - s_index)); 1600 | 1601 | /* skip extension bits */ 1602 | bits_left = end_pos2 - get_bits_count(&s->gb); 1603 | if (bits_left < 0) { 1604 | return -1; 1605 | } 1606 | skip_bits_long(&s->gb, bits_left); 1607 | 1608 | i= get_bits_count(&s->gb); 1609 | switch_buffer(s, &i, &end_pos, &end_pos2); 1610 | 1611 | return 0; 1612 | } 1613 | 1614 | //////////////////////////////////////////////////////////////////////////////// 1615 | 1616 | static void imdct12(int *out, int *in) 1617 | { 1618 | int in0, in1, in2, in3, in4, in5, t1, t2; 1619 | 1620 | in0= in[0*3]; 1621 | in1= in[1*3] + in[0*3]; 1622 | in2= in[2*3] + in[1*3]; 1623 | in3= in[3*3] + in[2*3]; 1624 | in4= in[4*3] + in[3*3]; 1625 | in5= in[5*3] + in[4*3]; 1626 | in5 += in3; 1627 | in3 += in1; 1628 | 1629 | in2= MULH(2*in2, C3); 1630 | in3= MULH(4*in3, C3); 1631 | 1632 | t1 = in0 - in4; 1633 | t2 = MULH(2*(in1 - in5), icos36h[4]); 1634 | 1635 | out[ 7]= 1636 | out[10]= t1 + t2; 1637 | out[ 1]= 1638 | out[ 4]= t1 - t2; 1639 | 1640 | in0 += in4>>1; 1641 | in4 = in0 + in2; 1642 | in5 += 2*in1; 1643 | in1 = MULH(in5 + in3, icos36h[1]); 1644 | out[ 8]= 1645 | out[ 9]= in4 + in1; 1646 | out[ 2]= 1647 | out[ 3]= in4 - in1; 1648 | 1649 | in0 -= in2; 1650 | in5 = MULH(2*(in5 - in3), icos36h[7]); 1651 | out[ 0]= 1652 | out[ 5]= in0 - in5; 1653 | out[ 6]= 1654 | out[11]= in0 + in5; 1655 | } 1656 | 1657 | static void imdct36(int *out, int *buf, int *in, int *win) 1658 | { 1659 | int i, j, t0, t1, t2, t3, s0, s1, s2, s3; 1660 | int tmp[18], *tmp1, *in1; 1661 | 1662 | for (i=17; i>=1; i--) { 1663 | in[i] += in[i-1]; 1664 | } 1665 | for (i=17; i>=3; i-=2) { 1666 | in[i] += in[i-2]; 1667 | } 1668 | 1669 | for (j=0; j<2; j++) { 1670 | tmp1 = tmp + j; 1671 | in1 = in + j; 1672 | t2 = in1[2*4] + in1[2*8] - in1[2*2]; 1673 | 1674 | t3 = in1[2*0] + (in1[2*6]>>1); 1675 | t1 = in1[2*0] - in1[2*6]; 1676 | tmp1[ 6] = t1 - (t2>>1); 1677 | tmp1[16] = t1 + t2; 1678 | 1679 | t0 = MULH(2*(in1[2*2] + in1[2*4]), C2); 1680 | t1 = MULH( in1[2*4] - in1[2*8] , -2*C8); 1681 | t2 = MULH(2*(in1[2*2] + in1[2*8]), -C4); 1682 | 1683 | tmp1[10] = t3 - t0 - t2; 1684 | tmp1[ 2] = t3 + t0 + t1; 1685 | tmp1[14] = t3 + t2 - t1; 1686 | 1687 | tmp1[ 4] = MULH(2*(in1[2*5] + in1[2*7] - in1[2*1]), -C3); 1688 | t2 = MULH(2*(in1[2*1] + in1[2*5]), C1); 1689 | t3 = MULH( in1[2*5] - in1[2*7] , -2*C7); 1690 | t0 = MULH(2*in1[2*3], C3); 1691 | 1692 | t1 = MULH(2*(in1[2*1] + in1[2*7]), -C5); 1693 | 1694 | tmp1[ 0] = t2 + t3 + t0; 1695 | tmp1[12] = t2 + t1 - t0; 1696 | tmp1[ 8] = t3 - t1 - t0; 1697 | } 1698 | 1699 | i = 0; 1700 | for (j=0; j<4; j++) { 1701 | t0 = tmp[i]; 1702 | t1 = tmp[i + 2]; 1703 | s0 = t1 + t0; 1704 | s2 = t1 - t0; 1705 | 1706 | t2 = tmp[i + 1]; 1707 | t3 = tmp[i + 3]; 1708 | s1 = MULH(2*(t3 + t2), icos36h[j]); 1709 | s3 = MULL(t3 - t2, icos36[8 - j]); 1710 | 1711 | t0 = s0 + s1; 1712 | t1 = s0 - s1; 1713 | out[(9 + j)*SBLIMIT] = MULH(t1, win[9 + j]) + buf[9 + j]; 1714 | out[(8 - j)*SBLIMIT] = MULH(t1, win[8 - j]) + buf[8 - j]; 1715 | buf[9 + j] = MULH(t0, win[18 + 9 + j]); 1716 | buf[8 - j] = MULH(t0, win[18 + 8 - j]); 1717 | 1718 | t0 = s2 + s3; 1719 | t1 = s2 - s3; 1720 | out[(9 + 8 - j)*SBLIMIT] = MULH(t1, win[9 + 8 - j]) + buf[9 + 8 - j]; 1721 | out[( j)*SBLIMIT] = MULH(t1, win[ j]) + buf[ j]; 1722 | buf[9 + 8 - j] = MULH(t0, win[18 + 9 + 8 - j]); 1723 | buf[ + j] = MULH(t0, win[18 + j]); 1724 | i += 4; 1725 | } 1726 | 1727 | s0 = tmp[16]; 1728 | s1 = MULH(2*tmp[17], icos36h[4]); 1729 | t0 = s0 + s1; 1730 | t1 = s0 - s1; 1731 | out[(9 + 4)*SBLIMIT] = MULH(t1, win[9 + 4]) + buf[9 + 4]; 1732 | out[(8 - 4)*SBLIMIT] = MULH(t1, win[8 - 4]) + buf[8 - 4]; 1733 | buf[9 + 4] = MULH(t0, win[18 + 9 + 4]); 1734 | buf[8 - 4] = MULH(t0, win[18 + 8 - 4]); 1735 | } 1736 | 1737 | static void compute_imdct( 1738 | mp3_context_t *s, granule_t *g, int32_t *sb_samples, int32_t *mdct_buf 1739 | ) 1740 | { 1741 | int32_t *ptr, *win, *win1, *buf, *out_ptr, *ptr1; 1742 | int32_t out2[12]; 1743 | int i, j, mdct_long_end, v, sblimit; 1744 | 1745 | /* find last non zero block */ 1746 | ptr = g->sb_hybrid + 576; 1747 | ptr1 = g->sb_hybrid + 2 * 18; 1748 | while (ptr >= ptr1) { 1749 | ptr -= 6; 1750 | v = ptr[0] | ptr[1] | ptr[2] | ptr[3] | ptr[4] | ptr[5]; 1751 | if (v != 0) { 1752 | break; 1753 | } 1754 | } 1755 | sblimit = ((ptr - g->sb_hybrid) / 18) + 1; 1756 | 1757 | if (g->block_type == 2) { 1758 | /* XXX: check for 8000 Hz */ 1759 | if (g->switch_point) { 1760 | mdct_long_end = 2; 1761 | } else { 1762 | mdct_long_end = 0; 1763 | } 1764 | } else { 1765 | mdct_long_end = sblimit; 1766 | } 1767 | 1768 | buf = mdct_buf; 1769 | ptr = g->sb_hybrid; 1770 | for (j=0; jswitch_point && j < 2) { 1775 | win1 = mdct_win[0]; 1776 | } else { 1777 | win1 = mdct_win[g->block_type]; 1778 | } 1779 | /* select frequency inversion */ 1780 | win = win1 + ((4 * 36) & -(j & 1)); 1781 | imdct36(out_ptr, buf, ptr, win); 1782 | out_ptr += 18*SBLIMIT; 1783 | ptr += 18; 1784 | buf += 18; 1785 | } 1786 | for (j=mdct_long_end; j 32767) { 2115 | v = 32767; 2116 | } else if (v < -32768) { 2117 | v = -32768; 2118 | } 2119 | synth_buf[j] = v; 2120 | } 2121 | /* copy to avoid wrap */ 2122 | memcpy(synth_buf + 512, synth_buf, 32 * sizeof(int16_t)); 2123 | 2124 | samples2 = samples + 31 * incr; 2125 | w = window; 2126 | w2 = window + 31; 2127 | 2128 | sum = *dither_state; 2129 | p = synth_buf + 16; 2130 | SUM8(sum, +=, w, p); 2131 | p = synth_buf + 48; 2132 | SUM8(sum, -=, w + 32, p); 2133 | *samples = round_sample(&sum); 2134 | samples += incr; 2135 | w++; 2136 | 2137 | /* we calculate two samples at the same time to avoid one memory 2138 | access per two sample */ 2139 | for (j=1; j<16; j++) { 2140 | sum2 = 0; 2141 | p = synth_buf + 16 + j; 2142 | SUM8P2(sum, +=, sum2, -=, w, w2, p); 2143 | p = synth_buf + 48 - j; 2144 | SUM8P2(sum, -=, sum2, -=, w + 32, w2 + 32, p); 2145 | 2146 | *samples = round_sample(&sum); 2147 | samples += incr; 2148 | sum += sum2; 2149 | *samples2 = round_sample(&sum); 2150 | samples2 -= incr; 2151 | w++; 2152 | w2--; 2153 | } 2154 | 2155 | p = synth_buf + 32; 2156 | SUM8(sum, -=, w + 32, p); 2157 | *samples = round_sample(&sum); 2158 | *dither_state= sum; 2159 | 2160 | offset = (offset - 32) & 511; 2161 | *synth_buf_offset = offset; 2162 | } 2163 | 2164 | //////////////////////////////////////////////////////////////////////////////// 2165 | 2166 | static int decode_header(mp3_context_t *s, uint32_t header) 2167 | { 2168 | int sample_rate, frame_size, mpeg25, padding; 2169 | int sample_rate_index, bitrate_index; 2170 | if (header & (1<<20)) { 2171 | s->lsf = (header & (1<<19)) ? 0 : 1; 2172 | mpeg25 = 0; 2173 | } else { 2174 | s->lsf = 1; 2175 | mpeg25 = 1; 2176 | } 2177 | 2178 | sample_rate_index = (header >> 10) & 3; 2179 | sample_rate = mp3_freq_tab[sample_rate_index] >> (s->lsf + mpeg25); 2180 | sample_rate_index += 3 * (s->lsf + mpeg25); 2181 | s->sample_rate_index = sample_rate_index; 2182 | s->error_protection = ((header >> 16) & 1) ^ 1; 2183 | s->sample_rate = sample_rate; 2184 | 2185 | bitrate_index = (header >> 12) & 0xf; 2186 | padding = (header >> 9) & 1; 2187 | s->mode = (header >> 6) & 3; 2188 | s->mode_ext = (header >> 4) & 3; 2189 | s->nb_channels = (s->mode == MP3_MONO) ? 1 : 2; 2190 | 2191 | if (bitrate_index != 0) { 2192 | frame_size = mp3_bitrate_tab[s->lsf][bitrate_index]; 2193 | s->bit_rate = frame_size * 1000; 2194 | s->frame_size = (frame_size * 144000) / (sample_rate << s->lsf) + padding; 2195 | } else { 2196 | /* if no frame size computed, signal it */ 2197 | return 1; 2198 | } 2199 | return 0; 2200 | } 2201 | 2202 | static int mp_decode_layer3(mp3_context_t *s) 2203 | { 2204 | int nb_granules, main_data_begin, private_bits; 2205 | int gr, ch, blocksplit_flag, i, j, k, n, bits_pos; 2206 | granule_t *g; 2207 | static granule_t granules[2][2]; 2208 | static int16_t exponents[576]; 2209 | const uint8_t *ptr; 2210 | 2211 | if (s->lsf) { 2212 | main_data_begin = _get_bits(&s->gb, 8); 2213 | private_bits = _get_bits(&s->gb, s->nb_channels); 2214 | nb_granules = 1; 2215 | } else { 2216 | main_data_begin = _get_bits(&s->gb, 9); 2217 | if (s->nb_channels == 2) { 2218 | private_bits = _get_bits(&s->gb, 3); 2219 | } else { 2220 | private_bits = _get_bits(&s->gb, 5); 2221 | } 2222 | nb_granules = 2; 2223 | for (ch=0; chnb_channels; ch++) { 2224 | granules[ch][0].scfsi = 0; /* all scale factors are transmitted */ 2225 | granules[ch][1].scfsi = _get_bits(&s->gb, 4); 2226 | } 2227 | } 2228 | 2229 | for (gr=0; grnb_channels; ch++) { 2231 | g = &granules[ch][gr]; 2232 | g->part2_3_length = _get_bits(&s->gb, 12); 2233 | g->big_values = _get_bits(&s->gb, 9); 2234 | g->global_gain = _get_bits(&s->gb, 8); 2235 | /* if MS stereo only is selected, we precompute the 2236 | 1/sqrt(2) renormalization factor */ 2237 | if ((s->mode_ext & (MODE_EXT_MS_STEREO | MODE_EXT_I_STEREO)) == 2238 | MODE_EXT_MS_STEREO) { 2239 | g->global_gain -= 2; 2240 | } 2241 | if (s->lsf) { 2242 | g->scalefac_compress = _get_bits(&s->gb, 9); 2243 | } else { 2244 | g->scalefac_compress = _get_bits(&s->gb, 4); 2245 | } 2246 | blocksplit_flag = _get_bits(&s->gb, 1); 2247 | if (blocksplit_flag) { 2248 | g->block_type = _get_bits(&s->gb, 2); 2249 | if (g->block_type == 0) { 2250 | return -1; 2251 | } 2252 | g->switch_point = _get_bits(&s->gb, 1); 2253 | for (i=0; i<2; i++) { 2254 | g->table_select[i] = _get_bits(&s->gb, 5); 2255 | } 2256 | for (i=0; i<3; i++) { 2257 | g->subblock_gain[i] = _get_bits(&s->gb, 3); 2258 | } 2259 | /* compute huffman coded region sizes */ 2260 | if (g->block_type == 2) { 2261 | g->region_size[0] = (36 / 2); 2262 | } else { 2263 | if (s->sample_rate_index <= 2) { 2264 | g->region_size[0] = (36 / 2); 2265 | } else if (s->sample_rate_index != 8) { 2266 | g->region_size[0] = (54 / 2); 2267 | } else { 2268 | g->region_size[0] = (108 / 2); 2269 | } 2270 | } 2271 | g->region_size[1] = (576 / 2); 2272 | } else { 2273 | int region_address1, region_address2, l; 2274 | g->block_type = 0; 2275 | g->switch_point = 0; 2276 | for (i=0; i<3; i++) { 2277 | g->table_select[i] = _get_bits(&s->gb, 5); 2278 | } 2279 | /* compute huffman coded region sizes */ 2280 | region_address1 = _get_bits(&s->gb, 4); 2281 | region_address2 = _get_bits(&s->gb, 3); 2282 | g->region_size[0] = 2283 | band_index_long[s->sample_rate_index][region_address1 + 1] >> 1; 2284 | l = region_address1 + region_address2 + 2; 2285 | /* should not overflow */ 2286 | if (l > 22) { 2287 | l = 22; 2288 | } 2289 | g->region_size[1] = 2290 | band_index_long[s->sample_rate_index][l] >> 1; 2291 | } 2292 | /* convert region offsets to region sizes and truncate 2293 | size to big_values */ 2294 | g->region_size[2] = (576 / 2); 2295 | j = 0; 2296 | for (i=0; i<3; i++) { 2297 | k = g->region_size[i]; 2298 | if (g->big_values < k) { 2299 | k = g->big_values; 2300 | } 2301 | g->region_size[i] = k - j; 2302 | j = k; 2303 | } 2304 | 2305 | /* compute band indexes */ 2306 | if (g->block_type == 2) { 2307 | if (g->switch_point) { 2308 | /* if switched mode, we handle the 36 first samples as 2309 | long blocks. For 8000Hz, we handle the 48 first 2310 | exponents as long blocks (XXX: check this!) */ 2311 | if (s->sample_rate_index <= 2) { 2312 | g->long_end = 8; 2313 | } else if (s->sample_rate_index != 8) { 2314 | g->long_end = 6; 2315 | } else { 2316 | g->long_end = 4; /* 8000 Hz */ 2317 | } 2318 | 2319 | g->short_start = 2 + (s->sample_rate_index != 8); 2320 | } else { 2321 | g->long_end = 0; 2322 | g->short_start = 0; 2323 | } 2324 | } else { 2325 | g->short_start = 13; 2326 | g->long_end = 22; 2327 | } 2328 | 2329 | g->preflag = 0; 2330 | if (!s->lsf) { 2331 | g->preflag = _get_bits(&s->gb, 1); 2332 | } 2333 | g->scalefac_scale = _get_bits(&s->gb, 1); 2334 | g->count1table_select = _get_bits(&s->gb, 1); 2335 | } 2336 | } 2337 | 2338 | ptr = s->gb.buffer + (get_bits_count(&s->gb)>>3); 2339 | /* now we get bits from the main_data_begin offset */ 2340 | if (main_data_begin > s->last_buf_size) { 2341 | s->last_buf_size= main_data_begin; 2342 | } 2343 | 2344 | memcpy(s->last_buf + s->last_buf_size, ptr, EXTRABYTES); 2345 | s->in_gb= s->gb; 2346 | init_get_bits(&s->gb, s->last_buf + s->last_buf_size - main_data_begin, main_data_begin*8); 2347 | 2348 | for (gr=0; grnb_channels; ch++) { 2350 | g = &granules[ch][gr]; 2351 | 2352 | bits_pos = get_bits_count(&s->gb); 2353 | 2354 | if (!s->lsf) { 2355 | uint8_t *sc; 2356 | int slen, slen1, slen2; 2357 | 2358 | /* MPEG1 scale factors */ 2359 | slen1 = slen_table[0][g->scalefac_compress]; 2360 | slen2 = slen_table[1][g->scalefac_compress]; 2361 | if (g->block_type == 2) { 2362 | n = g->switch_point ? 17 : 18; 2363 | j = 0; 2364 | if (slen1) { 2365 | for (i=0; iscale_factors[j++] = _get_bits(&s->gb, slen1); 2367 | } 2368 | } else { 2369 | memset((void*) &g->scale_factors[j], 0, n); 2370 | j += n; 2371 | // for(i=0;iscale_factors[j++] = 0; 2373 | } 2374 | if (slen2) { 2375 | for (i=0; i<18; i++) { 2376 | g->scale_factors[j++] = _get_bits(&s->gb, slen2); 2377 | } 2378 | for (i=0; i<3; i++) { 2379 | g->scale_factors[j++] = 0; 2380 | } 2381 | } else { 2382 | for (i=0; i<21; i++) { 2383 | g->scale_factors[j++] = 0; 2384 | } 2385 | } 2386 | } else { 2387 | sc = granules[ch][0].scale_factors; 2388 | j = 0; 2389 | for (k=0; k<4; k++) { 2390 | n = (k == 0 ? 6 : 5); 2391 | if ((g->scfsi & (0x8 >> k)) == 0) { 2392 | slen = (k < 2) ? slen1 : slen2; 2393 | if (slen) { 2394 | for (i=0; iscale_factors[j++] = _get_bits(&s->gb, slen); 2396 | } 2397 | } else { 2398 | memset((void*) &g->scale_factors[j], 0, n); 2399 | j += n; 2400 | // for(i=0;iscale_factors[j++] = 0; 2402 | } 2403 | } else { 2404 | /* simply copy from last granule */ 2405 | for (i=0; iscale_factors[j] = sc[j]; 2407 | j++; 2408 | } 2409 | } 2410 | } 2411 | g->scale_factors[j++] = 0; 2412 | } 2413 | } else { 2414 | int tindex, tindex2, slen[4], sl, sf; 2415 | 2416 | /* LSF scale factors */ 2417 | if (g->block_type == 2) { 2418 | tindex = g->switch_point ? 2 : 1; 2419 | } else { 2420 | tindex = 0; 2421 | } 2422 | sf = g->scalefac_compress; 2423 | if ((s->mode_ext & MODE_EXT_I_STEREO) && ch == 1) { 2424 | /* intensity stereo case */ 2425 | sf >>= 1; 2426 | if (sf < 180) { 2427 | lsf_sf_expand(slen, sf, 6, 6, 0); 2428 | tindex2 = 3; 2429 | } else if (sf < 244) { 2430 | lsf_sf_expand(slen, sf - 180, 4, 4, 0); 2431 | tindex2 = 4; 2432 | } else { 2433 | lsf_sf_expand(slen, sf - 244, 3, 0, 0); 2434 | tindex2 = 5; 2435 | } 2436 | } else { 2437 | /* normal case */ 2438 | if (sf < 400) { 2439 | lsf_sf_expand(slen, sf, 5, 4, 4); 2440 | tindex2 = 0; 2441 | } else if (sf < 500) { 2442 | lsf_sf_expand(slen, sf - 400, 5, 4, 0); 2443 | tindex2 = 1; 2444 | } else { 2445 | lsf_sf_expand(slen, sf - 500, 3, 0, 0); 2446 | tindex2 = 2; 2447 | g->preflag = 1; 2448 | } 2449 | } 2450 | 2451 | j = 0; 2452 | for (k=0; k<4; k++) { 2453 | n = lsf_nsf_table[tindex2][tindex][k]; 2454 | sl = slen[k]; 2455 | if (sl) { 2456 | for (i=0; iscale_factors[j++] = _get_bits(&s->gb, sl); 2458 | } 2459 | } else { 2460 | memset((void*) &g->scale_factors[j], 0, n); 2461 | j += n; 2462 | // for(i=0;iscale_factors[j++] = 0; 2464 | } 2465 | } 2466 | /* XXX: should compute exact size */ 2467 | memset((void*) &g->scale_factors[j], 0, 40 - j); 2468 | // for(;j<40;j++) 2469 | // g->scale_factors[j] = 0; 2470 | } 2471 | 2472 | exponents_from_scale_factors(s, g, exponents); 2473 | 2474 | /* read Huffman coded residue */ 2475 | if (huffman_decode(s, g, exponents, 2476 | bits_pos + g->part2_3_length) < 0) { 2477 | return -1; 2478 | } 2479 | } /* ch */ 2480 | 2481 | if (s->nb_channels == 2) { 2482 | compute_stereo(s, &granules[0][gr], &granules[1][gr]); 2483 | } 2484 | 2485 | for (ch=0; chnb_channels; ch++) { 2486 | g = &granules[ch][gr]; 2487 | reorder_block(s, g); 2488 | compute_antialias(s, g); 2489 | compute_imdct(s, g, &s->sb_samples[ch][18 * gr][0], s->mdct_buf[ch]); 2490 | } 2491 | } /* gr */ 2492 | return nb_granules * 18; 2493 | } 2494 | 2495 | static int mp3_decode_main( 2496 | mp3_context_t *s, 2497 | int16_t *samples, const uint8_t *buf, int buf_size 2498 | ) 2499 | { 2500 | int i, nb_frames, ch; 2501 | int16_t *samples_ptr; 2502 | 2503 | init_get_bits(&s->gb, buf + HEADER_SIZE, (buf_size - HEADER_SIZE)*8); 2504 | 2505 | if (s->error_protection) { 2506 | _get_bits(&s->gb, 16); 2507 | } 2508 | 2509 | nb_frames = mp_decode_layer3(s); 2510 | 2511 | s->last_buf_size=0; 2512 | if (s->in_gb.buffer) { 2513 | align_get_bits(&s->gb); 2514 | i= (s->gb.size_in_bits - get_bits_count(&s->gb))>>3; 2515 | if (i >= 0 && i <= BACKSTEP_SIZE) { 2516 | memmove(s->last_buf, s->gb.buffer + (get_bits_count(&s->gb)>>3), i); 2517 | s->last_buf_size=i; 2518 | } 2519 | s->gb= s->in_gb; 2520 | } 2521 | 2522 | align_get_bits(&s->gb); 2523 | i= (s->gb.size_in_bits - get_bits_count(&s->gb))>>3; 2524 | 2525 | if (i<0 || i > BACKSTEP_SIZE || nb_frames<0) { 2526 | i = buf_size - HEADER_SIZE; 2527 | if (BACKSTEP_SIZE < i) { 2528 | i = BACKSTEP_SIZE; 2529 | } 2530 | } 2531 | memcpy(s->last_buf + s->last_buf_size, s->gb.buffer + buf_size - HEADER_SIZE - i, i); 2532 | s->last_buf_size += i; 2533 | 2534 | /* apply the synthesis filter */ 2535 | for (ch=0; chnb_channels; ch++) { 2536 | samples_ptr = samples + ch; 2537 | for (i=0; isynth_buf[ch], &(s->synth_buf_offset[ch]), 2540 | window, &s->dither_state, 2541 | samples_ptr, s->nb_channels, 2542 | s->sb_samples[ch][i] 2543 | ); 2544 | samples_ptr += 32 * s->nb_channels; 2545 | } 2546 | } 2547 | return nb_frames * 32 * sizeof(uint16_t) * s->nb_channels; 2548 | } 2549 | 2550 | //////////////////////////////////////////////////////////////////////////////// 2551 | 2552 | static int mp3_decode_init(mp3_context_t *s) 2553 | { 2554 | static int init=0; 2555 | int i, j, k; 2556 | 2557 | if (!init) { 2558 | /* synth init */ 2559 | for (i=0; i<257; i++) { 2560 | int v; 2561 | v = mp3_enwindow[i]; 2562 | #if WFRAC_BITS < 16 2563 | v = (v + (1 << (16 - WFRAC_BITS - 1))) >> (16 - WFRAC_BITS); 2564 | #endif 2565 | window[i] = v; 2566 | if ((i & 63) != 0) { 2567 | v = -v; 2568 | } 2569 | if (i != 0) { 2570 | window[512 - i] = v; 2571 | } 2572 | } 2573 | 2574 | /* huffman decode tables */ 2575 | for (i=1; i<16; i++) { 2576 | const huff_table_t *h = &mp3_huff_tables[i]; 2577 | int xsize, x, y; 2578 | unsigned int n; 2579 | uint8_t tmp_bits [512]; 2580 | uint16_t tmp_codes[512]; 2581 | 2582 | memset(tmp_bits , 0, sizeof(tmp_bits )); 2583 | memset(tmp_codes, 0, sizeof(tmp_codes)); 2584 | 2585 | xsize = h->xsize; 2586 | n = xsize * xsize; 2587 | 2588 | j = 0; 2589 | for (x=0; xbits [j ]; 2592 | tmp_codes[(x << 5) | y | ((x&&y)<<4)]= h->codes[j++]; 2593 | } 2594 | } 2595 | 2596 | init_vlc(&huff_vlc[i], 7, 512, 2597 | tmp_bits, 1, 1, tmp_codes, 2, 2); 2598 | } 2599 | for (i=0; i<2; i++) { 2600 | init_vlc(&huff_quad_vlc[i], i == 0 ? 7 : 4, 16, 2601 | mp3_quad_bits[i], 1, 1, mp3_quad_codes[i], 1, 1); 2602 | } 2603 | 2604 | for (i=0; i<9; i++) { 2605 | k = 0; 2606 | for (j=0; j<22; j++) { 2607 | band_index_long[i][j] = k; 2608 | k += band_size_long[i][j]; 2609 | } 2610 | band_index_long[i][22] = k; 2611 | } 2612 | 2613 | /* compute n ^ (4/3) and store it in mantissa/exp format */ 2614 | table_4_3_exp= malloc(TABLE_4_3_SIZE * sizeof(table_4_3_exp[0])); 2615 | if (!table_4_3_exp) { 2616 | return -1; 2617 | } 2618 | table_4_3_value= malloc(TABLE_4_3_SIZE * sizeof(table_4_3_value[0])); 2619 | if (!table_4_3_value) { 2620 | return -1; 2621 | } 2622 | 2623 | for (i=1; i>4); 2635 | double f= pow(i&15, 4.0 / 3.0) * pow(2, (exponent-400)*0.25 + FRAC_BITS + 5); 2636 | expval_table[exponent][i&15]= f; 2637 | if ((i&15)==1) { 2638 | exp_table[exponent]= f; 2639 | } 2640 | } 2641 | 2642 | for (i=0; i<7; i++) { 2643 | float f; 2644 | int v; 2645 | if (i != 6) { 2646 | f = tan((double)i * M_PI / 12.0); 2647 | v = FIXR(f / (1.0 + f)); 2648 | } else { 2649 | v = FIXR(1.0); 2650 | } 2651 | is_table[0][i] = v; 2652 | is_table[1][6 - i] = v; 2653 | } 2654 | for (i=7; i<16; i++) { 2655 | is_table[0][i] = is_table[1][i] = 0.0; 2656 | } 2657 | 2658 | for (i=0; i<16; i++) { 2659 | double f; 2660 | int e, k; 2661 | 2662 | for (j=0; j<2; j++) { 2663 | e = -(j + 1) * ((i + 1) >> 1); 2664 | f = pow(2.0, e / 4.0); 2665 | k = i & 1; 2666 | is_table_lsf[j][k ^ 1][i] = FIXR(f); 2667 | is_table_lsf[j][k][i] = FIXR(1.0); 2668 | } 2669 | } 2670 | 2671 | for (i=0; i<8; i++) { 2672 | float ci, cs, ca; 2673 | ci = ci_table[i]; 2674 | cs = 1.0 / sqrt(1.0 + ci * ci); 2675 | ca = cs * ci; 2676 | csa_table[i][0] = FIXHR(cs/4); 2677 | csa_table[i][1] = FIXHR(ca/4); 2678 | csa_table[i][2] = FIXHR(ca/4) + FIXHR(cs/4); 2679 | csa_table[i][3] = FIXHR(ca/4) - FIXHR(cs/4); 2680 | csa_table_float[i][0] = cs; 2681 | csa_table_float[i][1] = ca; 2682 | csa_table_float[i][2] = ca + cs; 2683 | csa_table_float[i][3] = ca - cs; 2684 | } 2685 | 2686 | /* compute mdct windows */ 2687 | for (i=0; i<36; i++) { 2688 | for (j=0; j<4; j++) { 2689 | double d; 2690 | 2691 | if (j==2 && i%3 != 1) { 2692 | continue; 2693 | } 2694 | 2695 | d= sin(M_PI * (i + 0.5) / 36.0); 2696 | if (j==1) { 2697 | if (i>=30) { 2698 | d= 0; 2699 | } else if (i>=24) { 2700 | d= sin(M_PI * (i - 18 + 0.5) / 12.0); 2701 | } else if (i>=18) { 2702 | d= 1; 2703 | } 2704 | } else if (j==3) { 2705 | if (i< 6) { 2706 | d= 0; 2707 | } else if (i< 12) { 2708 | d= sin(M_PI * (i - 6 + 0.5) / 12.0); 2709 | } else if (i< 18) { 2710 | d= 1; 2711 | } 2712 | } 2713 | d*= 0.5 / cos(M_PI*(2*i + 19)/72); 2714 | if (j==2) { 2715 | mdct_win[j][i/3] = FIXHR((d / (1<<5))); 2716 | } else { 2717 | mdct_win[j][i ] = FIXHR((d / (1<<5))); 2718 | } 2719 | } 2720 | } 2721 | for (j=0; j<4; j++) { 2722 | for (i=0; i<36; i+=2) { 2723 | mdct_win[j + 4][i] = mdct_win[j][i]; 2724 | mdct_win[j + 4][i + 1] = -mdct_win[j][i + 1]; 2725 | } 2726 | } 2727 | init = 1; 2728 | } 2729 | return 0; 2730 | } 2731 | 2732 | static int mp3_decode_frame( 2733 | mp3_context_t *s, 2734 | int16_t *out_samples, int *data_size, 2735 | uint8_t *buf, int buf_size 2736 | ) 2737 | { 2738 | uint32_t header; 2739 | int out_size; 2740 | int extra_bytes = 0; 2741 | 2742 | retry: 2743 | if (buf_size < HEADER_SIZE) { 2744 | return -1; 2745 | } 2746 | 2747 | header = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; 2748 | if (mp3_check_header(header) < 0) { 2749 | buf++; 2750 | buf_size--; 2751 | extra_bytes++; 2752 | goto retry; 2753 | } 2754 | 2755 | if (decode_header(s, header) == 1) { 2756 | s->frame_size = -1; 2757 | return -1; 2758 | } 2759 | 2760 | if (s->frame_size<=0 || s->frame_size > buf_size) { 2761 | return -1; // incomplete frame 2762 | } 2763 | if (s->frame_size < buf_size) { 2764 | buf_size = s->frame_size; 2765 | } 2766 | 2767 | out_size = mp3_decode_main(s, out_samples, buf, buf_size); 2768 | if (out_size>=0) { 2769 | *data_size = out_size; 2770 | } 2771 | // else: Error while decoding MPEG audio frame. 2772 | s->frame_size += extra_bytes; 2773 | return buf_size; 2774 | } 2775 | 2776 | //////////////////////////////////////////////////////////////////////////////// 2777 | 2778 | mp3_decoder_t mp3_create(void) 2779 | { 2780 | void *dec = calloc(sizeof(mp3_context_t), 1); 2781 | if (dec) { 2782 | mp3_decode_init((mp3_context_t*) dec); 2783 | } 2784 | return (mp3_decoder_t) dec; 2785 | } 2786 | 2787 | void mp3_done(mp3_decoder_t *dec) 2788 | { 2789 | if (dec) { 2790 | free(dec); 2791 | } 2792 | } 2793 | 2794 | int mp3_decode(mp3_decoder_t *dec, void *buf, int bytes, signed short *out, mp3_info_t *info) 2795 | { 2796 | int res, size = -1; 2797 | mp3_context_t *s = (mp3_context_t*) dec; 2798 | if (!s) { 2799 | return 0; 2800 | } 2801 | res = mp3_decode_frame(s, (int16_t*) out, &size, buf, bytes); 2802 | if (res < 0) { 2803 | return 0; 2804 | } 2805 | if (info) { 2806 | info->sample_rate = s->sample_rate; 2807 | info->channels = s->nb_channels; 2808 | info->audio_bytes = size; 2809 | } 2810 | return s->frame_size; 2811 | } 2812 | 2813 | #undef UPDATE_CACHE 2814 | #undef BF 2815 | -------------------------------------------------------------------------------- /parg.h: -------------------------------------------------------------------------------- 1 | /* 2 | * parg - parse argv 3 | * 4 | * Written in 2015-2016 by Joergen Ibsen 5 | * 6 | * To the extent possible under law, the author(s) have dedicated all 7 | * copyright and related and neighboring rights to this software to the 8 | * public domain worldwide. This software is distributed without any 9 | * warranty. 10 | */ 11 | 12 | #ifndef PARG_H_INCLUDED 13 | #define PARG_H_INCLUDED 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #define PARG_VER_MAJOR 1 /**< Major version number */ 20 | #define PARG_VER_MINOR 0 /**< Minor version number */ 21 | #define PARG_VER_PATCH 2 /**< Patch version number */ 22 | #define PARG_VER_STRING "1.0.2" /**< Version number as a string */ 23 | 24 | /** 25 | * Structure containing state between calls to parser. 26 | * 27 | * @see parg_init 28 | */ 29 | struct parg_state { 30 | const char *optarg; /**< Pointer to option argument, if any */ 31 | int optind; /**< Next index in argv to process */ 32 | int optopt; /**< Option value resulting in error, if any */ 33 | const char *nextchar; /**< Next character to process */ 34 | }; 35 | 36 | /** 37 | * Structure for supplying long options to `parg_getopt_long()`. 38 | * 39 | * @see parg_getopt_long 40 | */ 41 | struct parg_option { 42 | const char *name; /**< Name of option */ 43 | int has_arg; /**< Option argument status */ 44 | int *flag; /**< Pointer to flag variable */ 45 | int val; /**< Value of option */ 46 | }; 47 | 48 | /** 49 | * Values for `has_arg` flag in `parg_option`. 50 | * 51 | * @see parg_option 52 | */ 53 | typedef enum { 54 | PARG_NOARG, /**< No argument */ 55 | PARG_REQARG, /**< Required argument */ 56 | PARG_OPTARG /**< Optional argument */ 57 | } parg_arg_num; 58 | 59 | /** 60 | * Initialize `ps`. 61 | * 62 | * Must be called before using state with a parser. 63 | * 64 | * @see parg_state 65 | * 66 | * @param ps pointer to state 67 | */ 68 | void 69 | parg_init(struct parg_state *ps); 70 | 71 | /** 72 | * Parse next short option in `argv`. 73 | * 74 | * Elements in `argv` that contain short options start with a single dash 75 | * followed by one or more option characters, and optionally an option 76 | * argument for the last option character. Examples are '`-d`', '`-ofile`', 77 | * and '`-dofile`'. 78 | * 79 | * Consecutive calls to this function match the command-line arguments in 80 | * `argv` against the short option characters in `optstring`. 81 | * 82 | * If an option character in `optstring` is followed by a colon, '`:`', the 83 | * option requires an argument. If it is followed by two colons, the option 84 | * may take an optional argument. 85 | * 86 | * If a match is found, `optarg` points to the option argument, if any, and 87 | * the value of the option character is returned. 88 | * 89 | * If a match is found, but is missing a required option argument, `optopt` 90 | * is set to the option character. If the first character in `optstring` is 91 | * '`:`', then '`:`' is returned, otherwise '`?`' is returned. 92 | * 93 | * If no option character in `optstring` matches a short option, `optopt` 94 | * is set to the option character, and '`?`' is returned. 95 | * 96 | * If an element of argv does not contain options (a nonoption element), 97 | * `optarg` points to the element, and `1` is returned. 98 | * 99 | * An element consisting of a single dash, '`-`', is returned as a nonoption. 100 | * 101 | * Parsing stops and `-1` is returned, when the end of `argv` is reached, or 102 | * if an element contains '`--`'. 103 | * 104 | * Works similarly to `getopt`, if `optstring` were prefixed by '`-`'. 105 | * 106 | * @param ps pointer to state 107 | * @param argc number of elements in `argv` 108 | * @param argv array of pointers to command-line arguments 109 | * @param optstring string containing option characters 110 | * @return option value on match, `1` on nonoption element, `-1` on end of 111 | * arguments, '`?`' on unmatched option, '`?`' or '`:`' on option argument 112 | * error 113 | */ 114 | int 115 | parg_getopt(struct parg_state *ps, int argc, char *const argv[], 116 | const char *optstring); 117 | 118 | /** 119 | * Parse next long or short option in `argv`. 120 | * 121 | * Elements in `argv` that contain a long option start with two dashes 122 | * followed by a string, and optionally an equal sign and an option argument. 123 | * Examples are '`--help`' and '`--size=5`'. 124 | * 125 | * If no exact match is found, an unambiguous prefix of a long option will 126 | * match. For example, if '`foo`' and '`foobar`' are valid long options, then 127 | * '`--fo`' is ambiguous and will not match, '`--foo`' matches exactly, and 128 | * '`--foob`' is an unambiguous prefix and will match. 129 | * 130 | * If a long option match is found, and `flag` is `NULL`, `val` is returned. 131 | * 132 | * If a long option match is found, and `flag` is not `NULL`, `val` is stored 133 | * in the variable `flag` points to, and `0` is returned. 134 | * 135 | * If a long option match is found, but is missing a required option argument, 136 | * or has an option argument even though it takes none, `optopt` is set to 137 | * `val` if `flag` is `NULL`, and `0` otherwise. If the first character in 138 | * `optstring` is '`:`', then '`:`' is returned, otherwise '`?`' is returned. 139 | * 140 | * If `longindex` is not `NULL`, the index of the entry in `longopts` that 141 | * matched is stored there. 142 | * 143 | * If no long option in `longopts` matches a long option, '`?`' is returned. 144 | * 145 | * Handling of nonoptions and short options is like `parg_getopt()`. 146 | * 147 | * If no short options are required, an empty string, `""`, should be passed 148 | * as `optstring`. 149 | * 150 | * Works similarly to `getopt_long`, if `optstring` were prefixed by '`-`'. 151 | * 152 | * @see parg_getopt 153 | * 154 | * @param ps pointer to state 155 | * @param argc number of elements in `argv` 156 | * @param argv array of pointers to command-line arguments 157 | * @param optstring string containing option characters 158 | * @param longopts array of `parg_option` structures 159 | * @param longindex pointer to variable to store index of matching option in 160 | * @return option value on match, `0` for flag option, `1` on nonoption 161 | * element, `-1` on end of arguments, '`?`' on unmatched or ambiguous option, 162 | * '`?`' or '`:`' on option argument error 163 | */ 164 | int 165 | parg_getopt_long(struct parg_state *ps, int argc, char *const argv[], 166 | const char *optstring, 167 | const struct parg_option *longopts, int *longindex); 168 | 169 | /** 170 | * Reorder elements of `argv` so options appear first. 171 | * 172 | * If there are no long options, `longopts` may be `NULL`. 173 | * 174 | * The return value can be used as `argc` parameter for `parg_getopt()` and 175 | * `parg_getopt_long()`. 176 | * 177 | * @param argc number of elements in `argv` 178 | * @param argv array of pointers to command-line arguments 179 | * @param optstring string containing option characters 180 | * @param longopts array of `parg_option` structures 181 | * @return index of first nonoption in `argv` on success, `-1` on error 182 | */ 183 | int 184 | parg_reorder(int argc, char *argv[], 185 | const char *optstring, 186 | const struct parg_option *longopts); 187 | 188 | 189 | #ifdef PARG_IMPLEMENTATION 190 | /* 191 | * parg - parse argv 192 | * 193 | * Written in 2015-2016 by Joergen Ibsen 194 | * 195 | * To the extent possible under law, the author(s) have dedicated all 196 | * copyright and related and neighboring rights to this software to the 197 | * public domain worldwide. This software is distributed without any 198 | * warranty. 199 | */ 200 | 201 | #include "parg.h" 202 | 203 | #include 204 | #include 205 | #include 206 | 207 | /* 208 | * Check if state is at end of argv. 209 | */ 210 | static int 211 | is_argv_end(const struct parg_state *ps, int argc, char *const argv[]) 212 | { 213 | return ps->optind >= argc || argv[ps->optind] == NULL; 214 | } 215 | 216 | /* 217 | * Match nextchar against optstring. 218 | */ 219 | static int 220 | match_short(struct parg_state *ps, int argc, char *const argv[], 221 | const char *optstring) 222 | { 223 | const char *p = strchr(optstring, *ps->nextchar); 224 | 225 | if (p == NULL) { 226 | ps->optopt = *ps->nextchar++; 227 | return '?'; 228 | } 229 | 230 | /* If no option argument, return option */ 231 | if (p[1] != ':') { 232 | return *ps->nextchar++; 233 | } 234 | 235 | /* If more characters, return as option argument */ 236 | if (ps->nextchar[1] != '\0') { 237 | ps->optarg = &ps->nextchar[1]; 238 | ps->nextchar = NULL; 239 | return *p; 240 | } 241 | 242 | /* If option argument is optional, return option */ 243 | if (p[2] == ':') { 244 | return *ps->nextchar++; 245 | } 246 | 247 | /* Option argument required, so return next argv element */ 248 | if (is_argv_end(ps, argc, argv)) { 249 | ps->optopt = *ps->nextchar++; 250 | return optstring[0] == ':' ? ':' : '?'; 251 | } 252 | 253 | ps->optarg = argv[ps->optind++]; 254 | ps->nextchar = NULL; 255 | return *p; 256 | } 257 | 258 | /* 259 | * Match string at nextchar against longopts. 260 | */ 261 | static int 262 | match_long(struct parg_state *ps, int argc, char *const argv[], 263 | const char *optstring, 264 | const struct parg_option *longopts, int *longindex) 265 | { 266 | size_t len; 267 | int num_match = 0; 268 | int match = -1; 269 | int i; 270 | 271 | len = strcspn(ps->nextchar, "="); 272 | 273 | for (i = 0; longopts[i].name; ++i) { 274 | if (strncmp(ps->nextchar, longopts[i].name, len) == 0) { 275 | match = i; 276 | num_match++; 277 | /* Take if exact match */ 278 | if (longopts[i].name[len] == '\0') { 279 | num_match = 1; 280 | break; 281 | } 282 | } 283 | } 284 | 285 | /* Return '?' on no or ambiguous match */ 286 | if (num_match != 1) { 287 | ps->optopt = 0; 288 | ps->nextchar = NULL; 289 | return '?'; 290 | } 291 | 292 | assert(match != -1); 293 | 294 | if (longindex) { 295 | *longindex = match; 296 | } 297 | 298 | if (ps->nextchar[len] == '=') { 299 | /* Option argument present, check if extraneous */ 300 | if (longopts[match].has_arg == PARG_NOARG) { 301 | ps->optopt = longopts[match].flag ? 0 : longopts[match].val; 302 | ps->nextchar = NULL; 303 | return optstring[0] == ':' ? ':' : '?'; 304 | } 305 | else { 306 | ps->optarg = &ps->nextchar[len + 1]; 307 | } 308 | } 309 | else if (longopts[match].has_arg == PARG_REQARG) { 310 | /* Option argument required, so return next argv element */ 311 | if (is_argv_end(ps, argc, argv)) { 312 | ps->optopt = longopts[match].flag ? 0 : longopts[match].val; 313 | ps->nextchar = NULL; 314 | return optstring[0] == ':' ? ':' : '?'; 315 | } 316 | 317 | ps->optarg = argv[ps->optind++]; 318 | } 319 | 320 | ps->nextchar = NULL; 321 | 322 | if (longopts[match].flag != NULL) { 323 | *longopts[match].flag = longopts[match].val; 324 | return 0; 325 | } 326 | 327 | return longopts[match].val; 328 | } 329 | 330 | void 331 | parg_init(struct parg_state *ps) 332 | { 333 | ps->optarg = NULL; 334 | ps->optind = 1; 335 | ps->optopt = '?'; 336 | ps->nextchar = NULL; 337 | } 338 | 339 | int 340 | parg_getopt(struct parg_state *ps, int argc, char *const argv[], 341 | const char *optstring) 342 | { 343 | return parg_getopt_long(ps, argc, argv, optstring, NULL, NULL); 344 | } 345 | 346 | int 347 | parg_getopt_long(struct parg_state *ps, int argc, char *const argv[], 348 | const char *optstring, 349 | const struct parg_option *longopts, int *longindex) 350 | { 351 | assert(ps != NULL); 352 | assert(argv != NULL); 353 | assert(optstring != NULL); 354 | 355 | ps->optarg = NULL; 356 | 357 | if (argc < 2) { 358 | return -1; 359 | } 360 | 361 | /* Advance to next element if needed */ 362 | if (ps->nextchar == NULL || *ps->nextchar == '\0') { 363 | if (is_argv_end(ps, argc, argv)) { 364 | return -1; 365 | } 366 | 367 | ps->nextchar = argv[ps->optind++]; 368 | 369 | /* Check for nonoption element (including '-') */ 370 | if (ps->nextchar[0] != '-' || ps->nextchar[1] == '\0') { 371 | ps->optarg = ps->nextchar; 372 | ps->nextchar = NULL; 373 | return 1; 374 | } 375 | 376 | /* Check for '--' */ 377 | if (ps->nextchar[1] == '-') { 378 | if (ps->nextchar[2] == '\0') { 379 | ps->nextchar = NULL; 380 | return -1; 381 | } 382 | 383 | if (longopts != NULL) { 384 | ps->nextchar += 2; 385 | 386 | return match_long(ps, argc, argv, optstring, 387 | longopts, longindex); 388 | } 389 | } 390 | 391 | ps->nextchar++; 392 | } 393 | 394 | /* Match nextchar */ 395 | return match_short(ps, argc, argv, optstring); 396 | } 397 | 398 | /* 399 | * Reverse elements of `v` from `i` to `j`. 400 | */ 401 | static void 402 | reverse(char *v[], int i, int j) 403 | { 404 | while (j - i > 1) { 405 | char *tmp = v[i]; 406 | v[i] = v[j - 1]; 407 | v[j - 1] = tmp; 408 | ++i; 409 | --j; 410 | } 411 | } 412 | 413 | /* 414 | * Reorder elements of `argv` with no special cases. 415 | * 416 | * This function assumes there is no `--` element, and the last element 417 | * is not an option missing a required argument. 418 | * 419 | * The algorithm is described here: 420 | * http://hardtoc.com/2016/11/07/reordering-arguments.html 421 | */ 422 | static int 423 | parg_reorder_simple(int argc, char *argv[], 424 | const char *optstring, 425 | const struct parg_option *longopts) 426 | { 427 | struct parg_state ps; 428 | int change; 429 | int l = 0; 430 | int m = 0; 431 | int r = 0; 432 | 433 | if (argc < 2) { 434 | return argc; 435 | } 436 | 437 | do { 438 | int nextind; 439 | int c; 440 | 441 | parg_init(&ps); 442 | 443 | nextind = ps.optind; 444 | 445 | /* Parse until end of argument */ 446 | do { 447 | c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); 448 | } while (ps.nextchar != NULL && *ps.nextchar != '\0'); 449 | 450 | change = 0; 451 | 452 | do { 453 | /* Find next non-option */ 454 | for (l = nextind; c != 1 && c != -1;) { 455 | l = ps.optind; 456 | 457 | do { 458 | c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); 459 | } while (ps.nextchar != NULL && *ps.nextchar != '\0'); 460 | } 461 | 462 | /* Find next option */ 463 | for (m = l; c == 1;) { 464 | m = ps.optind; 465 | 466 | do { 467 | c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); 468 | } while (ps.nextchar != NULL && *ps.nextchar != '\0'); 469 | } 470 | 471 | /* Find next non-option */ 472 | for (r = m; c != 1 && c != -1;) { 473 | r = ps.optind; 474 | 475 | do { 476 | c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); 477 | } while (ps.nextchar != NULL && *ps.nextchar != '\0'); 478 | } 479 | 480 | /* Find next option */ 481 | for (nextind = r; c == 1;) { 482 | nextind = ps.optind; 483 | 484 | do { 485 | c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); 486 | } while (ps.nextchar != NULL && *ps.nextchar != '\0'); 487 | } 488 | 489 | if (m < r) { 490 | change = 1; 491 | reverse(argv, l, m); 492 | reverse(argv, m, r); 493 | reverse(argv, l, r); 494 | } 495 | } while (c != -1); 496 | } while (change != 0); 497 | 498 | return l + (r - m); 499 | } 500 | 501 | int 502 | parg_reorder(int argc, char *argv[], 503 | const char *optstring, 504 | const struct parg_option *longopts) 505 | { 506 | struct parg_state ps; 507 | int lastind; 508 | int optend; 509 | int c; 510 | 511 | assert(argv != NULL); 512 | assert(optstring != NULL); 513 | 514 | if (argc < 2) { 515 | return argc; 516 | } 517 | 518 | parg_init(&ps); 519 | 520 | /* Find end of normal arguments */ 521 | do { 522 | lastind = ps.optind; 523 | 524 | c = parg_getopt_long(&ps, argc, argv, optstring, longopts, NULL); 525 | 526 | /* Check for trailing option with error */ 527 | if ((c == '?' || c == ':') && is_argv_end(&ps, argc, argv)) { 528 | lastind = ps.optind - 1; 529 | break; 530 | } 531 | } while (c != -1); 532 | 533 | optend = parg_reorder_simple(lastind, argv, optstring, longopts); 534 | 535 | /* Rotate `--` or trailing option with error into position */ 536 | if (lastind < argc) { 537 | reverse(argv, optend, lastind); 538 | reverse(argv, optend, lastind + 1); 539 | ++optend; 540 | } 541 | 542 | return optend; 543 | } 544 | #endif 545 | 546 | 547 | #ifdef __cplusplus 548 | } /* extern "C" */ 549 | #endif 550 | 551 | #endif /* PARG_H_INCLUDED */ 552 | -------------------------------------------------------------------------------- /random.h: -------------------------------------------------------------------------------- 1 | /* public domain Simple, Minimalistic, random function 2 | * ©2017-2023 Yuichiro Nakada 3 | * */ 4 | 5 | #ifndef RANDOM_H 6 | #define RANDOM_H 7 | 8 | #define XOR128_MAX 18446744073709551615.0 9 | 10 | typedef unsigned long int uint64_t; 11 | 12 | // The state must be seeded so that it is not everywhere zero. 13 | uint64_t xor128_seed[2]; 14 | 15 | static void xor128_init(unsigned int s) 16 | { 17 | for (int i=1; i<=2; i++) { 18 | xor128_seed[i-1] = s = 1812433253U * ( s ^ ( s >> 30 ) ) + i; 19 | } 20 | } 21 | 22 | static inline uint64_t xor128() 23 | { 24 | uint64_t s1 = xor128_seed[0]; 25 | const uint64_t s0 = xor128_seed[1]; 26 | xor128_seed[0] = s0; 27 | s1 ^= s1 << 23; 28 | return ( xor128_seed[1] = ( s1 ^ s0 ^ ( s1 >> 17 ) ^ ( s0 >> 26 ) ) ) + s0; 29 | } 30 | 31 | // xoroshiro generator taken from http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c 32 | uint64_t xoroshiro_s[2] = { 33 | 0X922AC4EB35B502D9L, 34 | 0XDA3AA4832B8F1D27L 35 | }; 36 | static void xoroshiro128plus_init(uint64_t s) 37 | { 38 | for (int i=1; i<=2; i++) { 39 | xoroshiro_s[i-1] = s = 1812433253U * ( s ^ ( s >> 30 ) ) + i; 40 | } 41 | } 42 | static inline uint64_t rotl(const uint64_t x, int k) 43 | { 44 | return (x << k) | (x >> (64 - k)); 45 | } 46 | static uint64_t xoroshiro128plus() 47 | { 48 | const uint64_t s0 = xoroshiro_s[0]; 49 | uint64_t s1 = xoroshiro_s[1]; 50 | const uint64_t result = s0 + s1; 51 | 52 | s1 ^= s0; 53 | xoroshiro_s[0] = rotl(s0, 55) ^ s1 ^ (s1 << 14); // a, b 54 | xoroshiro_s[1] = rotl(s1, 36); // c 55 | return result; 56 | } 57 | 58 | // taken from https://github.com/svaarala/duktape/blob/master/misc/splitmix64.c 59 | static uint64_t splitmix64_x; /* The state can be seeded with any value. */ 60 | static uint64_t splitmix64_next() 61 | { 62 | uint64_t z = (splitmix64_x += UINT64_C(0x9E3779B97F4A7C15)); 63 | z = (z ^ (z >> 30)) * UINT64_C(0xBF58476D1CE4E5B9); 64 | z = (z ^ (z >> 27)) * UINT64_C(0x94D049BB133111EB); 65 | return z ^ (z >> 31); 66 | } 67 | 68 | // execute RDTSC instruction and return cycle counter value 69 | static uint64_t rdtsc() 70 | { 71 | uint64_t result; 72 | __asm__ volatile ("rdtsc" : "=A" (result)); 73 | return result; 74 | } 75 | #define MATH_PI 3.14159265358979323846 76 | #define MATH_E 2.7182818284590452354 77 | #define CLK_TICK 16 78 | // physical random number generator 79 | static uint32_t prand32() 80 | { 81 | uint32_t y; 82 | char s1[80], s2[80]; 83 | uint64_t start_clk; 84 | uint64_t stop_clk; 85 | unsigned rnd_bit; 86 | unsigned i; 87 | 88 | y = 0; 89 | for (i=0; i<32; i++) { 90 | start_clk = rdtsc(); 91 | sprintf(s1, "%70.40lf", (double)y*MATH_PI); // meaningless, waste time... 92 | sprintf(s2, "%lf", atof(s1)*MATH_E); // meaningless, waste time... 93 | sprintf(s1, "%lf", atof(s2)/MATH_PI); // meaningless, waste time... 94 | sprintf(s2, "%s", s1); // meaningless, waste time... 95 | stop_clk = rdtsc(); 96 | rnd_bit = ((stop_clk-start_clk)/CLK_TICK)%2; 97 | y = (y<<1)|rnd_bit; 98 | //printf("%u %u %u\n", (unsigned)(stop_clk-start_clk)/CLK_TICK, (unsigned)stop_clk, (unsigned)start_clk); 99 | } 100 | return y; 101 | } 102 | 103 | //#define CATS_USE_XOR128 104 | #ifdef CATS_USE_XOR128 105 | #define xrand() xor128() 106 | #define frand() ( xor128() / (XOR128_MAX+1.0) ) 107 | #else 108 | #define xrand() xoroshiro128plus() 109 | #define frand() ( xoroshiro128plus() / (XOR128_MAX+1.0) ) 110 | #endif 111 | #define _rand(max) (int)( frand() * max) 112 | #define random(min, max) ( frand() * (max -min) +min ) 113 | #define irand(min, max) ( (xrand() % (max -min +1)) +min ) 114 | // http://www.natural-science.or.jp/article/20110404234734.php (mt19937ar.h) 115 | // https://omitakahiro.github.io/random/random_variables_generation.html 116 | 117 | #endif 118 | -------------------------------------------------------------------------------- /regexp.h: -------------------------------------------------------------------------------- 1 | #ifndef regexp_h 2 | #define regexp_h 3 | 4 | typedef struct Reprog Reprog; 5 | typedef struct Resub Resub; 6 | 7 | Reprog *regcomp(const char *pattern, int cflags, const char **errorp); 8 | int regexec(Reprog *prog, const char *string, Resub *sub, int eflags); 9 | void regfree(Reprog *prog); 10 | 11 | enum { 12 | /* regcomp flags */ 13 | REG_ICASE = 1, 14 | REG_NEWLINE = 2, 15 | 16 | /* regexec flags */ 17 | REG_NOTBOL = 4, 18 | 19 | /* limits */ 20 | REG_MAXSUB = 10 21 | }; 22 | 23 | struct Resub { 24 | unsigned int nsub; 25 | struct { 26 | const char *sp; 27 | const char *ep; 28 | } sub[REG_MAXSUB]; 29 | }; 30 | 31 | #endif 32 | 33 | 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | //#include "regexp.h" 42 | 43 | #define nelem(a) (sizeof (a) / sizeof (a)[0]) 44 | 45 | typedef unsigned int Rune; 46 | 47 | static int isalpharune(Rune c) 48 | { 49 | /* TODO: Add unicode support */ 50 | return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); 51 | } 52 | 53 | static Rune toupperrune(Rune c) 54 | { 55 | /* TODO: Add unicode support */ 56 | if (c >= 'a' && c <= 'z') 57 | return c - 'a' + 'A'; 58 | return c; 59 | } 60 | 61 | static int chartorune(Rune *r, const char *s) 62 | { 63 | /* TODO: Add UTF-8 decoding */ 64 | *r = *s; 65 | return 1; 66 | } 67 | 68 | #define REPINF 255 69 | #define MAXSUB REG_MAXSUB 70 | #define MAXPROG (32 << 10) 71 | 72 | typedef struct Reclass Reclass; 73 | typedef struct Renode Renode; 74 | typedef struct Reinst Reinst; 75 | typedef struct Rethread Rethread; 76 | 77 | struct Reclass { 78 | Rune *end; 79 | Rune spans[64]; 80 | }; 81 | 82 | struct Reprog { 83 | Reinst *start, *end; 84 | int flags; 85 | unsigned int nsub; 86 | Reclass cclass[16]; 87 | }; 88 | 89 | static struct { 90 | Reprog *prog; 91 | Renode *pstart, *pend; 92 | 93 | const char *source; 94 | unsigned int ncclass; 95 | unsigned int nsub; 96 | Renode *sub[MAXSUB]; 97 | 98 | int lookahead; 99 | Rune yychar; 100 | Reclass *yycc; 101 | int yymin, yymax; 102 | 103 | const char *error; 104 | jmp_buf kaboom; 105 | } g; 106 | 107 | static void die(const char *message) 108 | { 109 | g.error = message; 110 | longjmp(g.kaboom, 1); 111 | } 112 | 113 | static Rune canon(Rune c) 114 | { 115 | Rune u = toupperrune(c); 116 | if (c >= 128 && u < 128) 117 | return c; 118 | return u; 119 | } 120 | 121 | /* Scan */ 122 | 123 | enum { 124 | L_CHAR = 256, 125 | L_CCLASS, /* character class */ 126 | L_NCCLASS, /* negative character class */ 127 | L_NC, /* "(?:" no capture */ 128 | L_PLA, /* "(?=" positive lookahead */ 129 | L_NLA, /* "(?!" negative lookahead */ 130 | L_WORD, /* "\b" word boundary */ 131 | L_NWORD, /* "\B" non-word boundary */ 132 | L_REF, /* "\1" back-reference */ 133 | L_COUNT /* {M,N} */ 134 | }; 135 | 136 | static int hex(int c) 137 | { 138 | if (c >= '0' && c <= '9') return c - '0'; 139 | if (c >= 'a' && c <= 'f') return c - 'a' + 0xA; 140 | if (c >= 'A' && c <= 'F') return c - 'A' + 0xA; 141 | die("invalid escape sequence"); 142 | return 0; 143 | } 144 | 145 | static int dec(int c) 146 | { 147 | if (c >= '0' && c <= '9') return c - '0'; 148 | die("invalid quantifier"); 149 | return 0; 150 | } 151 | 152 | #define ESCAPES "BbDdSsWw^$\\.*+?()[]{}|0123456789" 153 | 154 | static int isunicodeletter(int c) 155 | { 156 | return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || isalpharune(c); 157 | } 158 | 159 | static int nextrune(void) 160 | { 161 | g.source += chartorune(&g.yychar, g.source); 162 | if (g.yychar == '\\') { 163 | g.source += chartorune(&g.yychar, g.source); 164 | switch (g.yychar) { 165 | case 0: die("unterminated escape sequence"); break; 166 | case 'f': g.yychar = '\f'; return 0; 167 | case 'n': g.yychar = '\n'; return 0; 168 | case 'r': g.yychar = '\r'; return 0; 169 | case 't': g.yychar = '\t'; return 0; 170 | case 'v': g.yychar = '\v'; return 0; 171 | case 'c': 172 | g.yychar = (*g.source++) & 31; 173 | return 0; 174 | case 'x': 175 | g.yychar = hex(*g.source++) << 4; 176 | g.yychar += hex(*g.source++); 177 | if (g.yychar == 0) { 178 | g.yychar = '0'; 179 | return 1; 180 | } 181 | return 0; 182 | case 'u': 183 | g.yychar = hex(*g.source++) << 12; 184 | g.yychar += hex(*g.source++) << 8; 185 | g.yychar += hex(*g.source++) << 4; 186 | g.yychar += hex(*g.source++); 187 | if (g.yychar == 0) { 188 | g.yychar = '0'; 189 | return 1; 190 | } 191 | return 0; 192 | } 193 | if (strchr(ESCAPES, g.yychar)) 194 | return 1; 195 | if (isunicodeletter(g.yychar) || g.yychar == '_') /* check identity escape */ 196 | die("invalid escape character"); 197 | return 0; 198 | } 199 | return 0; 200 | } 201 | 202 | static int lexcount(void) 203 | { 204 | g.yychar = *g.source++; 205 | 206 | g.yymin = dec(g.yychar); 207 | g.yychar = *g.source++; 208 | while (g.yychar != ',' && g.yychar != '}') { 209 | g.yymin = g.yymin * 10 + dec(g.yychar); 210 | g.yychar = *g.source++; 211 | } 212 | if (g.yymin >= REPINF) 213 | die("numeric overflow"); 214 | 215 | if (g.yychar == ',') { 216 | g.yychar = *g.source++; 217 | if (g.yychar == '}') { 218 | g.yymax = REPINF; 219 | } else { 220 | g.yymax = dec(g.yychar); 221 | g.yychar = *g.source++; 222 | while (g.yychar != '}') { 223 | g.yymax = g.yymax * 10 + dec(g.yychar); 224 | g.yychar = *g.source++; 225 | } 226 | if (g.yymax >= REPINF) 227 | die("numeric overflow"); 228 | } 229 | } else { 230 | g.yymax = g.yymin; 231 | } 232 | 233 | return L_COUNT; 234 | } 235 | 236 | static void newcclass(void) 237 | { 238 | if (g.ncclass >= nelem(g.prog->cclass)) 239 | die("too many character classes"); 240 | g.yycc = g.prog->cclass + g.ncclass++; 241 | g.yycc->end = g.yycc->spans; 242 | } 243 | 244 | static void addrange(Rune a, Rune b) 245 | { 246 | if (a > b) 247 | die("invalid character class range"); 248 | if (g.yycc->end + 2 == g.yycc->spans + nelem(g.yycc->spans)) 249 | die("too many character class ranges"); 250 | *g.yycc->end++ = a; 251 | *g.yycc->end++ = b; 252 | } 253 | 254 | static void addranges_d(void) 255 | { 256 | addrange('0', '9'); 257 | } 258 | 259 | static void addranges_D(void) 260 | { 261 | addrange(0, '0'-1); 262 | addrange('9'+1, 0xFFFF); 263 | } 264 | 265 | static void addranges_s(void) 266 | { 267 | addrange(0x9, 0x9); 268 | addrange(0xA, 0xD); 269 | addrange(0x20, 0x20); 270 | addrange(0xA0, 0xA0); 271 | addrange(0x2028, 0x2029); 272 | addrange(0xFEFF, 0xFEFF); 273 | } 274 | 275 | static void addranges_S(void) 276 | { 277 | addrange(0, 0x9-1); 278 | addrange(0x9+1, 0xA-1); 279 | addrange(0xD+1, 0x20-1); 280 | addrange(0x20+1, 0xA0-1); 281 | addrange(0xA0+1, 0x2028-1); 282 | addrange(0x2029+1, 0xFEFF-1); 283 | addrange(0xFEFF+1, 0xFFFF); 284 | } 285 | 286 | static void addranges_w(void) 287 | { 288 | addrange('0', '9'); 289 | addrange('A', 'Z'); 290 | addrange('_', '_'); 291 | addrange('a', 'z'); 292 | } 293 | 294 | static void addranges_W(void) 295 | { 296 | addrange(0, '0'-1); 297 | addrange('9'+1, 'A'-1); 298 | addrange('Z'+1, '_'-1); 299 | addrange('_'+1, 'a'-1); 300 | addrange('z'+1, 0xFFFF); 301 | } 302 | 303 | static int lexclass(void) 304 | { 305 | int type = L_CCLASS; 306 | int quoted, havesave, havedash; 307 | Rune save = 0; 308 | 309 | newcclass(); 310 | 311 | quoted = nextrune(); 312 | if (!quoted && g.yychar == '^') { 313 | type = L_NCCLASS; 314 | quoted = nextrune(); 315 | } 316 | 317 | havesave = havedash = 0; 318 | for (;;) { 319 | if (g.yychar == 0) 320 | die("unterminated character class"); 321 | if (!quoted && g.yychar == ']') 322 | break; 323 | 324 | if (!quoted && g.yychar == '-') { 325 | if (havesave) { 326 | if (havedash) { 327 | addrange(save, '-'); 328 | havesave = havedash = 0; 329 | } else { 330 | havedash = 1; 331 | } 332 | } else { 333 | save = '-'; 334 | havesave = 1; 335 | } 336 | } else if (quoted && strchr("DSWdsw", g.yychar)) { 337 | if (havesave) { 338 | addrange(save, save); 339 | if (havedash) 340 | addrange('-', '-'); 341 | } 342 | switch (g.yychar) { 343 | case 'd': addranges_d(); break; 344 | case 's': addranges_s(); break; 345 | case 'w': addranges_w(); break; 346 | case 'D': addranges_D(); break; 347 | case 'S': addranges_S(); break; 348 | case 'W': addranges_W(); break; 349 | } 350 | havesave = havedash = 0; 351 | } else { 352 | if (quoted) { 353 | if (g.yychar == 'b') 354 | g.yychar = '\b'; 355 | else if (g.yychar == '0') 356 | g.yychar = 0; 357 | /* else identity escape */ 358 | } 359 | if (havesave) { 360 | if (havedash) { 361 | addrange(save, g.yychar); 362 | havesave = havedash = 0; 363 | } else { 364 | addrange(save, save); 365 | save = g.yychar; 366 | } 367 | } else { 368 | save = g.yychar; 369 | havesave = 1; 370 | } 371 | } 372 | 373 | quoted = nextrune(); 374 | } 375 | 376 | if (havesave) { 377 | addrange(save, save); 378 | if (havedash) 379 | addrange('-', '-'); 380 | } 381 | 382 | return type; 383 | } 384 | 385 | static int lex(void) 386 | { 387 | int quoted = nextrune(); 388 | if (quoted) { 389 | switch (g.yychar) { 390 | case 'b': return L_WORD; 391 | case 'B': return L_NWORD; 392 | case 'd': newcclass(); addranges_d(); return L_CCLASS; 393 | case 's': newcclass(); addranges_s(); return L_CCLASS; 394 | case 'w': newcclass(); addranges_w(); return L_CCLASS; 395 | case 'D': newcclass(); addranges_d(); return L_NCCLASS; 396 | case 'S': newcclass(); addranges_s(); return L_NCCLASS; 397 | case 'W': newcclass(); addranges_w(); return L_NCCLASS; 398 | case '0': g.yychar = 0; return L_CHAR; 399 | } 400 | if (g.yychar >= '0' && g.yychar <= '9') { 401 | g.yychar -= '0'; 402 | if (*g.source >= '0' && *g.source <= '9') 403 | g.yychar = g.yychar * 10 + *g.source++ - '0'; 404 | return L_REF; 405 | } 406 | return L_CHAR; 407 | } 408 | 409 | switch (g.yychar) { 410 | case 0: 411 | case '$': case ')': case '*': case '+': 412 | case '.': case '?': case '^': case '|': 413 | return g.yychar; 414 | } 415 | 416 | if (g.yychar == '{') 417 | return lexcount(); 418 | if (g.yychar == '[') 419 | return lexclass(); 420 | if (g.yychar == '(') { 421 | if (g.source[0] == '?') { 422 | if (g.source[1] == ':') { 423 | g.source += 2; 424 | return L_NC; 425 | } 426 | if (g.source[1] == '=') { 427 | g.source += 2; 428 | return L_PLA; 429 | } 430 | if (g.source[1] == '!') { 431 | g.source += 2; 432 | return L_NLA; 433 | } 434 | } 435 | return '('; 436 | } 437 | 438 | return L_CHAR; 439 | } 440 | 441 | /* Parse */ 442 | 443 | enum { 444 | P_CAT, P_ALT, P_REP, 445 | P_BOL, P_EOL, P_WORD, P_NWORD, 446 | P_PAR, P_PLA, P_NLA, 447 | P_ANY, P_CHAR, P_CCLASS, P_NCCLASS, 448 | P_REF 449 | }; 450 | 451 | struct Renode { 452 | unsigned char type; 453 | unsigned char ng, m, n; 454 | Rune c; 455 | Reclass *cc; 456 | Renode *x; 457 | Renode *y; 458 | }; 459 | 460 | static Renode *newnode(int type) 461 | { 462 | Renode *node = g.pend++; 463 | node->type = type; 464 | node->cc = NULL; 465 | node->c = 0; 466 | node->ng = 0; 467 | node->m = 0; 468 | node->n = 0; 469 | node->x = node->y = NULL; 470 | return node; 471 | } 472 | 473 | static int empty(Renode *node) 474 | { 475 | if (!node) return 1; 476 | switch (node->type) { 477 | default: return 1; 478 | case P_CAT: return empty(node->x) && empty(node->y); 479 | case P_ALT: return empty(node->x) || empty(node->y); 480 | case P_REP: return empty(node->x) || node->m == 0; 481 | case P_PAR: return empty(node->x); 482 | case P_REF: return empty(node->x); 483 | case P_ANY: case P_CHAR: case P_CCLASS: case P_NCCLASS: return 0; 484 | } 485 | } 486 | 487 | static Renode *newrep(Renode *atom, int ng, int min, int max) 488 | { 489 | Renode *rep = newnode(P_REP); 490 | if (max == REPINF && empty(atom)) 491 | die("infinite loop matching the empty string"); 492 | rep->ng = ng; 493 | rep->m = min; 494 | rep->n = max; 495 | rep->x = atom; 496 | return rep; 497 | } 498 | 499 | static void next(void) 500 | { 501 | g.lookahead = lex(); 502 | } 503 | 504 | static int accept(int t) 505 | { 506 | if (g.lookahead == t) { 507 | next(); 508 | return 1; 509 | } 510 | return 0; 511 | } 512 | 513 | static Renode *parsealt(void); 514 | 515 | static Renode *parseatom(void) 516 | { 517 | Renode *atom; 518 | if (g.lookahead == L_CHAR) { 519 | atom = newnode(P_CHAR); 520 | atom->c = g.yychar; 521 | next(); 522 | return atom; 523 | } 524 | if (g.lookahead == L_CCLASS) { 525 | atom = newnode(P_CCLASS); 526 | atom->cc = g.yycc; 527 | next(); 528 | return atom; 529 | } 530 | if (g.lookahead == L_NCCLASS) { 531 | atom = newnode(P_NCCLASS); 532 | atom->cc = g.yycc; 533 | next(); 534 | return atom; 535 | } 536 | if (g.lookahead == L_REF) { 537 | atom = newnode(P_REF); 538 | if (g.yychar == 0 || g.yychar > g.nsub || !g.sub[g.yychar]) 539 | die("invalid back-reference"); 540 | atom->n = g.yychar; 541 | atom->x = g.sub[g.yychar]; 542 | next(); 543 | return atom; 544 | } 545 | if (accept('.')) 546 | return newnode(P_ANY); 547 | if (accept('(')) { 548 | atom = newnode(P_PAR); 549 | if (g.nsub == MAXSUB) 550 | die("too many captures"); 551 | atom->n = g.nsub++; 552 | atom->x = parsealt(); 553 | g.sub[atom->n] = atom; 554 | if (!accept(')')) 555 | die("unmatched '('"); 556 | return atom; 557 | } 558 | if (accept(L_NC)) { 559 | atom = parsealt(); 560 | if (!accept(')')) 561 | die("unmatched '('"); 562 | return atom; 563 | } 564 | if (accept(L_PLA)) { 565 | atom = newnode(P_PLA); 566 | atom->x = parsealt(); 567 | if (!accept(')')) 568 | die("unmatched '('"); 569 | return atom; 570 | } 571 | if (accept(L_NLA)) { 572 | atom = newnode(P_NLA); 573 | atom->x = parsealt(); 574 | if (!accept(')')) 575 | die("unmatched '('"); 576 | return atom; 577 | } 578 | die("syntax error"); 579 | return NULL; 580 | } 581 | 582 | static Renode *parserep(void) 583 | { 584 | Renode *atom; 585 | 586 | if (accept('^')) return newnode(P_BOL); 587 | if (accept('$')) return newnode(P_EOL); 588 | if (accept(L_WORD)) return newnode(P_WORD); 589 | if (accept(L_NWORD)) return newnode(P_NWORD); 590 | 591 | atom = parseatom(); 592 | if (g.lookahead == L_COUNT) { 593 | int min = g.yymin, max = g.yymax; 594 | next(); 595 | if (max < min) 596 | die("invalid quantifier"); 597 | return newrep(atom, accept('?'), min, max); 598 | } 599 | if (accept('*')) return newrep(atom, accept('?'), 0, REPINF); 600 | if (accept('+')) return newrep(atom, accept('?'), 1, REPINF); 601 | if (accept('?')) return newrep(atom, accept('?'), 0, 1); 602 | return atom; 603 | } 604 | 605 | static Renode *parsecat(void) 606 | { 607 | Renode *cat, *head, **tail; 608 | if (g.lookahead && g.lookahead != '|' && g.lookahead != ')') { 609 | /* Build a right-leaning tree by splicing in new 'cat' at the tail. */ 610 | head = parserep(); 611 | tail = &head; 612 | while (g.lookahead && g.lookahead != '|' && g.lookahead != ')') { 613 | cat = newnode(P_CAT); 614 | cat->x = *tail; 615 | cat->y = parserep(); 616 | *tail = cat; 617 | tail = &cat->y; 618 | } 619 | return head; 620 | } 621 | return NULL; 622 | } 623 | 624 | static Renode *parsealt(void) 625 | { 626 | Renode *alt, *x; 627 | alt = parsecat(); 628 | while (accept('|')) { 629 | x = alt; 630 | alt = newnode(P_ALT); 631 | alt->x = x; 632 | alt->y = parsecat(); 633 | } 634 | return alt; 635 | } 636 | 637 | /* Compile */ 638 | 639 | enum { 640 | I_END, I_JUMP, I_SPLIT, I_PLA, I_NLA, 641 | I_ANYNL, I_ANY, I_CHAR, I_CCLASS, I_NCCLASS, I_REF, 642 | I_BOL, I_EOL, I_WORD, I_NWORD, 643 | I_LPAR, I_RPAR 644 | }; 645 | 646 | struct Reinst { 647 | unsigned char opcode; 648 | unsigned char n; 649 | Rune c; 650 | Reclass *cc; 651 | Reinst *x; 652 | Reinst *y; 653 | }; 654 | 655 | static unsigned int count(Renode *node) 656 | { 657 | unsigned int min, max, n; 658 | if (!node) return 0; 659 | switch (node->type) { 660 | default: return 1; 661 | case P_CAT: return count(node->x) + count(node->y); 662 | case P_ALT: return count(node->x) + count(node->y) + 2; 663 | case P_REP: 664 | min = node->m; 665 | max = node->n; 666 | if (min == max) n = count(node->x) * min; 667 | else if (max < REPINF) n = count(node->x) * max + (max - min); 668 | else n = count(node->x) * (min + 1) + 2; 669 | if (n > MAXPROG) die("program too large"); 670 | return n; 671 | case P_PAR: return count(node->x) + 2; 672 | case P_PLA: return count(node->x) + 2; 673 | case P_NLA: return count(node->x) + 2; 674 | } 675 | } 676 | 677 | static Reinst *emit(Reprog *prog, int opcode) 678 | { 679 | Reinst *inst = prog->end++; 680 | inst->opcode = opcode; 681 | inst->n = 0; 682 | inst->c = 0; 683 | inst->cc = NULL; 684 | inst->x = inst->y = NULL; 685 | return inst; 686 | } 687 | 688 | static void compile(Reprog *prog, Renode *node) 689 | { 690 | Reinst *inst, *split, *jump; 691 | unsigned int i; 692 | 693 | if (!node) 694 | return; 695 | 696 | loop: 697 | switch (node->type) { 698 | case P_CAT: 699 | compile(prog, node->x); 700 | node = node->y; 701 | goto loop; 702 | 703 | case P_ALT: 704 | split = emit(prog, I_SPLIT); 705 | compile(prog, node->x); 706 | jump = emit(prog, I_JUMP); 707 | compile(prog, node->y); 708 | split->x = split + 1; 709 | split->y = jump + 1; 710 | jump->x = prog->end; 711 | break; 712 | 713 | case P_REP: 714 | for (i = 0; i < node->m; ++i) { 715 | inst = prog->end; 716 | compile(prog, node->x); 717 | } 718 | if (node->m == node->n) 719 | break; 720 | if (node->n < REPINF) { 721 | for (i = node->m; i < node->n; ++i) { 722 | split = emit(prog, I_SPLIT); 723 | compile(prog, node->x); 724 | if (node->ng) { 725 | split->y = split + 1; 726 | split->x = prog->end; 727 | } else { 728 | split->x = split + 1; 729 | split->y = prog->end; 730 | } 731 | } 732 | } else if (node->m == 0) { 733 | split = emit(prog, I_SPLIT); 734 | compile(prog, node->x); 735 | jump = emit(prog, I_JUMP); 736 | if (node->ng) { 737 | split->y = split + 1; 738 | split->x = prog->end; 739 | } else { 740 | split->x = split + 1; 741 | split->y = prog->end; 742 | } 743 | jump->x = split; 744 | } else { 745 | split = emit(prog, I_SPLIT); 746 | if (node->ng) { 747 | split->y = inst; 748 | split->x = prog->end; 749 | } else { 750 | split->x = inst; 751 | split->y = prog->end; 752 | } 753 | } 754 | break; 755 | 756 | case P_BOL: emit(prog, I_BOL); break; 757 | case P_EOL: emit(prog, I_EOL); break; 758 | case P_WORD: emit(prog, I_WORD); break; 759 | case P_NWORD: emit(prog, I_NWORD); break; 760 | 761 | case P_PAR: 762 | inst = emit(prog, I_LPAR); 763 | inst->n = node->n; 764 | compile(prog, node->x); 765 | inst = emit(prog, I_RPAR); 766 | inst->n = node->n; 767 | break; 768 | case P_PLA: 769 | split = emit(prog, I_PLA); 770 | compile(prog, node->x); 771 | emit(prog, I_END); 772 | split->x = split + 1; 773 | split->y = prog->end; 774 | break; 775 | case P_NLA: 776 | split = emit(prog, I_NLA); 777 | compile(prog, node->x); 778 | emit(prog, I_END); 779 | split->x = split + 1; 780 | split->y = prog->end; 781 | break; 782 | 783 | case P_ANY: 784 | emit(prog, I_ANY); 785 | break; 786 | case P_CHAR: 787 | inst = emit(prog, I_CHAR); 788 | inst->c = (prog->flags & REG_ICASE) ? canon(node->c) : node->c; 789 | break; 790 | case P_CCLASS: 791 | inst = emit(prog, I_CCLASS); 792 | inst->cc = node->cc; 793 | break; 794 | case P_NCCLASS: 795 | inst = emit(prog, I_NCCLASS); 796 | inst->cc = node->cc; 797 | break; 798 | case P_REF: 799 | inst = emit(prog, I_REF); 800 | inst->n = node->n; 801 | break; 802 | } 803 | } 804 | 805 | #ifdef TEST 806 | static void dumpnode(Renode *node) 807 | { 808 | Rune *p; 809 | if (!node) { printf("Empty"); return; } 810 | switch (node->type) { 811 | case P_CAT: printf("Cat("); dumpnode(node->x); printf(", "); dumpnode(node->y); printf(")"); break; 812 | case P_ALT: printf("Alt("); dumpnode(node->x); printf(", "); dumpnode(node->y); printf(")"); break; 813 | case P_REP: 814 | printf(node->ng ? "NgRep(%d,%d," : "Rep(%d,%d,", node->m, node->n); 815 | dumpnode(node->x); 816 | printf(")"); 817 | break; 818 | case P_BOL: printf("Bol"); break; 819 | case P_EOL: printf("Eol"); break; 820 | case P_WORD: printf("Word"); break; 821 | case P_NWORD: printf("NotWord"); break; 822 | case P_PAR: printf("Par(%d,", node->n); dumpnode(node->x); printf(")"); break; 823 | case P_PLA: printf("PLA("); dumpnode(node->x); printf(")"); break; 824 | case P_NLA: printf("NLA("); dumpnode(node->x); printf(")"); break; 825 | case P_ANY: printf("Any"); break; 826 | case P_CHAR: printf("Char(%c)", node->c); break; 827 | case P_CCLASS: 828 | printf("Class("); 829 | for (p = node->cc->spans; p < node->cc->end; p += 2) printf("%02X-%02X,", p[0], p[1]); 830 | printf(")"); 831 | break; 832 | case P_NCCLASS: 833 | printf("NotClass("); 834 | for (p = node->cc->spans; p < node->cc->end; p += 2) printf("%02X-%02X,", p[0], p[1]); 835 | printf(")"); 836 | break; 837 | case P_REF: printf("Ref(%d)", node->n); break; 838 | } 839 | } 840 | 841 | static void dumpprog(Reprog *prog) 842 | { 843 | Reinst *inst; 844 | int i; 845 | for (i = 0, inst = prog->start; inst < prog->end; ++i, ++inst) { 846 | printf("% 5d: ", i); 847 | switch (inst->opcode) { 848 | case I_END: puts("end"); break; 849 | case I_JUMP: printf("jump %d\n", (int)(inst->x - prog->start)); break; 850 | case I_SPLIT: printf("split %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; 851 | case I_PLA: printf("pla %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; 852 | case I_NLA: printf("nla %d %d\n", (int)(inst->x - prog->start), (int)(inst->y - prog->start)); break; 853 | case I_ANY: puts("any"); break; 854 | case I_ANYNL: puts("anynl"); break; 855 | case I_CHAR: printf(inst->c >= 32 && inst->c < 127 ? "char '%c'\n" : "char U+%04X\n", inst->c); break; 856 | case I_CCLASS: puts("cclass"); break; 857 | case I_NCCLASS: puts("ncclass"); break; 858 | case I_REF: printf("ref %d\n", inst->n); break; 859 | case I_BOL: puts("bol"); break; 860 | case I_EOL: puts("eol"); break; 861 | case I_WORD: puts("word"); break; 862 | case I_NWORD: puts("nword"); break; 863 | case I_LPAR: printf("lpar %d\n", inst->n); break; 864 | case I_RPAR: printf("rpar %d\n", inst->n); break; 865 | } 866 | } 867 | } 868 | #endif 869 | 870 | Reprog *regcomp(const char *pattern, int cflags, const char **errorp) 871 | { 872 | Renode *node; 873 | Reinst *split, *jump; 874 | int i, n; 875 | 876 | g.pstart = NULL; 877 | g.prog = NULL; 878 | 879 | if (setjmp(g.kaboom)) { 880 | if (errorp) *errorp = g.error; 881 | free(g.pstart); 882 | free(g.prog); 883 | return NULL; 884 | } 885 | 886 | g.prog = malloc(sizeof (Reprog)); 887 | if (!g.prog) 888 | die("cannot allocate regular expression"); 889 | n = strlen(pattern) * 2; 890 | if (n > 0) { 891 | g.pstart = g.pend = malloc(sizeof (Renode) * n); 892 | if (!g.pstart) 893 | die("cannot allocate regular expression parse list"); 894 | } 895 | 896 | g.source = pattern; 897 | g.ncclass = 0; 898 | g.nsub = 1; 899 | for (i = 0; i < MAXSUB; ++i) 900 | g.sub[i] = 0; 901 | 902 | g.prog->flags = cflags; 903 | 904 | next(); 905 | node = parsealt(); 906 | if (g.lookahead == ')') 907 | die("unmatched ')'"); 908 | if (g.lookahead != 0) 909 | die("syntax error"); 910 | 911 | #ifdef TEST 912 | dumpnode(node); 913 | putchar('\n'); 914 | #endif 915 | 916 | n = 6 + count(node); 917 | if (n < 0 || n > MAXPROG) 918 | die("program too large"); 919 | 920 | g.prog->nsub = g.nsub; 921 | g.prog->start = g.prog->end = malloc(n * sizeof (Reinst)); 922 | 923 | split = emit(g.prog, I_SPLIT); 924 | split->x = split + 3; 925 | split->y = split + 1; 926 | emit(g.prog, I_ANYNL); 927 | jump = emit(g.prog, I_JUMP); 928 | jump->x = split; 929 | emit(g.prog, I_LPAR); 930 | compile(g.prog, node); 931 | emit(g.prog, I_RPAR); 932 | emit(g.prog, I_END); 933 | 934 | #ifdef TEST 935 | dumpprog(g.prog); 936 | #endif 937 | 938 | free(g.pstart); 939 | 940 | if (errorp) *errorp = NULL; 941 | return g.prog; 942 | } 943 | 944 | void regfree(Reprog *prog) 945 | { 946 | if (prog) { 947 | free(prog->start); 948 | free(prog); 949 | } 950 | } 951 | 952 | /* Match */ 953 | 954 | static int isnewline(int c) 955 | { 956 | return c == 0xA || c == 0xD || c == 0x2028 || c == 0x2029; 957 | } 958 | 959 | static int iswordchar(int c) 960 | { 961 | return c == '_' || 962 | (c >= 'a' && c <= 'z') || 963 | (c >= 'A' && c <= 'Z') || 964 | (c >= '0' && c <= '9'); 965 | } 966 | 967 | static int incclass(Reclass *cc, Rune c) 968 | { 969 | Rune *p; 970 | for (p = cc->spans; p < cc->end; p += 2) 971 | if (p[0] <= c && c <= p[1]) 972 | return 1; 973 | return 0; 974 | } 975 | 976 | static int incclasscanon(Reclass *cc, Rune c) 977 | { 978 | Rune *p, r; 979 | for (p = cc->spans; p < cc->end; p += 2) 980 | for (r = p[0]; r <= p[1]; ++r) 981 | if (c == canon(r)) 982 | return 1; 983 | return 0; 984 | } 985 | 986 | static int strncmpcanon(const char *a, const char *b, unsigned int n) 987 | { 988 | Rune ra, rb; 989 | int c; 990 | while (n--) { 991 | if (!*a) return -1; 992 | if (!*b) return 1; 993 | a += chartorune(&ra, a); 994 | b += chartorune(&rb, b); 995 | c = canon(ra) - canon(rb); 996 | if (c) 997 | return c; 998 | } 999 | return 0; 1000 | } 1001 | 1002 | static int match(Reinst *pc, const char *sp, const char *bol, int flags, Resub *out) 1003 | { 1004 | Resub scratch; 1005 | int i; 1006 | Rune c; 1007 | 1008 | for (;;) { 1009 | switch (pc->opcode) { 1010 | case I_END: 1011 | return 1; 1012 | case I_JUMP: 1013 | pc = pc->x; 1014 | break; 1015 | case I_SPLIT: 1016 | scratch = *out; 1017 | if (match(pc->x, sp, bol, flags, &scratch)) { 1018 | *out = scratch; 1019 | return 1; 1020 | } 1021 | pc = pc->y; 1022 | break; 1023 | 1024 | case I_PLA: 1025 | if (!match(pc->x, sp, bol, flags, out)) 1026 | return 0; 1027 | pc = pc->y; 1028 | break; 1029 | case I_NLA: 1030 | scratch = *out; 1031 | if (match(pc->x, sp, bol, flags, &scratch)) 1032 | return 0; 1033 | pc = pc->y; 1034 | break; 1035 | 1036 | case I_ANYNL: 1037 | sp += chartorune(&c, sp); 1038 | if (c == 0) 1039 | return 0; 1040 | pc = pc + 1; 1041 | break; 1042 | case I_ANY: 1043 | sp += chartorune(&c, sp); 1044 | if (c == 0) 1045 | return 0; 1046 | if (isnewline(c)) 1047 | return 0; 1048 | pc = pc + 1; 1049 | break; 1050 | case I_CHAR: 1051 | sp += chartorune(&c, sp); 1052 | if (c == 0) 1053 | return 0; 1054 | if (flags & REG_ICASE) 1055 | c = canon(c); 1056 | if (c != pc->c) 1057 | return 0; 1058 | pc = pc + 1; 1059 | break; 1060 | case I_CCLASS: 1061 | sp += chartorune(&c, sp); 1062 | if (c == 0) 1063 | return 0; 1064 | if (flags & REG_ICASE) { 1065 | if (!incclasscanon(pc->cc, canon(c))) 1066 | return 0; 1067 | } else { 1068 | if (!incclass(pc->cc, c)) 1069 | return 0; 1070 | } 1071 | pc = pc + 1; 1072 | break; 1073 | case I_NCCLASS: 1074 | sp += chartorune(&c, sp); 1075 | if (c == 0) 1076 | return 0; 1077 | if (flags & REG_ICASE) { 1078 | if (incclasscanon(pc->cc, canon(c))) 1079 | return 0; 1080 | } else { 1081 | if (incclass(pc->cc, c)) 1082 | return 0; 1083 | } 1084 | pc = pc + 1; 1085 | break; 1086 | case I_REF: 1087 | i = out->sub[pc->n].ep - out->sub[pc->n].sp; 1088 | if (flags & REG_ICASE) { 1089 | if (strncmpcanon(sp, out->sub[pc->n].sp, i)) 1090 | return 0; 1091 | } else { 1092 | if (strncmp(sp, out->sub[pc->n].sp, i)) 1093 | return 0; 1094 | } 1095 | if (i > 0) 1096 | sp += i; 1097 | pc = pc + 1; 1098 | break; 1099 | 1100 | case I_BOL: 1101 | if (sp == bol && !(flags & REG_NOTBOL)) { 1102 | pc = pc + 1; 1103 | break; 1104 | } 1105 | if (flags & REG_NEWLINE) { 1106 | if (sp > bol && isnewline(sp[-1])) { 1107 | pc = pc + 1; 1108 | break; 1109 | } 1110 | } 1111 | return 0; 1112 | case I_EOL: 1113 | if (*sp == 0) { 1114 | pc = pc + 1; 1115 | break; 1116 | } 1117 | if (flags & REG_NEWLINE) { 1118 | if (isnewline(*sp)) { 1119 | pc = pc + 1; 1120 | break; 1121 | } 1122 | } 1123 | return 0; 1124 | case I_WORD: 1125 | i = sp > bol && iswordchar(sp[-1]); 1126 | i ^= iswordchar(sp[0]); 1127 | if (!i) 1128 | return 0; 1129 | pc = pc + 1; 1130 | break; 1131 | case I_NWORD: 1132 | i = sp > bol && iswordchar(sp[-1]); 1133 | i ^= iswordchar(sp[0]); 1134 | if (i) 1135 | return 0; 1136 | pc = pc + 1; 1137 | break; 1138 | 1139 | case I_LPAR: 1140 | out->sub[pc->n].sp = sp; 1141 | pc = pc + 1; 1142 | break; 1143 | case I_RPAR: 1144 | out->sub[pc->n].ep = sp; 1145 | pc = pc + 1; 1146 | break; 1147 | default: 1148 | return 0; 1149 | } 1150 | } 1151 | } 1152 | 1153 | int regexec(Reprog *prog, const char *sp, Resub *sub, int eflags) 1154 | { 1155 | Resub scratch; 1156 | int i; 1157 | 1158 | if (!sub) 1159 | sub = &scratch; 1160 | 1161 | sub->nsub = prog->nsub; 1162 | for (i = 0; i < MAXSUB; ++i) 1163 | sub->sub[i].sp = sub->sub[i].ep = NULL; 1164 | 1165 | return !match(prog->start, sp, sp, prog->flags | eflags, sub); 1166 | } 1167 | 1168 | #ifdef TEST 1169 | int main(int argc, char **argv) 1170 | { 1171 | const char *error; 1172 | const char *s; 1173 | Reprog *p; 1174 | Resub m; 1175 | unsigned int i; 1176 | 1177 | if (argc > 1) { 1178 | p = regcomp(argv[1], 0, &error); 1179 | if (!p) { 1180 | fprintf(stderr, "regcomp: %s\n", error); 1181 | return 1; 1182 | } 1183 | 1184 | if (argc > 2) { 1185 | s = argv[2]; 1186 | printf("nsub = %d\n", p->nsub); 1187 | if (!regexec(p, s, &m, 0)) { 1188 | for (i = 0; i < m.nsub; ++i) { 1189 | int n = m.sub[i].ep - m.sub[i].sp; 1190 | if (n > 0) 1191 | printf("match %d: s=%d e=%d n=%d '%.*s'\n", i, (int)(m.sub[i].sp - s), (int)(m.sub[i].ep - s), n, n, m.sub[i].sp); 1192 | else 1193 | printf("match %d: n=0 ''\n", i); 1194 | } 1195 | } else { 1196 | printf("no match\n"); 1197 | } 1198 | } 1199 | } 1200 | 1201 | return 0; 1202 | } 1203 | #endif 1204 | 1205 | --------------------------------------------------------------------------------