├── 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 | 
4 | 
5 | 
6 | [](https://github.com/yui0/aplay-/releases)
7 | [](LICENSE)
8 |
9 | 🎧 **Enjoy BitPerfect audio playback with simplicity and precision!**
10 |
11 | 
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)
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 |
--------------------------------------------------------------------------------