From c91800155174803a26a306f448cdc829792f9aaf Mon Sep 17 00:00:00 2001 From: xufulong Date: Mon, 27 Sep 2021 21:22:26 +0800 Subject: [PATCH] add library of sox --- app/src/main/cpp/sox/8svx.c | 342 ++ app/src/main/cpp/sox/Makefile.am | 184 + app/src/main/cpp/sox/adpcm.c | 367 ++ app/src/main/cpp/sox/adpcm.h | 79 + app/src/main/cpp/sox/adpcms.c | 322 ++ app/src/main/cpp/sox/adpcms.h | 55 + app/src/main/cpp/sox/aifc-fmt.c | 36 + app/src/main/cpp/sox/aiff-fmt.c | 33 + app/src/main/cpp/sox/aiff.c | 1151 +++++++ app/src/main/cpp/sox/aiff.h | 22 + app/src/main/cpp/sox/al-fmt.c | 21 + app/src/main/cpp/sox/alsa.c | 379 ++ app/src/main/cpp/sox/amr-nb.c | 90 + app/src/main/cpp/sox/amr-wb.c | 115 + app/src/main/cpp/sox/amr.h | 335 ++ app/src/main/cpp/sox/ao.c | 134 + app/src/main/cpp/sox/au.c | 237 ++ app/src/main/cpp/sox/avr.c | 287 ++ app/src/main/cpp/sox/band.h | 47 + app/src/main/cpp/sox/bend.c | 325 ++ app/src/main/cpp/sox/biquad.c | 178 + app/src/main/cpp/sox/biquad.h | 78 + app/src/main/cpp/sox/biquads.c | 416 +++ .../cpp/sox/bit-rot/CoreAudio/CoreAudio.h | 273 ++ app/src/main/cpp/sox/bit-rot/mmreg.h | 0 app/src/main/cpp/sox/bit-rot/mmsystem.h | 89 + app/src/main/cpp/sox/bit-rot/sndio.h | 160 + app/src/main/cpp/sox/bit-rot/sys/audioio.h | 289 ++ app/src/main/cpp/sox/bit-rot/windows.h | 34 + app/src/main/cpp/sox/caf.c | 35 + app/src/main/cpp/sox/cdr.c | 49 + app/src/main/cpp/sox/chorus.c | 351 ++ app/src/main/cpp/sox/compand.c | 293 ++ app/src/main/cpp/sox/compandt.c | 229 ++ app/src/main/cpp/sox/compandt.h | 52 + app/src/main/cpp/sox/contrast.c | 49 + app/src/main/cpp/sox/coreaudio.c | 418 +++ app/src/main/cpp/sox/cvsd-fmt.c | 114 + app/src/main/cpp/sox/cvsd.c | 680 ++++ app/src/main/cpp/sox/cvsd.h | 68 + app/src/main/cpp/sox/cvsdfilt.h | 112 + app/src/main/cpp/sox/dat.c | 162 + app/src/main/cpp/sox/dcshift.c | 165 + app/src/main/cpp/sox/deemph.plt | 118 + app/src/main/cpp/sox/delay.c | 163 + app/src/main/cpp/sox/dft_filter.c | 137 + app/src/main/cpp/sox/dft_filter.h | 16 + app/src/main/cpp/sox/dither.c | 436 +++ app/src/main/cpp/sox/dither.h | 63 + app/src/main/cpp/sox/divide.c | 73 + app/src/main/cpp/sox/downsample.c | 85 + app/src/main/cpp/sox/dvms-fmt.c | 32 + app/src/main/cpp/sox/earwax.c | 97 + app/src/main/cpp/sox/echo.c | 266 ++ app/src/main/cpp/sox/echos.c | 278 ++ app/src/main/cpp/sox/effects.c | 669 ++++ app/src/main/cpp/sox/effects.h | 90 + app/src/main/cpp/sox/effects_i.c | 483 +++ app/src/main/cpp/sox/effects_i_dsp.c | 645 ++++ app/src/main/cpp/sox/example0.c | 97 + app/src/main/cpp/sox/example1.c | 167 + app/src/main/cpp/sox/example2.c | 118 + app/src/main/cpp/sox/example3.c | 113 + app/src/main/cpp/sox/example4.c | 98 + app/src/main/cpp/sox/example5.c | 83 + app/src/main/cpp/sox/example6.c | 128 + app/src/main/cpp/sox/f4-fmt.c | 21 + app/src/main/cpp/sox/f8-fmt.c | 21 + app/src/main/cpp/sox/fade.c | 399 +++ app/src/main/cpp/sox/fap.c | 31 + app/src/main/cpp/sox/fft4g.c | 1362 ++++++++ app/src/main/cpp/sox/fft4g.h | 37 + app/src/main/cpp/sox/fifo.h | 119 + app/src/main/cpp/sox/fir.c | 105 + app/src/main/cpp/sox/firfit.c | 145 + app/src/main/cpp/sox/flac.c | 606 ++++ app/src/main/cpp/sox/flanger.c | 275 ++ app/src/main/cpp/sox/formats.c | 1351 ++++++++ app/src/main/cpp/sox/formats.h | 130 + app/src/main/cpp/sox/formats_i.c | 545 +++ app/src/main/cpp/sox/g711.c | 2421 +++++++++++++ app/src/main/cpp/sox/g711.h | 21 + app/src/main/cpp/sox/g721.c | 167 + app/src/main/cpp/sox/g723_24.c | 151 + app/src/main/cpp/sox/g723_40.c | 171 + app/src/main/cpp/sox/g72x.c | 575 ++++ app/src/main/cpp/sox/g72x.h | 157 + app/src/main/cpp/sox/gain.c | 276 ++ app/src/main/cpp/sox/getopt.c | 349 ++ app/src/main/cpp/sox/gsm.c | 247 ++ app/src/main/cpp/sox/gsrt.c | 207 ++ app/src/main/cpp/sox/hcom.c | 502 +++ app/src/main/cpp/sox/hilbert.c | 102 + app/src/main/cpp/sox/htk.c | 80 + app/src/main/cpp/sox/id3.c | 227 ++ app/src/main/cpp/sox/id3.h | 25 + app/src/main/cpp/sox/ima-fmt.c | 33 + app/src/main/cpp/sox/ima_rw.c | 365 ++ app/src/main/cpp/sox/ima_rw.h | 84 + app/src/main/cpp/sox/input.c | 58 + app/src/main/cpp/sox/la-fmt.c | 21 + app/src/main/cpp/sox/ladspa.c | 492 +++ app/src/main/cpp/sox/ladspa.h | 603 ++++ app/src/main/cpp/sox/libsox.c | 224 ++ app/src/main/cpp/sox/libsox.sym | 96 + app/src/main/cpp/sox/libsox_i.c | 116 + app/src/main/cpp/sox/loudness.c | 129 + app/src/main/cpp/sox/lpc10.c | 225 ++ app/src/main/cpp/sox/lu-fmt.c | 21 + app/src/main/cpp/sox/mat4.c | 33 + app/src/main/cpp/sox/mat5.c | 33 + app/src/main/cpp/sox/maud.c | 344 ++ app/src/main/cpp/sox/mcompand.c | 524 +++ app/src/main/cpp/sox/mcompand_xover.h | 106 + app/src/main/cpp/sox/mp3-util.h | 171 + app/src/main/cpp/sox/mp3.c | 1299 +++++++ app/src/main/cpp/sox/noiseprof.c | 223 ++ app/src/main/cpp/sox/noisered.c | 357 ++ app/src/main/cpp/sox/noisered.h | 26 + app/src/main/cpp/sox/nulfile.c | 58 + app/src/main/cpp/sox/optional-fmts.am | 297 ++ app/src/main/cpp/sox/opus.c | 235 ++ app/src/main/cpp/sox/oss.c | 446 +++ app/src/main/cpp/sox/output.c | 59 + app/src/main/cpp/sox/overdrive.c | 71 + app/src/main/cpp/sox/pad.c | 180 + app/src/main/cpp/sox/paf.c | 31 + app/src/main/cpp/sox/phaser.c | 147 + app/src/main/cpp/sox/prc.c | 449 +++ app/src/main/cpp/sox/pulseaudio.c | 172 + app/src/main/cpp/sox/pvf.c | 30 + app/src/main/cpp/sox/rate.c | 712 ++++ app/src/main/cpp/sox/rate_filters.h | 187 + app/src/main/cpp/sox/rate_half_fir.h | 39 + app/src/main/cpp/sox/rate_poly_fir.h | 91 + app/src/main/cpp/sox/rate_poly_fir0.h | 48 + app/src/main/cpp/sox/raw-fmt.c | 61 + app/src/main/cpp/sox/raw.c | 196 ++ app/src/main/cpp/sox/raw.h | 54 + app/src/main/cpp/sox/remix.c | 284 ++ app/src/main/cpp/sox/repeat.c | 114 + app/src/main/cpp/sox/reverb.c | 277 ++ app/src/main/cpp/sox/reverse.c | 86 + app/src/main/cpp/sox/s1-fmt.c | 21 + app/src/main/cpp/sox/s2-fmt.c | 21 + app/src/main/cpp/sox/s3-fmt.c | 21 + app/src/main/cpp/sox/s4-fmt.c | 21 + app/src/main/cpp/sox/sd2.c | 30 + app/src/main/cpp/sox/sf.c | 154 + app/src/main/cpp/sox/silence.c | 690 ++++ app/src/main/cpp/sox/sinc.c | 157 + app/src/main/cpp/sox/skeleff.c | 141 + app/src/main/cpp/sox/skelform.c | 218 ++ app/src/main/cpp/sox/smp.c | 418 +++ app/src/main/cpp/sox/sndfile.c | 532 +++ app/src/main/cpp/sox/sndio.c | 246 ++ app/src/main/cpp/sox/sounder.c | 55 + app/src/main/cpp/sox/soundtool.c | 78 + app/src/main/cpp/sox/sox-fmt.c | 108 + app/src/main/cpp/sox/sox.c | 3036 +++++++++++++++++ app/src/main/cpp/sox/sox.h | 2603 ++++++++++++++ app/src/main/cpp/sox/sox_i.h | 416 +++ app/src/main/cpp/sox/sox_sample_test.c | 190 ++ app/src/main/cpp/sox/soxomp.h | 47 + app/src/main/cpp/sox/spectrogram.c | 1009 ++++++ app/src/main/cpp/sox/speed.c | 73 + app/src/main/cpp/sox/speexdsp.c | 349 ++ app/src/main/cpp/sox/sphere.c | 199 ++ app/src/main/cpp/sox/splice.c | 302 ++ app/src/main/cpp/sox/stat.c | 336 ++ app/src/main/cpp/sox/stats.c | 298 ++ app/src/main/cpp/sox/stretch.c | 326 ++ app/src/main/cpp/sox/sunaudio.c | 520 +++ app/src/main/cpp/sox/swap.c | 62 + app/src/main/cpp/sox/synth.c | 677 ++++ app/src/main/cpp/sox/tempo.c | 360 ++ app/src/main/cpp/sox/tremolo.c | 47 + app/src/main/cpp/sox/trim.c | 216 ++ app/src/main/cpp/sox/tx16w.c | 382 +++ app/src/main/cpp/sox/u1-fmt.c | 21 + app/src/main/cpp/sox/u2-fmt.c | 21 + app/src/main/cpp/sox/u3-fmt.c | 21 + app/src/main/cpp/sox/u4-fmt.c | 21 + app/src/main/cpp/sox/ul-fmt.c | 21 + app/src/main/cpp/sox/upsample.c | 64 + app/src/main/cpp/sox/util.c | 304 ++ app/src/main/cpp/sox/util.h | 184 + app/src/main/cpp/sox/vad.c | 329 ++ app/src/main/cpp/sox/voc.c | 815 +++++ app/src/main/cpp/sox/vol.c | 184 + app/src/main/cpp/sox/vorbis.c | 429 +++ app/src/main/cpp/sox/vox-fmt.c | 33 + app/src/main/cpp/sox/vox.c | 47 + app/src/main/cpp/sox/vox.h | 23 + app/src/main/cpp/sox/w64.c | 39 + app/src/main/cpp/sox/wav.c | 1650 +++++++++ app/src/main/cpp/sox/waveaudio.c | 534 +++ app/src/main/cpp/sox/wavpack.c | 206 ++ app/src/main/cpp/sox/win32/glob.c | 170 + app/src/main/cpp/sox/win32/glob.h | 49 + app/src/main/cpp/sox/wve.c | 63 + app/src/main/cpp/sox/xa.c | 297 ++ app/src/main/cpp/sox/xi.c | 30 + app/src/main/cpp/sox/xmalloc.c | 73 + app/src/main/cpp/sox/xmalloc.h | 36 + 205 files changed, 54065 insertions(+) create mode 100644 app/src/main/cpp/sox/8svx.c create mode 100755 app/src/main/cpp/sox/Makefile.am create mode 100644 app/src/main/cpp/sox/adpcm.c create mode 100644 app/src/main/cpp/sox/adpcm.h create mode 100644 app/src/main/cpp/sox/adpcms.c create mode 100644 app/src/main/cpp/sox/adpcms.h create mode 100644 app/src/main/cpp/sox/aifc-fmt.c create mode 100644 app/src/main/cpp/sox/aiff-fmt.c create mode 100644 app/src/main/cpp/sox/aiff.c create mode 100644 app/src/main/cpp/sox/aiff.h create mode 100644 app/src/main/cpp/sox/al-fmt.c create mode 100644 app/src/main/cpp/sox/alsa.c create mode 100644 app/src/main/cpp/sox/amr-nb.c create mode 100644 app/src/main/cpp/sox/amr-wb.c create mode 100644 app/src/main/cpp/sox/amr.h create mode 100644 app/src/main/cpp/sox/ao.c create mode 100644 app/src/main/cpp/sox/au.c create mode 100644 app/src/main/cpp/sox/avr.c create mode 100644 app/src/main/cpp/sox/band.h create mode 100644 app/src/main/cpp/sox/bend.c create mode 100644 app/src/main/cpp/sox/biquad.c create mode 100644 app/src/main/cpp/sox/biquad.h create mode 100644 app/src/main/cpp/sox/biquads.c create mode 100644 app/src/main/cpp/sox/bit-rot/CoreAudio/CoreAudio.h create mode 100755 app/src/main/cpp/sox/bit-rot/mmreg.h create mode 100644 app/src/main/cpp/sox/bit-rot/mmsystem.h create mode 100644 app/src/main/cpp/sox/bit-rot/sndio.h create mode 100644 app/src/main/cpp/sox/bit-rot/sys/audioio.h create mode 100644 app/src/main/cpp/sox/bit-rot/windows.h create mode 100644 app/src/main/cpp/sox/caf.c create mode 100644 app/src/main/cpp/sox/cdr.c create mode 100644 app/src/main/cpp/sox/chorus.c create mode 100644 app/src/main/cpp/sox/compand.c create mode 100644 app/src/main/cpp/sox/compandt.c create mode 100644 app/src/main/cpp/sox/compandt.h create mode 100644 app/src/main/cpp/sox/contrast.c create mode 100644 app/src/main/cpp/sox/coreaudio.c create mode 100644 app/src/main/cpp/sox/cvsd-fmt.c create mode 100644 app/src/main/cpp/sox/cvsd.c create mode 100644 app/src/main/cpp/sox/cvsd.h create mode 100644 app/src/main/cpp/sox/cvsdfilt.h create mode 100644 app/src/main/cpp/sox/dat.c create mode 100644 app/src/main/cpp/sox/dcshift.c create mode 100644 app/src/main/cpp/sox/deemph.plt create mode 100644 app/src/main/cpp/sox/delay.c create mode 100644 app/src/main/cpp/sox/dft_filter.c create mode 100644 app/src/main/cpp/sox/dft_filter.h create mode 100644 app/src/main/cpp/sox/dither.c create mode 100644 app/src/main/cpp/sox/dither.h create mode 100644 app/src/main/cpp/sox/divide.c create mode 100644 app/src/main/cpp/sox/downsample.c create mode 100644 app/src/main/cpp/sox/dvms-fmt.c create mode 100644 app/src/main/cpp/sox/earwax.c create mode 100644 app/src/main/cpp/sox/echo.c create mode 100644 app/src/main/cpp/sox/echos.c create mode 100644 app/src/main/cpp/sox/effects.c create mode 100644 app/src/main/cpp/sox/effects.h create mode 100644 app/src/main/cpp/sox/effects_i.c create mode 100644 app/src/main/cpp/sox/effects_i_dsp.c create mode 100644 app/src/main/cpp/sox/example0.c create mode 100644 app/src/main/cpp/sox/example1.c create mode 100644 app/src/main/cpp/sox/example2.c create mode 100644 app/src/main/cpp/sox/example3.c create mode 100644 app/src/main/cpp/sox/example4.c create mode 100644 app/src/main/cpp/sox/example5.c create mode 100644 app/src/main/cpp/sox/example6.c create mode 100644 app/src/main/cpp/sox/f4-fmt.c create mode 100644 app/src/main/cpp/sox/f8-fmt.c create mode 100644 app/src/main/cpp/sox/fade.c create mode 100644 app/src/main/cpp/sox/fap.c create mode 100644 app/src/main/cpp/sox/fft4g.c create mode 100644 app/src/main/cpp/sox/fft4g.h create mode 100644 app/src/main/cpp/sox/fifo.h create mode 100644 app/src/main/cpp/sox/fir.c create mode 100644 app/src/main/cpp/sox/firfit.c create mode 100644 app/src/main/cpp/sox/flac.c create mode 100644 app/src/main/cpp/sox/flanger.c create mode 100644 app/src/main/cpp/sox/formats.c create mode 100644 app/src/main/cpp/sox/formats.h create mode 100644 app/src/main/cpp/sox/formats_i.c create mode 100644 app/src/main/cpp/sox/g711.c create mode 100644 app/src/main/cpp/sox/g711.h create mode 100644 app/src/main/cpp/sox/g721.c create mode 100644 app/src/main/cpp/sox/g723_24.c create mode 100644 app/src/main/cpp/sox/g723_40.c create mode 100644 app/src/main/cpp/sox/g72x.c create mode 100644 app/src/main/cpp/sox/g72x.h create mode 100644 app/src/main/cpp/sox/gain.c create mode 100644 app/src/main/cpp/sox/getopt.c create mode 100644 app/src/main/cpp/sox/gsm.c create mode 100644 app/src/main/cpp/sox/gsrt.c create mode 100644 app/src/main/cpp/sox/hcom.c create mode 100644 app/src/main/cpp/sox/hilbert.c create mode 100644 app/src/main/cpp/sox/htk.c create mode 100644 app/src/main/cpp/sox/id3.c create mode 100644 app/src/main/cpp/sox/id3.h create mode 100644 app/src/main/cpp/sox/ima-fmt.c create mode 100644 app/src/main/cpp/sox/ima_rw.c create mode 100644 app/src/main/cpp/sox/ima_rw.h create mode 100644 app/src/main/cpp/sox/input.c create mode 100644 app/src/main/cpp/sox/la-fmt.c create mode 100644 app/src/main/cpp/sox/ladspa.c create mode 100644 app/src/main/cpp/sox/ladspa.h create mode 100644 app/src/main/cpp/sox/libsox.c create mode 100644 app/src/main/cpp/sox/libsox.sym create mode 100644 app/src/main/cpp/sox/libsox_i.c create mode 100644 app/src/main/cpp/sox/loudness.c create mode 100644 app/src/main/cpp/sox/lpc10.c create mode 100644 app/src/main/cpp/sox/lu-fmt.c create mode 100644 app/src/main/cpp/sox/mat4.c create mode 100644 app/src/main/cpp/sox/mat5.c create mode 100644 app/src/main/cpp/sox/maud.c create mode 100644 app/src/main/cpp/sox/mcompand.c create mode 100644 app/src/main/cpp/sox/mcompand_xover.h create mode 100644 app/src/main/cpp/sox/mp3-util.h create mode 100644 app/src/main/cpp/sox/mp3.c create mode 100644 app/src/main/cpp/sox/noiseprof.c create mode 100644 app/src/main/cpp/sox/noisered.c create mode 100644 app/src/main/cpp/sox/noisered.h create mode 100644 app/src/main/cpp/sox/nulfile.c create mode 100644 app/src/main/cpp/sox/optional-fmts.am create mode 100644 app/src/main/cpp/sox/opus.c create mode 100644 app/src/main/cpp/sox/oss.c create mode 100644 app/src/main/cpp/sox/output.c create mode 100644 app/src/main/cpp/sox/overdrive.c create mode 100644 app/src/main/cpp/sox/pad.c create mode 100644 app/src/main/cpp/sox/paf.c create mode 100644 app/src/main/cpp/sox/phaser.c create mode 100644 app/src/main/cpp/sox/prc.c create mode 100644 app/src/main/cpp/sox/pulseaudio.c create mode 100644 app/src/main/cpp/sox/pvf.c create mode 100644 app/src/main/cpp/sox/rate.c create mode 100644 app/src/main/cpp/sox/rate_filters.h create mode 100644 app/src/main/cpp/sox/rate_half_fir.h create mode 100644 app/src/main/cpp/sox/rate_poly_fir.h create mode 100644 app/src/main/cpp/sox/rate_poly_fir0.h create mode 100644 app/src/main/cpp/sox/raw-fmt.c create mode 100644 app/src/main/cpp/sox/raw.c create mode 100644 app/src/main/cpp/sox/raw.h create mode 100644 app/src/main/cpp/sox/remix.c create mode 100644 app/src/main/cpp/sox/repeat.c create mode 100644 app/src/main/cpp/sox/reverb.c create mode 100644 app/src/main/cpp/sox/reverse.c create mode 100644 app/src/main/cpp/sox/s1-fmt.c create mode 100644 app/src/main/cpp/sox/s2-fmt.c create mode 100644 app/src/main/cpp/sox/s3-fmt.c create mode 100644 app/src/main/cpp/sox/s4-fmt.c create mode 100644 app/src/main/cpp/sox/sd2.c create mode 100644 app/src/main/cpp/sox/sf.c create mode 100644 app/src/main/cpp/sox/silence.c create mode 100644 app/src/main/cpp/sox/sinc.c create mode 100644 app/src/main/cpp/sox/skeleff.c create mode 100644 app/src/main/cpp/sox/skelform.c create mode 100644 app/src/main/cpp/sox/smp.c create mode 100644 app/src/main/cpp/sox/sndfile.c create mode 100644 app/src/main/cpp/sox/sndio.c create mode 100644 app/src/main/cpp/sox/sounder.c create mode 100644 app/src/main/cpp/sox/soundtool.c create mode 100644 app/src/main/cpp/sox/sox-fmt.c create mode 100644 app/src/main/cpp/sox/sox.c create mode 100644 app/src/main/cpp/sox/sox.h create mode 100644 app/src/main/cpp/sox/sox_i.h create mode 100644 app/src/main/cpp/sox/sox_sample_test.c create mode 100644 app/src/main/cpp/sox/soxomp.h create mode 100644 app/src/main/cpp/sox/spectrogram.c create mode 100644 app/src/main/cpp/sox/speed.c create mode 100644 app/src/main/cpp/sox/speexdsp.c create mode 100644 app/src/main/cpp/sox/sphere.c create mode 100644 app/src/main/cpp/sox/splice.c create mode 100644 app/src/main/cpp/sox/stat.c create mode 100644 app/src/main/cpp/sox/stats.c create mode 100644 app/src/main/cpp/sox/stretch.c create mode 100644 app/src/main/cpp/sox/sunaudio.c create mode 100644 app/src/main/cpp/sox/swap.c create mode 100644 app/src/main/cpp/sox/synth.c create mode 100644 app/src/main/cpp/sox/tempo.c create mode 100644 app/src/main/cpp/sox/tremolo.c create mode 100644 app/src/main/cpp/sox/trim.c create mode 100644 app/src/main/cpp/sox/tx16w.c create mode 100644 app/src/main/cpp/sox/u1-fmt.c create mode 100644 app/src/main/cpp/sox/u2-fmt.c create mode 100644 app/src/main/cpp/sox/u3-fmt.c create mode 100644 app/src/main/cpp/sox/u4-fmt.c create mode 100644 app/src/main/cpp/sox/ul-fmt.c create mode 100644 app/src/main/cpp/sox/upsample.c create mode 100644 app/src/main/cpp/sox/util.c create mode 100644 app/src/main/cpp/sox/util.h create mode 100644 app/src/main/cpp/sox/vad.c create mode 100644 app/src/main/cpp/sox/voc.c create mode 100644 app/src/main/cpp/sox/vol.c create mode 100644 app/src/main/cpp/sox/vorbis.c create mode 100644 app/src/main/cpp/sox/vox-fmt.c create mode 100644 app/src/main/cpp/sox/vox.c create mode 100644 app/src/main/cpp/sox/vox.h create mode 100644 app/src/main/cpp/sox/w64.c create mode 100644 app/src/main/cpp/sox/wav.c create mode 100644 app/src/main/cpp/sox/waveaudio.c create mode 100644 app/src/main/cpp/sox/wavpack.c create mode 100644 app/src/main/cpp/sox/win32/glob.c create mode 100644 app/src/main/cpp/sox/win32/glob.h create mode 100644 app/src/main/cpp/sox/wve.c create mode 100644 app/src/main/cpp/sox/xa.c create mode 100644 app/src/main/cpp/sox/xi.c create mode 100644 app/src/main/cpp/sox/xmalloc.c create mode 100644 app/src/main/cpp/sox/xmalloc.h diff --git a/app/src/main/cpp/sox/8svx.c b/app/src/main/cpp/sox/8svx.c new file mode 100644 index 0000000..3b7af8c --- /dev/null +++ b/app/src/main/cpp/sox/8svx.c @@ -0,0 +1,342 @@ +/* Amiga 8SVX format handler: W V Neisius, February 1992 */ + +#include "sox_i.h" + +#include +#include +#include +#include + +#define BUFLEN 512 + +/* Private data used by writer */ +typedef struct{ + uint32_t nsamples; + uint32_t left; + off_t ch0_pos; + sox_uint8_t buf[4][BUFLEN]; + FILE* tmp[4]; +} priv_t; + +static void svxwriteheader(sox_format_t *, size_t); + +/*======================================================================*/ +/* 8SVXSTARTREAD */ +/*======================================================================*/ + +static int startread(sox_format_t * ft) +{ + priv_t * p = (priv_t * ) ft->priv; + + char buf[12]; + char *chunk_buf; + + uint32_t totalsize; + uint32_t chunksize; + + uint32_t channels; + unsigned short rate; + + if (! ft->seekable) + { + lsx_fail_errno(ft,SOX_EINVAL,"8svx input file must be a file, not a pipe"); + return (SOX_EOF); + } + rate = 0; + channels = 1; + + /* read FORM chunk */ + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) + { + lsx_fail_errno(ft, SOX_EHDR, "Header did not begin with magic word `FORM'"); + return(SOX_EOF); + } + lsx_readdw(ft, &totalsize); + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "8SVX", (size_t)4) != 0) + { + lsx_fail_errno(ft, SOX_EHDR, "'FORM' chunk does not specify `8SVX' as type"); + return(SOX_EOF); + } + + /* read chunks until 'BODY' (or end) */ + while (lsx_reads(ft, buf, (size_t)4) == SOX_SUCCESS && strncmp(buf,"BODY",(size_t)4) != 0) { + if (strncmp(buf,"VHDR",(size_t)4) == 0) { + lsx_readdw(ft, &chunksize); + if (chunksize != 20) + { + lsx_fail_errno(ft, SOX_EHDR, "VHDR chunk has bad size"); + return(SOX_EOF); + } + lsx_seeki(ft,(off_t)12,SEEK_CUR); + lsx_readw(ft, &rate); + lsx_seeki(ft,(off_t)1,SEEK_CUR); + lsx_readbuf(ft, buf,(size_t)1); + if (buf[0] != 0) + { + lsx_fail_errno(ft, SOX_EFMT, "Unsupported data compression"); + return(SOX_EOF); + } + lsx_seeki(ft,(off_t)4,SEEK_CUR); + continue; + } + + if (strncmp(buf,"ANNO",(size_t)4) == 0) { + lsx_readdw(ft, &chunksize); + if (chunksize & 1) + chunksize++; + chunk_buf = lsx_malloc(chunksize + (size_t)2); + if (lsx_readbuf(ft, chunk_buf,(size_t)chunksize) + != chunksize) + { + lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header"); + return(SOX_EOF); + } + chunk_buf[chunksize] = '\0'; + lsx_debug("%s",chunk_buf); + free(chunk_buf); + + continue; + } + + if (strncmp(buf,"NAME",(size_t)4) == 0) { + lsx_readdw(ft, &chunksize); + if (chunksize & 1) + chunksize++; + chunk_buf = lsx_malloc(chunksize + (size_t)1); + if (lsx_readbuf(ft, chunk_buf,(size_t)chunksize) + != chunksize) + { + lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header"); + return(SOX_EOF); + } + chunk_buf[chunksize] = '\0'; + lsx_debug("%s",chunk_buf); + free(chunk_buf); + + continue; + } + + if (strncmp(buf,"CHAN",(size_t)4) == 0) { + lsx_readdw(ft, &chunksize); + if (chunksize != 4) + { + lsx_fail_errno(ft, SOX_EHDR, "Couldn't read all of header"); + return(SOX_EOF); + } + lsx_readdw(ft, &channels); + channels = (channels & 0x01) + + ((channels & 0x02) >> 1) + + ((channels & 0x04) >> 2) + + ((channels & 0x08) >> 3); + + continue; + } + + /* some other kind of chunk */ + lsx_readdw(ft, &chunksize); + if (chunksize & 1) + chunksize++; + lsx_seeki(ft,(off_t)chunksize,SEEK_CUR); + continue; + + } + + if (rate == 0) + { + lsx_fail_errno(ft, SOX_EHDR, "Invalid sample rate"); + return(SOX_EOF); + } + if (strncmp(buf,"BODY",(size_t)4) != 0) + { + lsx_fail_errno(ft, SOX_EHDR, "BODY chunk not found"); + return(SOX_EOF); + } + lsx_readdw(ft, &(p->nsamples)); + p->left = p->nsamples; + p->ch0_pos = lsx_tell(ft); + + ft->signal.length = p->nsamples; + ft->signal.channels = channels; + ft->signal.rate = rate; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + ft->encoding.bits_per_sample = 8; + + return(SOX_SUCCESS); +} + +/*======================================================================*/ +/* 8SVXREAD */ +/*======================================================================*/ +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t nsamp) +{ + size_t done = 0; + + priv_t * p = (priv_t * ) ft->priv; + size_t frames = nsamp / ft->signal.channels; + unsigned width = p->nsamples / ft->signal.channels; + + if (p->left < frames) + frames = p->left; + + while (done != frames) { + size_t chunk = frames - done; + size_t i; + unsigned ch; + + if (chunk > BUFLEN) + chunk = BUFLEN; + + for (ch = 0; ch != ft->signal.channels; ch++) { + if (lsx_seeki(ft, p->ch0_pos + ch * width, SEEK_SET) || + chunk != lsx_readbuf(ft, p->buf[ch], chunk)) + return done * ft->signal.channels; + } + + for (i = 0; i != chunk; i++) { + for (ch = 0; ch != ft->signal.channels; ch++) { + /* scale signed up to long's range */ + *buf++ = SOX_SIGNED_8BIT_TO_SAMPLE(p->buf[ch][i], dummy); + } + } + + done += chunk; + p->left -= chunk * ft->signal.channels; + p->ch0_pos += chunk; + } + return done * ft->signal.channels; +} + +/*======================================================================*/ +/* 8SVXSTARTWRITE */ +/*======================================================================*/ +static int startwrite(sox_format_t * ft) +{ + priv_t * p = (priv_t * ) ft->priv; + size_t i; + + /* open channel output files */ + for (i = 0; i < ft->signal.channels; i++) { + if ((p->tmp[i] = lsx_tmpfile()) == NULL) + { + lsx_fail_errno(ft,errno,"Can't open channel output file"); + return(SOX_EOF); + } + } + + p->nsamples = 0; + return(SOX_SUCCESS); +} + +/*======================================================================*/ +/* 8SVXWRITE */ +/*======================================================================*/ + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * p = (priv_t * ) ft->priv; + SOX_SAMPLE_LOCALS; + + unsigned char datum; + size_t done = 0, i; + + p->nsamples += len; + + while(done < len) { + for (i = 0; i < ft->signal.channels; i++) { + datum = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips); + putc(datum, p->tmp[i]); + } + done += ft->signal.channels; + } + return (done); +} + +/*======================================================================*/ +/* 8SVXSTOPWRITE */ +/*======================================================================*/ + +static int stopwrite(sox_format_t * ft) +{ + priv_t * p = (priv_t * ) ft->priv; + + size_t i, len; + char svxbuf[512]; + + svxwriteheader(ft, (size_t) p->nsamples); + + /* append all channel pieces to channel 0 */ + /* close temp files */ + for (i = 0; i < ft->signal.channels; i++) { + if (fseeko(p->tmp[i], (off_t)0, 0)) + { + lsx_fail_errno (ft,errno,"Can't rewind channel output file %lu",(unsigned long)i); + return(SOX_EOF); + } + while (!feof(p->tmp[i])) { + len = fread(svxbuf, (size_t) 1, (size_t) 512, p->tmp[i]); + if (lsx_writebuf(ft, svxbuf, len) != len) { + lsx_fail_errno (ft,errno,"Can't write channel output file %lu",(unsigned long)i); + return SOX_EOF; + } + } + fclose (p->tmp[i]); + } + + /* add a pad byte if BODY size is odd */ + if(p->nsamples % 2 != 0) + lsx_writeb(ft, '\0'); + + return(SOX_SUCCESS); +} + +/*======================================================================*/ +/* 8SVXWRITEHEADER */ +/*======================================================================*/ +#define SVXHEADERSIZE 100 +static void svxwriteheader(sox_format_t * ft, size_t nsamples) +{ + size_t formsize = nsamples + SVXHEADERSIZE - 8; + + /* FORM size must be even */ + if(formsize % 2 != 0) formsize++; + + lsx_writes(ft, "FORM"); + lsx_writedw(ft, (unsigned) formsize); /* size of file */ + lsx_writes(ft, "8SVX"); /* File type */ + + lsx_writes(ft, "VHDR"); + lsx_writedw(ft, 20); /* number of bytes to follow */ + lsx_writedw(ft, (unsigned) nsamples/ft->signal.channels); /* samples, 1-shot */ + lsx_writedw(ft, 0); /* samples, repeat */ + lsx_writedw(ft, 0); /* samples per repeat cycle */ + lsx_writew(ft, min(65535, (unsigned)(ft->signal.rate + .5))); + lsx_writeb(ft,1); /* number of octabes */ + lsx_writeb(ft,0); /* data compression (none) */ + lsx_writew(ft,1); lsx_writew(ft,0); /* volume */ + + lsx_writes(ft, "ANNO"); + lsx_writedw(ft, 32); /* length of block */ + lsx_writes(ft, "File created by Sound Exchange "); + + lsx_writes(ft, "CHAN"); + lsx_writedw(ft, 4); + lsx_writedw(ft, (ft->signal.channels == 2) ? 6u : + (ft->signal.channels == 4) ? 15u : 2u); + + lsx_writes(ft, "BODY"); + lsx_writedw(ft, (unsigned) nsamples); /* samples in file */ +} + +LSX_FORMAT_HANDLER(svx) +{ + static char const * const names[] = {"8svx", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 8, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Amiga audio format (a subformat of the Interchange File Format)", + names, SOX_FILE_BIG_END|SOX_FILE_MONO|SOX_FILE_STEREO|SOX_FILE_QUAD, + startread, read_samples, NULL, + startwrite, write_samples, stopwrite, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/Makefile.am b/app/src/main/cpp/sox/Makefile.am new file mode 100755 index 0000000..fe02441 --- /dev/null +++ b/app/src/main/cpp/sox/Makefile.am @@ -0,0 +1,184 @@ +## Process this file with automake to produce Makefile.in + +RM = rm -f + +AM_CPPFLAGS = -DLADSPA_PATH="\"@LADSPA_PATH@\"" + +if HAVE_LIBLTDL +# This is being used as a short cut to turn off versioning of ALL dynamic +# fmt libraries. If any fmt ever needs to add a specific LDFLAGS +# then it will need to also add -avoid-version because AM_LDFLAGS +# is ignored when you specify a more specific one. +# We want to version libsox and we are OK because they +# have a more specific LDFLAGS that includes -version-info. +AM_LDFLAGS = -avoid-version -module +AM_CPPFLAGS += -DPKGLIBDIR="\"$(pkglibdir)\"" +endif + + + +######################### +# SoX - the application # +######################### + +bin_PROGRAMS = sox +EXTRA_PROGRAMS = example0 example1 example2 example3 example4 example5 example6 sox_sample_test +lib_LTLIBRARIES = libsox.la +include_HEADERS = sox.h +sox_SOURCES = sox.c +if HAVE_WIN32_GLOB +sox_SOURCES += win32/glob.c win32/glob.h +AM_CPPFLAGS += -I$(srcdir)/win32 +endif +sox_LDADD = libsox.la +example0_SOURCES = example0.c +example1_SOURCES = example1.c +example2_SOURCES = example2.c +example3_SOURCES = example3.c +example4_SOURCES = example4.c +example5_SOURCES = example5.c +example6_SOURCES = example6.c +sox_sample_test_SOURCES = sox_sample_test.c + + + +###################################################### +# libsox - file format, effects, and utility library # +###################################################### + +# Format handlers and utils source +libsox_la_SOURCES = adpcms.c adpcms.h aiff.c aiff.h cvsd.c cvsd.h cvsdfilt.h \ + g711.c g711.h g721.c g723_24.c g723_40.c g72x.c g72x.h vox.c vox.h \ + raw.c raw.h formats.c formats.h formats_i.c sox_i.h skelform.c \ + xmalloc.c xmalloc.h getopt.c \ + util.c util.h libsox.c libsox_i.c sox-fmt.c soxomp.h + +# Effects source +libsox_la_SOURCES += \ + band.h bend.c biquad.c biquad.h biquads.c chorus.c compand.c \ + compandt.c compandt.h contrast.c dcshift.c delay.c dft_filter.c \ + dft_filter.h dither.c dither.h divide.c downsample.c earwax.c \ + echo.c echos.c effects.c effects.h effects_i.c effects_i_dsp.c \ + fade.c fft4g.c fft4g.h fifo.h fir.c firfit.c flanger.c gain.c \ + hilbert.c input.c ladspa.h ladspa.c loudness.c mcompand.c \ + mcompand_xover.h noiseprof.c noisered.c \ + noisered.h output.c overdrive.c pad.c phaser.c rate.c \ + rate_filters.h rate_half_fir.h rate_poly_fir0.h rate_poly_fir.h \ + remix.c repeat.c reverb.c reverse.c silence.c sinc.c skeleff.c \ + speed.c splice.c stat.c stats.c stretch.c swap.c \ + synth.c tempo.c tremolo.c trim.c upsample.c vad.c vol.c +if HAVE_PNG + libsox_la_SOURCES += spectrogram.c +endif + +libsox_la_LIBADD = + +# Libraries required by libsox for file handlers, effects, or utils; +# regardless if libltdl is used or not. +if HAVE_PNG +libsox_la_LIBADD += @PNG_LIBS@ +endif +if HAVE_MAGIC +libsox_la_LIBADD += @MAGIC_LIBS@ +endif +if HAVE_LIBGSM +libsox_la_LIBADD += @LIBGSM_LIBS@ +endif + +libsox_la_CFLAGS = +libsox_la_LDFLAGS = -no-undefined -version-info @SHLIB_VERSION@ \ + -export-symbols $(srcdir)/libsox.sym + +EXTRA_libsox_la_DEPENDENCIES = $(srcdir)/libsox.sym + +if HAVE_LIBLTDL + libsox_la_CFLAGS += $(LIBLTDL_CFLAGS) + libsox_la_LIBADD += $(LIBLTDL_LIBS) +endif + + + +######################### +# libsox - File Formats # +######################### + +# Uncomment for bit-rot detection on linux +#libsox_la_SOURCES += coreaudio.c sndio.c sunaudio.c +#libsox_la_CFLAGS += -Ibit-rot + +libsox_la_SOURCES += raw-fmt.c s1-fmt.c s2-fmt.c s3-fmt.c \ + s4-fmt.c u1-fmt.c u2-fmt.c u3-fmt.c u4-fmt.c al-fmt.c la-fmt.c ul-fmt.c \ + lu-fmt.c 8svx.c aiff-fmt.c aifc-fmt.c au.c avr.c cdr.c cvsd-fmt.c \ + dvms-fmt.c dat.c hcom.c htk.c maud.c prc.c sf.c smp.c \ + sounder.c soundtool.c sphere.c tx16w.c voc.c vox-fmt.c ima-fmt.c adpcm.c adpcm.h \ + ima_rw.c ima_rw.h wav.c wve.c xa.c nulfile.c f4-fmt.c f8-fmt.c gsrt.c \ + id3.c id3.h + +if HAVE_ID3TAG + libsox_la_LIBADD += @ID3TAG_LIBS@ +endif + +pkglib_LTLIBRARIES = + +include optional-fmts.am + + + +# example programs will need same link options as sox does. +example0_LDADD = ${sox_LDADD} +example1_LDADD = ${sox_LDADD} +example2_LDADD = ${sox_LDADD} +example3_LDADD = ${sox_LDADD} +example4_LDADD = ${sox_LDADD} +example5_LDADD = ${sox_LDADD} +example6_LDADD = ${sox_LDADD} + +EXTRA_DIST = monkey.wav optional-fmts.am \ + tests.sh testall.sh tests.bat testall.bat test-comments + +all: sox$(EXEEXT) + +examples: example0$(EXEEXT) example1$(EXEEXT) example2$(EXEEXT) example3$(EXEEXT) example4$(EXEEXT) example5$(EXEEXT) example6$(EXEEXT) + +extras: examples sox_sample_test$(EXEEXT) + +MAKELINKS = for n in $(SYMLINKS); do $(RM) $$n$(EXEEXT) && $(LN_S) sox$(EXEEXT) $$n$(EXEEXT); done + +all-local: sox$(EXEEXT) + $(MAKELINKS) + +install-exec-hook: + cd $(DESTDIR)$(bindir) && $(MAKELINKS) + +uninstall-hook: + cd $(DESTDIR)$(bindir) && $(RM) play$(EXEEXT) rec$(EXEEXT) soxi$(EXEEXT) + +clean-local: + $(RM) play$(EXEEXT) rec$(EXEEXT) soxi$(EXEEXT) + $(RM) sox_sample_test$(EXEEXT) + $(RM) example0$(EXEEXT) example1$(EXEEXT) example2$(EXEEXT) example3$(EXEEXT) example4$(EXEEXT) example5$(EXEEXT) example6$(EXEEXT) + +distclean-local: + +loc: + sloccount \ + $(include_HEADERS) \ + $(sox_SOURCES) \ + $(example0_SOURCES) \ + $(example1_SOURCES) \ + $(example2_SOURCES) \ + $(example3_SOURCES) \ + $(example4_SOURCES) \ + $(example5_SOURCES) \ + $(example6_SOURCES) \ + $(sox_sample_test_SOURCES) \ + $(libsox_la_SOURCES) + + +# Ideally we would use the "check" target so that "make distcheck" +# would run the test suite, but an uninstalled libltdl build cannot +# currently load its formats and effects, so the checks would fail. +installcheck: + $(srcdir)/tests.sh --bindir=$(DESTDIR)${bindir} --builddir=${builddir} --srcdir=${srcdir} + $(srcdir)/testall.sh --bindir=$(DESTDIR)${bindir} --srcdir=${srcdir} + diff --git a/app/src/main/cpp/sox/adpcm.c b/app/src/main/cpp/sox/adpcm.c new file mode 100644 index 0000000..f64b7d5 --- /dev/null +++ b/app/src/main/cpp/sox/adpcm.c @@ -0,0 +1,367 @@ +/* adpcm.c codex functions for MS_ADPCM data + * (hopefully) provides interoperability with + * Microsoft's ADPCM format, but, as usual, + * see LACK-OF-WARRANTY information below. + * + * Copyright (C) 1999 Stanley J. Brooks + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +/* + * November 22, 1999 + * specs I've seen are unclear about ADPCM supporting more than 2 channels, + * but these routines support more channels in a manner which looks (IMHO) + * like the most natural extension. + * + * Remark: code still turbulent, encoding very new. + * + */ + +#include "sox_i.h" +#include "adpcm.h" + +#include +#include + +typedef struct { + sox_sample_t step; /* step size */ + short coef[2]; +} MsState_t; + +#define lsbshortldi(x,p) { (x)=((short)((int)(p)[0] + ((int)(p)[1]<<8))); (p) += 2; } + +/* + * Lookup tables for MS ADPCM format + */ + +/* these are step-size adjust factors, where + * 1.0 is scaled to 0x100 + */ +static const +sox_sample_t stepAdjustTable[] = { + 230, 230, 230, 230, 307, 409, 512, 614, + 768, 614, 512, 409, 307, 230, 230, 230 +}; + +/* TODO : The first 7 lsx_ms_adpcm_i_coef sets are always hardcoded and must + appear in the actual WAVE file. They should be read in + in case a sound program added extras to the list. */ + +const short lsx_ms_adpcm_i_coef[7][2] = { + { 256, 0}, + { 512,-256}, + { 0, 0}, + { 192, 64}, + { 240, 0}, + { 460,-208}, + { 392,-232} +}; + +extern void *lsx_ms_adpcm_alloc(unsigned chans) +{ + return lsx_malloc(chans * sizeof(MsState_t)); +} + +static inline sox_sample_t AdpcmDecode(sox_sample_t c, MsState_t *state, + sox_sample_t sample1, sox_sample_t sample2) +{ + sox_sample_t vlin; + sox_sample_t sample; + sox_sample_t step; + + /** Compute next step value **/ + step = state->step; + { + sox_sample_t nstep; + nstep = (stepAdjustTable[c] * step) >> 8; + state->step = (nstep < 16)? 16:nstep; + } + + /** make linear prediction for next sample **/ + vlin = + ((sample1 * state->coef[0]) + + (sample2 * state->coef[1])) >> 8; + /** then add the code*step adjustment **/ + c -= (c & 0x08) << 1; + sample = (c * step) + vlin; + + if (sample > 0x7fff) sample = 0x7fff; + else if (sample < -0x8000) sample = -0x8000; + + return (sample); +} + +/* lsx_ms_adpcm_block_expand_i() outputs interleaved samples into one output buffer */ +const char *lsx_ms_adpcm_block_expand_i( + void *priv, + unsigned chans, /* total channels */ + int nCoef, + const short *coef, + const unsigned char *ibuff,/* input buffer[blockAlign] */ + SAMPL *obuff, /* output samples, n*chans */ + int n /* samples to decode PER channel */ +) +{ + const unsigned char *ip; + unsigned ch; + const char *errmsg = NULL; + MsState_t *state = priv; /* One decompressor state for each channel */ + + /* Read the four-byte header for each channel */ + ip = ibuff; + for (ch = 0; ch < chans; ch++) { + unsigned char bpred = *ip++; + if (bpred >= nCoef) { + errmsg = "MSADPCM bpred >= nCoef, arbitrarily using 0\n"; + bpred = 0; + } + state[ch].coef[0] = coef[(int)bpred*2+0]; + state[ch].coef[1] = coef[(int)bpred*2+1]; + } + + for (ch = 0; ch < chans; ch++) + lsbshortldi(state[ch].step, ip); + + /* sample1's directly into obuff */ + for (ch = 0; ch < chans; ch++) + lsbshortldi(obuff[chans+ch], ip); + + /* sample2's directly into obuff */ + for (ch = 0; ch < chans; ch++) + lsbshortldi(obuff[ch], ip); + + { + unsigned ch2; + unsigned char b; + short *op, *top, *tmp; + + /* already have 1st 2 samples from block-header */ + op = obuff + 2*chans; + top = obuff + n*chans; + + ch2 = 0; + while (op < top) { /*** N.B. Without int casts, crashes on 64-bit arch ***/ + b = *ip++; + tmp = op; + *op++ = AdpcmDecode(b >> 4, state+ch2, tmp[-(int)chans], tmp[-(int)(2*chans)]); + if (++ch2 == chans) ch2 = 0; + tmp = op; + *op++ = AdpcmDecode(b&0x0f, state+ch2, tmp[-(int)chans], tmp[-(int)(2*chans)]); + if (++ch2 == chans) ch2 = 0; + } + } + return errmsg; +} + +static int AdpcmMashS( + unsigned ch, /* channel number to encode, REQUIRE 0 <= ch < chans */ + unsigned chans, /* total channels */ + SAMPL v[2], /* values to use as starting 2 */ + const short coef[2],/* lin predictor coeffs */ + const SAMPL *ibuff, /* ibuff[] is interleaved input samples */ + int n, /* samples to encode PER channel */ + int *iostep, /* input/output step, REQUIRE 16 <= *st <= 0x7fff */ + unsigned char *obuff /* output buffer[blockAlign], or NULL for no output */ +) +{ + const SAMPL *ip, *itop; + unsigned char *op; + int ox = 0; /* */ + int d, v0, v1, step; + double d2; /* long long is okay also, speed abt the same */ + + ip = ibuff + ch; /* point ip to 1st input sample for this channel */ + itop = ibuff + n*chans; + v0 = v[0]; + v1 = v[1]; + d = *ip - v1; ip += chans; /* 1st input sample for this channel */ + d2 = d*d; /* d2 will be sum of squares of errors, given input v0 and *st */ + d = *ip - v0; ip += chans; /* 2nd input sample for this channel */ + d2 += d*d; + + step = *iostep; + + op = obuff; /* output pointer (or NULL) */ + if (op) { /* NULL means don't output, just compute the rms error */ + op += chans; /* skip bpred indices */ + op += 2*ch; /* channel's stepsize */ + op[0] = step; op[1] = step>>8; + op += 2*chans; /* skip to v0 */ + op[0] = v0; op[1] = v0>>8; + op += 2*chans; /* skip to v1 */ + op[0] = v1; op[1] = v1>>8; + op = obuff+7*chans; /* point to base of output nibbles */ + ox = 4*ch; + } + for (; ip < itop; ip+=chans) { + int vlin,d3,dp,c; + + /* make linear prediction for next sample */ + vlin = (v0 * coef[0] + v1 * coef[1]) >> 8; + d3 = *ip - vlin; /* difference between linear prediction and current sample */ + dp = d3 + (step<<3) + (step>>1); + c = 0; + if (dp>0) { + c = dp/step; + if (c>15) c = 15; + } + c -= 8; + dp = c * step; /* quantized estimate of samp - vlin */ + c &= 0x0f; /* mask to 4 bits */ + + v1 = v0; /* shift history */ + v0 = vlin + dp; + if (v0<-0x8000) v0 = -0x8000; + else if (v0>0x7fff) v0 = 0x7fff; + + d3 = *ip - v0; + d2 += d3*d3; /* update square-error */ + + if (op) { /* if we want output, put it in proper place */ + op[ox>>3] |= (ox&4)? c:(c<<4); + ox += 4*chans; + lsx_debug_more("%.1x",c); + + } + + /* Update the step for the next sample */ + step = (stepAdjustTable[c] * step) >> 8; + if (step < 16) step = 16; + + } + if (op) lsx_debug_more("\n"); + d2 /= n; /* be sure it's non-negative */ + lsx_debug_more("ch%d: st %d->%d, d %.1f\n", ch, *iostep, step, sqrt(d2)); + *iostep = step; + return (int) sqrt(d2); +} + +static inline void AdpcmMashChannel( + unsigned ch, /* channel number to encode, REQUIRE 0 <= ch < chans */ + unsigned chans, /* total channels */ + const SAMPL *ip, /* ip[] is interleaved input samples */ + int n, /* samples to encode PER channel, REQUIRE */ + int *st, /* input/output steps, 16<=st[i] */ + unsigned char *obuff /* output buffer[blockAlign] */ +) +{ + SAMPL v[2]; + int n0,s0,s1,ss,smin; + int dmin,k,kmin; + + n0 = n/2; if (n0>32) n0=32; + if (*st<16) *st = 16; + v[1] = ip[ch]; + v[0] = ip[ch+chans]; + + dmin = 0; kmin = 0; smin = 0; + /* for each of 7 standard coeff sets, we try compression + * beginning with last step-value, and with slightly + * forward-adjusted step-value, taking best of the 14 + */ + for (k=0; k<7; k++) { + int d0,d1; + ss = s0 = *st; + d0=AdpcmMashS(ch, chans, v, lsx_ms_adpcm_i_coef[k], ip, n, &ss, NULL); /* with step s0 */ + + s1 = s0; + AdpcmMashS(ch, chans, v, lsx_ms_adpcm_i_coef[k], ip, n0, &s1, NULL); + lsx_debug_more(" s32 %d\n",s1); + ss = s1 = (3*s0+s1)/4; + d1=AdpcmMashS(ch, chans, v, lsx_ms_adpcm_i_coef[k], ip, n, &ss, NULL); /* with step s1 */ + if (!k || d0= 7*chans + chans*(n-2)/2.0 */ +) +{ + unsigned ch; + unsigned char *p; + + lsx_debug_more("AdpcmMashI(chans %d, ip %p, n %d, st %p, obuff %p, bA %d)\n", + chans, (void *)ip, n, (void *)st, obuff, blockAlign); + + for (p=obuff+7*chans; p= (size_t)(7*chans)) { + m -= 7*chans; /* bytes beyond block-header */ + m = (2*m)/chans + 2; /* nibbles/chans + 2 in header */ + if (samplesPerBlock && m > samplesPerBlock) m = samplesPerBlock; + n += m; + } + return n; +} + +size_t lsx_ms_adpcm_bytes_per_block( + size_t chans, + size_t samplesPerBlock +) +{ + size_t n; + n = 7*chans; /* header */ + if (samplesPerBlock > 2) + n += (((size_t)samplesPerBlock-2)*chans + 1)/2; + return n; +} + diff --git a/app/src/main/cpp/sox/adpcm.h b/app/src/main/cpp/sox/adpcm.h new file mode 100644 index 0000000..db5cc61 --- /dev/null +++ b/app/src/main/cpp/sox/adpcm.h @@ -0,0 +1,79 @@ +/* adpcm.h codex functions for MS_ADPCM data + * (hopefully) provides interoperability with + * Microsoft's ADPCM format, but, as usual, + * see LACK-OF-WARRANTY information below. + * + * Copyright (C) 1999 Stanley J. Brooks + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "sox.h" + +#ifndef SAMPL +#define SAMPL short +#endif + +/* default coef sets */ +extern const short lsx_ms_adpcm_i_coef[7][2]; + +extern void *lsx_ms_adpcm_alloc(unsigned chans); + +/* lsx_ms_adpcm_block_expand_i() outputs interleaved samples into one output buffer */ +extern const char *lsx_ms_adpcm_block_expand_i( + void *priv, + unsigned chans, /* total channels */ + int nCoef, + const short *coef, + const unsigned char *ibuff,/* input buffer[blockAlign] */ + SAMPL *obuff, /* output samples, n*chans */ + int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */ +); + +extern void lsx_ms_adpcm_block_mash_i( + unsigned chans, /* total channels */ + const SAMPL *ip, /* ip[n*chans] is interleaved input samples */ + int n, /* samples to encode PER channel, REQUIRE */ + int *st, /* input/output steps, 16<=st[i] */ + unsigned char *obuff, /* output buffer[blockAlign] */ + int blockAlign /* >= 7*chans + n/2 */ +); + +/* Some helper functions for computing samples/block and blockalign */ + +/* + * lsx_ms_adpcm_samples_in(dataLen, chans, blockAlign, samplesPerBlock) + * returns the number of samples/channel which would be + * in the dataLen, given the other parameters ... + * if input samplesPerBlock is 0, then returns the max + * samplesPerBlock which would go into a block of size blockAlign + * Yes, it is confusing usage. + */ +extern size_t lsx_ms_adpcm_samples_in( + size_t dataLen, + size_t chans, + size_t blockAlign, + size_t samplesPerBlock +); + +/* + * size_t lsx_ms_adpcm_bytes_per_block(chans, samplesPerBlock) + * return minimum blocksize which would be required + * to encode number of chans with given samplesPerBlock + */ +extern size_t lsx_ms_adpcm_bytes_per_block( + size_t chans, + size_t samplesPerBlock +); diff --git a/app/src/main/cpp/sox/adpcms.c b/app/src/main/cpp/sox/adpcms.c new file mode 100644 index 0000000..7295689 --- /dev/null +++ b/app/src/main/cpp/sox/adpcms.c @@ -0,0 +1,322 @@ +/* libSoX ADPCM codecs: IMA, OKI, CL. (c) 2007-8 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "adpcms.h" + +static int const ima_steps[89] = { /* ~16-bit precision; 4 bit code */ + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, + 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, + 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, + 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, + 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, + 32767}; + +static int const oki_steps[49] = { /* ~12-bit precision; 4 bit code */ + 256, 272, 304, 336, 368, 400, 448, 496, 544, 592, 656, 720, 800, 880, 960, + 1056, 1168, 1280, 1408, 1552, 1712, 1888, 2080, 2288, 2512, 2768, 3040, 3344, + 3680, 4048, 4464, 4912, 5392, 5936, 6528, 7184, 7904, 8704, 9568, 10528, + 11584, 12736, 14016, 15408, 16960, 18656, 20512, 22576, 24832}; + +static int const step_changes[8] = {-1, -1, -1, -1, 2, 4, 6, 8}; + +/* Creative Labs ~8 bit precision; 4, 3, & 2 bit codes: */ +static int const cl4_steps[4] = {0x100, 0x200, 0x400, 0x800}; +static int const cl4_changes[8] = {-1, 0, 0, 0, 0, 1, 1, 1}; + +static int const cl3_steps[5] = {0x100, 0x200, 0x400, 0x800, 0xA00}; +static int const cl3_changes[4] = {-1, 0, 0, 1}; + +static int const cl2_steps[6] = {0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000}; +static int const cl2_changes[2] = {-1, 1}; + +static adpcm_setup_t const setup_table[] = { + {88, 8, 2, ima_steps, step_changes, ~0}, + {48, 8, 2, oki_steps, step_changes, ~15}, + { 3, 8, 0, cl4_steps, cl4_changes , ~255}, + { 4, 4, 0, cl3_steps, cl3_changes , ~255}, + { 5, 2, 0, cl2_steps, cl2_changes , ~255}, +}; + +void lsx_adpcm_init(adpcm_t * p, int type, int first_sample) +{ + p->setup = setup_table[type]; + p->last_output = first_sample; + p->step_index = 0; + p->errors = 0; +} + +#define min_sample -0x8000 +#define max_sample 0x7fff + +int lsx_adpcm_decode(int code, adpcm_t * p) +{ + int s = ((code & (p->setup.sign - 1)) << 1) | 1; + s = ((p->setup.steps[p->step_index] * s) >> (p->setup.shift + 1)) & p->setup.mask; + if (code & p->setup.sign) + s = -s; + s += p->last_output; + if (s < min_sample || s > max_sample) { + int grace = (p->setup.steps[p->step_index] >> (p->setup.shift + 1)) & p->setup.mask; + if (s < min_sample - grace || s > max_sample + grace) { + lsx_debug_most("code=%i step=%i grace=%i s=%i", + code & (2 * p->setup.sign - 1), p->setup.steps[p->step_index], grace, s); + p->errors++; + } + s = s < min_sample? min_sample : max_sample; + } + p->step_index += p->setup.changes[code & (p->setup.sign - 1)]; + p->step_index = range_limit(p->step_index, 0, p->setup.max_step_index); + return p->last_output = s; +} + +int lsx_adpcm_encode(int sample, adpcm_t * p) +{ + int delta = sample - p->last_output; + int sign = 0; + int code; + if (delta < 0) { + sign = p->setup.sign; + delta = -delta; + } + code = (delta << p->setup.shift) / p->setup.steps[p->step_index]; + code = sign | min(code, p->setup.sign - 1); + lsx_adpcm_decode(code, p); /* Update encoder state */ + return code; +} + + +/* + * Format methods + * + * Almost like the raw format functions, but cannot be used directly + * since they require an additional state parameter. + */ + +/****************************************************************************** + * Function : lsx_adpcm_reset + * Description: Resets the ADPCM codec state. + * Parameters : state - ADPCM state structure + * type - SOX_ENCODING_OKI_ADPCM or SOX_ENCODING_IMA_ADPCM + * Returns : + * Exceptions : + * Notes : 1. This function is used for framed ADPCM formats to reset + * the decoder between frames. + ******************************************************************************/ + +void lsx_adpcm_reset(adpcm_io_t * state, sox_encoding_t type) +{ + state->file.count = 0; + state->file.pos = 0; + state->store.byte = 0; + state->store.flag = 0; + + lsx_adpcm_init(&state->encoder, (type == SOX_ENCODING_OKI_ADPCM) ? 1 : 0, 0); +} + +/****************************************************************************** + * Function : lsx_adpcm_start + * Description: Initialises the file parameters and ADPCM codec state. + * Parameters : ft - file info structure + * state - ADPCM state structure + * type - SOX_ENCODING_OKI_ADPCM or SOX_ENCODING_IMA_ADPCM + * Returns : int - SOX_SUCCESS + * SOX_EOF + * Exceptions : + * Notes : 1. This function can be used as a startread or + * startwrite method. + * 2. VOX file format is 4-bit OKI ADPCM that decodes to + * to 12 bit signed linear PCM. + * 3. Dialogic only supports 6kHz, 8kHz and 11 kHz sampling + * rates but the codecs allows any user specified rate. + ******************************************************************************/ + +static int adpcm_start(sox_format_t * ft, adpcm_io_t * state, sox_encoding_t type) +{ + /* setup file info */ + state->file.buf = lsx_malloc(sox_globals.bufsiz); + state->file.size = sox_globals.bufsiz; + ft->signal.channels = 1; + + lsx_adpcm_reset(state, type); + + return lsx_rawstart(ft, sox_true, sox_false, sox_true, type, 4); +} + +int lsx_adpcm_oki_start(sox_format_t * ft, adpcm_io_t * state) +{ + return adpcm_start(ft, state, SOX_ENCODING_OKI_ADPCM); +} + +int lsx_adpcm_ima_start(sox_format_t * ft, adpcm_io_t * state) +{ + return adpcm_start(ft, state, SOX_ENCODING_IMA_ADPCM); +} + +/****************************************************************************** + * Function : lsx_adpcm_read + * Description: Converts the OKI ADPCM 4-bit samples to 16-bit signed PCM and + * then scales the samples to full sox_sample_t range. + * Parameters : ft - file info structure + * state - ADPCM state structure + * buffer - output buffer + * len - size of output buffer + * Returns : - number of samples returned in buffer + * Exceptions : + * Notes : + ******************************************************************************/ + +size_t lsx_adpcm_read(sox_format_t * ft, adpcm_io_t * state, sox_sample_t * buffer, size_t len) +{ + size_t n = 0; + uint8_t byte; + int16_t word; + + if (len && state->store.flag) { + word = lsx_adpcm_decode(state->store.byte, &state->encoder); + *buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips); + state->store.flag = 0; + ++n; + } + while (n < len && lsx_read_b_buf(ft, &byte, (size_t) 1) == 1) { + word = lsx_adpcm_decode(byte >> 4, &state->encoder); + *buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips); + + if (++n < len) { + word = lsx_adpcm_decode(byte, &state->encoder); + *buffer++ = SOX_SIGNED_16BIT_TO_SAMPLE(word, ft->clips); + ++n; + } else { + state->store.byte = byte; + state->store.flag = 1; + } + } + return n; +} + +/****************************************************************************** + * Function : stopread + * Description: Frees the internal buffer allocated in voxstart/imastart. + * Parameters : ft - file info structure + * state - ADPCM state structure + * Returns : int - SOX_SUCCESS + * Exceptions : + * Notes : + ******************************************************************************/ + +int lsx_adpcm_stopread(sox_format_t * ft UNUSED, adpcm_io_t * state) +{ + if (state->encoder.errors) + lsx_warn("%s: ADPCM state errors: %u", ft->filename, state->encoder.errors); + free(state->file.buf); + + return (SOX_SUCCESS); +} + + +/****************************************************************************** + * Function : write + * Description: Converts the supplied buffer to 12 bit linear PCM and encodes + * to OKI ADPCM 4-bit samples (packed a two nibbles per byte). + * Parameters : ft - file info structure + * state - ADPCM state structure + * buffer - output buffer + * length - size of output buffer + * Returns : int - SOX_SUCCESS + * SOX_EOF + * Exceptions : + * Notes : + ******************************************************************************/ + +size_t lsx_adpcm_write(sox_format_t * ft, adpcm_io_t * state, const sox_sample_t * buffer, size_t length) +{ + size_t count = 0; + uint8_t byte = state->store.byte; + uint8_t flag = state->store.flag; + short word; + + while (count < length) { + SOX_SAMPLE_LOCALS; + word = SOX_SAMPLE_TO_SIGNED_16BIT(*buffer++, ft->clips); + + byte <<= 4; + byte |= lsx_adpcm_encode(word, &state->encoder) & 0x0F; + + flag = !flag; + + if (flag == 0) { + state->file.buf[state->file.count++] = byte; + + if (state->file.count >= state->file.size) { + lsx_writebuf(ft, state->file.buf, state->file.count); + + state->file.count = 0; + } + } + + count++; + } + + /* keep last byte across calls */ + state->store.byte = byte; + state->store.flag = flag; + return (count); +} + +/****************************************************************************** + * Function : lsx_adpcm_flush + * Description: Flushes any leftover samples. + * Parameters : ft - file info structure + * state - ADPCM state structure + * Returns : + * Exceptions : + * Notes : 1. Called directly for writing framed formats + ******************************************************************************/ + +void lsx_adpcm_flush(sox_format_t * ft, adpcm_io_t * state) +{ + uint8_t byte = state->store.byte; + uint8_t flag = state->store.flag; + + /* flush remaining samples */ + + if (flag != 0) { + byte <<= 4; + state->file.buf[state->file.count++] = byte; + } + if (state->file.count > 0) + lsx_writebuf(ft, state->file.buf, state->file.count); +} + +/****************************************************************************** + * Function : lsx_adpcm_stopwrite + * Description: Flushes any leftover samples and frees the internal buffer + * allocated in voxstart/imastart. + * Parameters : ft - file info structure + * state - ADPCM state structure + * Returns : int - SOX_SUCCESS + * Exceptions : + * Notes : + ******************************************************************************/ + +int lsx_adpcm_stopwrite(sox_format_t * ft, adpcm_io_t * state) +{ + lsx_adpcm_flush(ft, state); + free(state->file.buf); + return (SOX_SUCCESS); +} diff --git a/app/src/main/cpp/sox/adpcms.h b/app/src/main/cpp/sox/adpcms.h new file mode 100644 index 0000000..bac2e2a --- /dev/null +++ b/app/src/main/cpp/sox/adpcms.h @@ -0,0 +1,55 @@ +/* libSoX ADPCM codecs: IMA, OKI, CL. (c) 2007-8 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +typedef struct { + int max_step_index; + int sign; + int shift; + int const * steps; + int const * changes; + int mask; +} adpcm_setup_t; + +typedef struct { + adpcm_setup_t setup; + int last_output; + int step_index; + int errors; +} adpcm_t; + +void lsx_adpcm_init(adpcm_t * p, int type, int first_sample); +int lsx_adpcm_decode(int code, adpcm_t * p); +int lsx_adpcm_encode(int sample, adpcm_t * p); + +typedef struct { + adpcm_t encoder; + struct { + uint8_t byte; /* write store */ + uint8_t flag; + } store; + sox_fileinfo_t file; +} adpcm_io_t; + +/* Format methods */ +void lsx_adpcm_reset(adpcm_io_t * state, sox_encoding_t type); +int lsx_adpcm_oki_start(sox_format_t * ft, adpcm_io_t * state); +int lsx_adpcm_ima_start(sox_format_t * ft, adpcm_io_t * state); +size_t lsx_adpcm_read(sox_format_t * ft, adpcm_io_t * state, sox_sample_t *buffer, size_t len); +int lsx_adpcm_stopread(sox_format_t * ft, adpcm_io_t * state); +size_t lsx_adpcm_write(sox_format_t * ft, adpcm_io_t * state, const sox_sample_t *buffer, size_t length); +void lsx_adpcm_flush(sox_format_t * ft, adpcm_io_t * state); +int lsx_adpcm_stopwrite(sox_format_t * ft, adpcm_io_t * state); diff --git a/app/src/main/cpp/sox/aifc-fmt.c b/app/src/main/cpp/sox/aifc-fmt.c new file mode 100644 index 0000000..2c4a73b --- /dev/null +++ b/app/src/main/cpp/sox/aifc-fmt.c @@ -0,0 +1,36 @@ +/* File format: AIFF-C (see aiff.c) (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "aiff.h" + +LSX_FORMAT_HANDLER(aifc) +{ + static char const * const names[] = {"aifc", "aiffc", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + 0}; + static sox_format_handler_t const sox_aifc_format = {SOX_LIB_VERSION_CODE, + "AIFF-C (not compressed), defined in DAVIC 1.4 Part 9 Annex B", + names, SOX_FILE_BIG_END, + lsx_aiffstartread, lsx_rawread, lsx_aiffstopread, + lsx_aifcstartwrite, lsx_rawwrite, lsx_aifcstopwrite, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &sox_aifc_format; +} diff --git a/app/src/main/cpp/sox/aiff-fmt.c b/app/src/main/cpp/sox/aiff-fmt.c new file mode 100644 index 0000000..eee45e9 --- /dev/null +++ b/app/src/main/cpp/sox/aiff-fmt.c @@ -0,0 +1,33 @@ +/* File format: AIFF (see aiff.c) (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "aiff.h" + +LSX_FORMAT_HANDLER(aiff) +{ + static char const * const names[] = {"aiff", "aif", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, 0}; + static sox_format_handler_t const sox_aiff_format = {SOX_LIB_VERSION_CODE, + "AIFF files used on Apple IIc/IIgs and SGI", names, SOX_FILE_BIG_END, + lsx_aiffstartread, lsx_rawread, lsx_aiffstopread, + lsx_aiffstartwrite, lsx_rawwrite, lsx_aiffstopwrite, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &sox_aiff_format; +} diff --git a/app/src/main/cpp/sox/aiff.c b/app/src/main/cpp/sox/aiff.c new file mode 100644 index 0000000..3a152c5 --- /dev/null +++ b/app/src/main/cpp/sox/aiff.c @@ -0,0 +1,1151 @@ +/* libSoX SGI/Amiga AIFF format. + * Copyright 1991-2007 Guido van Rossum And Sundry Contributors + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Guido van Rossum And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * Used by SGI on 4D/35 and Indigo. + * This is a subformat of the EA-IFF-85 format. + * This is related to the IFF format used by the Amiga. + * But, apparently, not the same. + * Also AIFF-C format output that is defined in DAVIC 1.4 Part 9 Annex B + * (usable for japanese-data-broadcasting, specified by ARIB STD-B24.) + */ + +#include "sox_i.h" +#include "aiff.h" +#include "id3.h" + +#include /* for time stamping comments */ +#include +#include +#include +#include +#include + +/* forward declarations */ +static double read_ieee_extended(sox_format_t *); +static int aiffwriteheader(sox_format_t *, uint64_t); +static int aifcwriteheader(sox_format_t *, uint64_t); +static void write_ieee_extended(sox_format_t *, double); +static double ConvertFromIeeeExtended(unsigned char*); +static void ConvertToIeeeExtended(double, char *); +static int textChunk(char **text, char *chunkDescription, sox_format_t * ft); +static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft); +static void reportInstrument(sox_format_t * ft); + +int lsx_aiffstartread(sox_format_t * ft) +{ + char buf[5]; + uint32_t totalsize; + uint32_t chunksize; + unsigned short channels = 0; + sox_encoding_t enc = SOX_ENCODING_SIGN2; + uint32_t frames; + unsigned short bits = 0; + double rate = 0.0; + uint32_t offset = 0; + uint32_t blocksize = 0; + int foundcomm = 0, foundmark = 0, foundinstr = 0, is_sowt = 0; + struct mark { + unsigned short id; + uint32_t position; + char name[40]; + } marks[32]; + unsigned short looptype; + int i, j; + unsigned short nmarks = 0; + unsigned short sustainLoopBegin = 0, sustainLoopEnd = 0, + releaseLoopBegin = 0, releaseLoopEnd = 0; + off_t seekto = 0; + size_t ssndsize = 0; + char *annotation; + char *author; + char *copyright; + char *nametext; + + uint8_t trash8; + uint16_t trash16; + uint32_t trash32; + + int rc; + + /* FORM chunk */ + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) { + lsx_fail_errno(ft,SOX_EHDR,"AIFF header does not begin with magic word `FORM'"); + return(SOX_EOF); + } + lsx_readdw(ft, &totalsize); + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || (strncmp(buf, "AIFF", (size_t)4) != 0 && + strncmp(buf, "AIFC", (size_t)4) != 0)) { + lsx_fail_errno(ft,SOX_EHDR,"AIFF `FORM' chunk does not specify `AIFF' or `AIFC' as type"); + return(SOX_EOF); + } + + + /* Skip everything but the COMM chunk and the SSND chunk */ + /* The SSND chunk must be the last in the file */ + while (1) { + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF) { + if (seekto > 0) + break; + else { + lsx_fail_errno(ft,SOX_EHDR,"Missing SSND chunk in AIFF file"); + return(SOX_EOF); + } + } + if (strncmp(buf, "COMM", (size_t)4) == 0) { + /* COMM chunk */ + lsx_readdw(ft, &chunksize); + lsx_readw(ft, &channels); + lsx_readdw(ft, &frames); + lsx_readw(ft, &bits); + rate = read_ieee_extended(ft); + chunksize -= 18; + if (chunksize > 0) { + lsx_reads(ft, buf, (size_t)4); + chunksize -= 4; + if (strncmp(buf, "sowt", (size_t)4) == 0) { + /* CD audio as read on Mac OS machines */ + /* Need to endian swap all the data */ + is_sowt = 1; + } + else if (strncmp(buf, "fl32", (size_t)4) == 0 || + strncmp(buf, "FL32", (size_t)4) == 0) { + enc = SOX_ENCODING_FLOAT; + if (bits != 32) { + lsx_fail_errno(ft, SOX_EHDR, + "Sample size of %u is not consistent with `fl32' compression type", bits); + return SOX_EOF; + } + } + else if (strncmp(buf, "fl64", (size_t)4) == 0 || + strncmp(buf, "FL64", (size_t)4) == 0) { + enc = SOX_ENCODING_FLOAT; + if (bits != 64) { + lsx_fail_errno(ft, SOX_EHDR, + "Sample size of %u is not consistent with `fl64' compression type", bits); + return SOX_EOF; + } + } + else if (strncmp(buf, "NONE", (size_t)4) != 0 && + strncmp(buf, "twos", (size_t)4) != 0) { + buf[4] = 0; + lsx_fail_errno(ft, SOX_EHDR, "Unsupported AIFC compression type `%s'", buf); + return(SOX_EOF); + } + } + while(chunksize-- > 0) + lsx_readb(ft, &trash8); + foundcomm = 1; + } + else if (strncmp(buf, "SSND", (size_t)4) == 0) { + /* SSND chunk */ + lsx_readdw(ft, &chunksize); + lsx_readdw(ft, &offset); + lsx_readdw(ft, &blocksize); + chunksize -= 8; + ssndsize = chunksize; + /* word-align chunksize in case it wasn't + * done by writing application already. + */ + chunksize += (chunksize % 2); + /* if can't seek, just do sound now */ + if (!ft->seekable) + break; + /* else, seek to end of sound and hunt for more */ + seekto = lsx_tell(ft); + lsx_seeki(ft, (off_t)chunksize, SEEK_CUR); + } + else if (strncmp(buf, "MARK", (size_t)4) == 0) { + /* MARK chunk */ + lsx_readdw(ft, &chunksize); + if (chunksize >= sizeof(nmarks)) { + lsx_readw(ft, &nmarks); + chunksize -= sizeof(nmarks); + } + else nmarks = 0; + + /* Some programs like to always have a MARK chunk + * but will set number of marks to 0 and force + * software to detect and ignore it. + */ + if (nmarks == 0) + foundmark = 0; + else + foundmark = 1; + + /* Make sure its not larger then we support */ + if (nmarks > 32) + nmarks = 32; + + for(i = 0; i < nmarks && chunksize; i++) { + unsigned char len, read_len, tmp_c; + + if (chunksize < 6) + break; + lsx_readw(ft, &(marks[i].id)); + lsx_readdw(ft, &(marks[i].position)); + chunksize -= 6; + /* If error reading length then + * don't try to read more bytes + * based on that value. + */ + if (lsx_readb(ft, &len) != SOX_SUCCESS) + break; + --chunksize; + if (len > chunksize) + len = chunksize; + read_len = len; + if (read_len > 39) + read_len = 39; + for(j = 0; j < len && chunksize; j++) { + lsx_readb(ft, &tmp_c); + if (j < read_len) + marks[i].name[j] = tmp_c; + chunksize--; + } + marks[i].name[read_len] = 0; + if ((len & 1) == 0 && chunksize) { + chunksize--; + lsx_readb(ft, &trash8); + } + } + /* HA HA! Sound Designer (and others) makes */ + /* bogus files. It spits out bogus chunksize */ + /* for MARK field */ + while(chunksize-- > 0) + lsx_readb(ft, &trash8); + } + else if (strncmp(buf, "INST", (size_t)4) == 0) { + /* INST chunk */ + lsx_readdw(ft, &chunksize); + lsx_readsb(ft, &(ft->oob.instr.MIDInote)); + lsx_readb(ft, &trash8); + lsx_readsb(ft, &(ft->oob.instr.MIDIlow)); + lsx_readsb(ft, &(ft->oob.instr.MIDIhi)); + /* Low velocity */ + lsx_readb(ft, &trash8); + /* Hi velocity */ + lsx_readb(ft, &trash8); + lsx_readw(ft, &trash16);/* gain */ + lsx_readw(ft, &looptype); /* sustain loop */ + ft->oob.loops[0].type = looptype; + lsx_readw(ft, &sustainLoopBegin); /* begin marker */ + lsx_readw(ft, &sustainLoopEnd); /* end marker */ + lsx_readw(ft, &looptype); /* release loop */ + ft->oob.loops[1].type = looptype; + lsx_readw(ft, &releaseLoopBegin); /* begin marker */ + lsx_readw(ft, &releaseLoopEnd); /* end marker */ + + foundinstr = 1; + } + else if (strncmp(buf, "APPL", (size_t)4) == 0) { + lsx_readdw(ft, &chunksize); + /* word-align chunksize in case it wasn't + * done by writing application already. + */ + chunksize += (chunksize % 2); + while(chunksize-- > 0) + lsx_readb(ft, &trash8); + } + else if (strncmp(buf, "ALCH", (size_t)4) == 0) { + /* I think this is bogus and gets grabbed by APPL */ + /* INST chunk */ + lsx_readdw(ft, &trash32); /* ENVS - jeez! */ + lsx_readdw(ft, &chunksize); + while(chunksize-- > 0) + lsx_readb(ft, &trash8); + } + else if (strncmp(buf, "ANNO", (size_t)4) == 0) { + rc = textChunk(&annotation, "Annotation:", ft); + if (rc) { + /* Fail already called in function */ + return(SOX_EOF); + } + if (annotation) + sox_append_comments(&ft->oob.comments, annotation); + free(annotation); + } + else if (strncmp(buf, "COMT", (size_t)4) == 0) { + char *comment = NULL; + rc = commentChunk(&comment, "Comment:", ft); + if (rc) { + /* Fail already called in function */ + return(SOX_EOF); + } + if (comment) + sox_append_comments(&ft->oob.comments, comment); + free(comment); + } + else if (strncmp(buf, "AUTH", (size_t)4) == 0) { + /* Author chunk */ + rc = textChunk(&author, "Author:", ft); + if (rc) { + /* Fail already called in function */ + return(SOX_EOF); + } + free(author); + } + else if (strncmp(buf, "NAME", (size_t)4) == 0) { + /* Name chunk */ + rc = textChunk(&nametext, "Name:", ft); + if (rc) { + /* Fail already called in function */ + return(SOX_EOF); + } + free(nametext); + } + else if (strncmp(buf, "(c) ", (size_t)4) == 0) { + /* Copyright chunk */ + rc = textChunk(©right, "Copyright:", ft); + if (rc) { + /* Fail already called in function */ + return(SOX_EOF); + } + free(copyright); + } + else if (strncmp(buf, "ID3 ", 4) == 0) { + off_t offs; + lsx_readdw(ft, &chunksize); + offs = lsx_tell(ft); + lsx_id3_read_tag(ft, 0); + lsx_seeki(ft, offs + chunksize, SEEK_SET); + } + else { + if (lsx_eof(ft)) + break; + buf[4] = 0; + lsx_debug("AIFFstartread: ignoring `%s' chunk", buf); + lsx_readdw(ft, &chunksize); + if (lsx_eof(ft)) + break; + /* account for padding after odd-sized chunks */ + chunksize += chunksize & 1; + /* Skip the chunk using lsx_readb() so we may read + from a pipe */ + while (chunksize-- > 0) { + if (lsx_readb(ft, &trash8) == SOX_EOF) + break; + } + } + if (lsx_eof(ft)) + break; + } + + /* + * if a pipe, we lose all chunks after sound. + * Like, say, instrument loops. + */ + if (ft->seekable) { + if (seekto > 0) + lsx_seeki(ft, seekto, SEEK_SET); + else { + lsx_fail_errno(ft,SOX_EOF,"AIFF: no sound data on input file"); + return(SOX_EOF); + } + } + /* SSND chunk just read */ + if (blocksize != 0) + lsx_warn("AIFF header has invalid blocksize. Ignoring but expect a premature EOF"); + + ssndsize -= offset; + while (offset-- > 0) { + if (lsx_readb(ft, &trash8) == SOX_EOF) { + lsx_fail_errno(ft,errno,"unexpected EOF while skipping AIFF offset"); + return(SOX_EOF); + } + } + + if (foundcomm) { + if (bits <= 8) bits = 8; + else if (bits <= 16) bits = 16; + else if (bits <= 24) bits = 24; + else if (bits <= 32) bits = 32; + else if (bits == 64 && enc == SOX_ENCODING_FLOAT) /* no-op */; + else { + lsx_fail_errno(ft,SOX_EFMT,"unsupported sample size in AIFF header: %d", bits); + return(SOX_EOF); + } + } else { + if ((ft->signal.channels == SOX_UNSPEC) + || (ft->signal.rate == SOX_UNSPEC) + || (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) + || (ft->encoding.bits_per_sample == 0)) { + lsx_report("You must specify # channels, sample rate, signed/unsigned,"); + lsx_report("and 8/16 on the command line."); + lsx_fail_errno(ft,SOX_EFMT,"Bogus AIFF file: no COMM section."); + return(SOX_EOF); + } + + } + ssndsize /= bits >> 3; + + /* Cope with 'sowt' CD tracks as read on Macs */ + if (is_sowt) + ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; + + if (foundmark && !foundinstr) { + lsx_debug("Ignoring MARK chunk since no INSTR found."); + foundmark = 0; + } + if (!foundmark && foundinstr) { + lsx_debug("Ignoring INSTR chunk since no MARK found."); + foundinstr = 0; + } + if (foundmark && foundinstr) { + int i2; + int slbIndex = 0, sleIndex = 0; + int rlbIndex = 0, rleIndex = 0; + + /* find our loop markers and save their marker indexes */ + for(i2 = 0; i2 < nmarks; i2++) { + if(marks[i2].id == sustainLoopBegin) + slbIndex = i2; + if(marks[i2].id == sustainLoopEnd) + sleIndex = i2; + if(marks[i2].id == releaseLoopBegin) + rlbIndex = i2; + if(marks[i2].id == releaseLoopEnd) + rleIndex = i2; + } + + ft->oob.instr.nloops = 0; + if (ft->oob.loops[0].type != 0) { + ft->oob.loops[0].start = marks[slbIndex].position; + ft->oob.loops[0].length = + marks[sleIndex].position - marks[slbIndex].position; + /* really the loop count should be infinite */ + ft->oob.loops[0].count = 1; + ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[0].type; + ft->oob.instr.nloops++; + } + if (ft->oob.loops[1].type != 0) { + ft->oob.loops[1].start = marks[rlbIndex].position; + ft->oob.loops[1].length = + marks[rleIndex].position - marks[rlbIndex].position; + /* really the loop count should be infinite */ + ft->oob.loops[1].count = 1; + ft->oob.instr.loopmode = SOX_LOOP_SUSTAIN_DECAY | ft->oob.loops[1].type; + ft->oob.instr.nloops++; + } + } + reportInstrument(ft); + + return lsx_check_read_params( + ft, channels, rate, enc, bits, (uint64_t)ssndsize, sox_false); +} + +/* print out the MIDI key allocations, loop points, directions etc */ +static void reportInstrument(sox_format_t * ft) +{ + unsigned loopNum; + + if(ft->oob.instr.nloops > 0) + lsx_report("AIFF Loop markers:"); + for(loopNum = 0; loopNum < ft->oob.instr.nloops; loopNum++) { + if (ft->oob.loops[loopNum].count) { + lsx_report("Loop %d: start: %6lu", loopNum, (unsigned long)ft->oob.loops[loopNum].start); + lsx_report(" end: %6lu", + (unsigned long)(ft->oob.loops[loopNum].start + ft->oob.loops[loopNum].length)); + lsx_report(" count: %6d", ft->oob.loops[loopNum].count); + lsx_report(" type: "); + switch(ft->oob.loops[loopNum].type & ~SOX_LOOP_SUSTAIN_DECAY) { + case 0: lsx_report("off"); break; + case 1: lsx_report("forward"); break; + case 2: lsx_report("forward/backward"); break; + } + } + } + lsx_report("Unity MIDI Note: %d", ft->oob.instr.MIDInote); + lsx_report("Low MIDI Note: %d", ft->oob.instr.MIDIlow); + lsx_report("High MIDI Note: %d", ft->oob.instr.MIDIhi); +} + +/* Process a text chunk, allocate memory, display it if verbose and return */ +static int textChunk(char **text, char *chunkDescription, sox_format_t * ft) +{ + uint32_t chunksize0; + size_t chunksize; + lsx_readdw(ft, &chunksize0); + chunksize = chunksize0; + + /* allocate enough memory to hold the text including a terminating \0 */ + if (chunksize != SOX_SIZE_MAX) + *text = lsx_malloc((size_t)chunksize+1); + else + *text = lsx_malloc((size_t)chunksize); + + if (lsx_readbuf(ft, *text, (size_t) chunksize) != chunksize) + { + lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); + return(SOX_EOF); + } + if (chunksize != SOX_SIZE_MAX) + *(*text + chunksize) = '\0'; + else + *(*text + chunksize-1) = '\0'; + if (chunksize % 2) + { + /* Read past pad byte */ + char c; + if (lsx_readbuf(ft, &c, (size_t)1) != 1) + { + lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); + return(SOX_EOF); + } + } + lsx_debug("%-10s \"%s\"", chunkDescription, *text); + return(SOX_SUCCESS); +} + +/* Comment lengths are words, not double words, and we can have several, so + we use a special function, not textChunk().; + */ +static int commentChunk(char **text, char *chunkDescription, sox_format_t * ft) +{ + uint32_t chunksize; + unsigned short numComments; + uint32_t timeStamp; + unsigned short markerId; + unsigned short totalCommentLength = 0; + unsigned int totalReadLength = 0; + unsigned int commentIndex; + + lsx_readdw(ft, &chunksize); + lsx_readw(ft, &numComments); + totalReadLength += 2; /* chunksize doesn't count */ + for(commentIndex = 0; commentIndex < numComments; commentIndex++) { + unsigned short commentLength; + + lsx_readdw(ft, &timeStamp); + lsx_readw(ft, &markerId); + lsx_readw(ft, &commentLength); + if (((size_t)totalCommentLength) + commentLength > USHRT_MAX) { + lsx_fail_errno(ft,SOX_EOF,"AIFF: Comment too long in %s header", chunkDescription); + return(SOX_EOF); + } + totalCommentLength += commentLength; + /* allocate enough memory to hold the text including a terminating \0 */ + if(commentIndex == 0) { + *text = lsx_malloc((size_t) totalCommentLength + 1); + } + else { + *text = lsx_realloc(*text, (size_t) totalCommentLength + 1); + } + + if (lsx_readbuf(ft, *text + totalCommentLength - commentLength, (size_t) commentLength) != commentLength) { + lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); + return(SOX_EOF); + } + *(*text + totalCommentLength) = '\0'; + totalReadLength += totalCommentLength + 4 + 2 + 2; /* include header */ + if (commentLength % 2) { + /* Read past pad byte */ + char c; + if (lsx_readbuf(ft, &c, (size_t)1) != 1) { + lsx_fail_errno(ft,SOX_EOF,"AIFF: Unexpected EOF in %s header", chunkDescription); + return(SOX_EOF); + } + totalReadLength += 1; + } + } + lsx_debug("%-10s \"%s\"", chunkDescription, *text); + /* make sure we read the whole chunk */ + if (totalReadLength < chunksize) { + size_t i; + char c; + for (i=0; i < chunksize - totalReadLength; i++ ) + lsx_readbuf(ft, &c, (size_t)1); + } + return(SOX_SUCCESS); +} + +int lsx_aiffstopread(sox_format_t * ft) +{ + char buf[5]; + uint32_t chunksize; + uint8_t trash; + + if (!ft->seekable) + { + while (! lsx_eof(ft)) + { + if (lsx_readbuf(ft, buf, (size_t)4) != 4) + break; + + lsx_readdw(ft, &chunksize); + if (lsx_eof(ft)) + break; + buf[4] = '\0'; + lsx_warn("Ignoring AIFF tail chunk: `%s', %u bytes long", + buf, chunksize); + if (! strcmp(buf, "MARK") || ! strcmp(buf, "INST")) + lsx_warn(" You're stripping MIDI/loop info!"); + while (chunksize-- > 0) + { + if (lsx_readb(ft, &trash) == SOX_EOF) + break; + } + } + } + return SOX_SUCCESS; +} + +/* When writing, the header is supposed to contain the number of + samples and data bytes written. + Since we don't know how many samples there are until we're done, + we first write the header with an very large number, + and at the end we rewind the file and write the header again + with the right number. This only works if the file is seekable; + if it is not, the very large size remains in the header. + Strictly spoken this is not legal, but the playaiff utility + will still be able to play the resulting file. */ + +int lsx_aiffstartwrite(sox_format_t * ft) +{ + int rc; + + /* Needed because lsx_rawwrite() */ + rc = lsx_rawstartwrite(ft); + if (rc) + return rc; + + /* Compute the "very large number" so that a maximum number + of samples can be transmitted through a pipe without the + risk of causing overflow when calculating the number of bytes. + At 48 kHz, 16 bits stereo, this gives ~3 hours of audio. + Sorry, the AIFF format does not provide for an indefinite + number of samples. */ + return(aiffwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample>>3)*ft->signal.channels))); +} + +int lsx_aiffstopwrite(sox_format_t * ft) +{ + /* If we've written an odd number of bytes, write a padding + NUL */ + if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1) + { + sox_sample_t buf = 0; + lsx_rawwrite(ft, &buf, (size_t) 1); + } + + if (!ft->seekable) + { + lsx_fail_errno(ft,SOX_EOF,"Non-seekable file."); + return(SOX_EOF); + } + if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0) + { + lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFF header"); + return(SOX_EOF); + } + return(aiffwriteheader(ft, ft->olength / ft->signal.channels)); +} + +static int aiffwriteheader(sox_format_t * ft, uint64_t nframes) +{ + int hsize = + 8 /*COMM hdr*/ + 18 /*COMM chunk*/ + + 8 /*SSND hdr*/ + 12 /*SSND chunk*/; + unsigned bits = 0; + unsigned i; + uint64_t size; + size_t padded_comment_size = 0, comment_size = 0; + size_t comment_chunk_size = 0; + char * comment = lsx_cat_comments(ft->oob.comments); + + /* MARK and INST chunks */ + if (ft->oob.instr.nloops) { + hsize += 8 /* MARK hdr */ + 2 + 16*ft->oob.instr.nloops; + hsize += 8 /* INST hdr */ + 20; /* INST chunk */ + } + + if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 8) + bits = 8; + else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 16) + bits = 16; + else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 24) + bits = 24; + else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 32) + bits = 32; + else + { + lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFF header"); + return(SOX_EOF); + } + + /* COMT comment chunk -- holds comments text with a timestamp and marker id */ + /* We calculate the comment_chunk_size if we will be writing a comment */ + if (ft->oob.comments) + { + comment_size = strlen(comment); + /* Must put an even number of characters out. + * True 68k processors OS's seem to require this. + */ + padded_comment_size = ((comment_size % 2) == 0) ? + comment_size : comment_size + 1; + /* one comment, timestamp, marker ID and text count */ + comment_chunk_size = (2 + 4 + 2 + 2 + padded_comment_size); + hsize += 8 /* COMT hdr */ + comment_chunk_size; + } + + lsx_writes(ft, "FORM"); /* IFF header */ + /* file size */ + size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels; + if (size > UINT_MAX) + { + lsx_warn("file size too big for accurate AIFF header"); + size = UINT_MAX; + } + lsx_writedw(ft, (unsigned)size); + lsx_writes(ft, "AIFF"); /* File type */ + + /* Now we write the COMT comment chunk using the precomputed sizes */ + if (ft->oob.comments) + { + lsx_writes(ft, "COMT"); + lsx_writedw(ft, (unsigned) comment_chunk_size); + + /* one comment */ + lsx_writew(ft, 1); + + /* time stamp of comment, Unix knows of time from 1/1/1970, + Apple knows time from 1/1/1904 */ + lsx_writedw(ft, (unsigned)((sox_globals.repeatable? 0 : time(NULL)) + 2082844800)); + + /* A marker ID of 0 indicates the comment is not associated + with a marker */ + lsx_writew(ft, 0); + + /* now write the count and the bytes of text */ + lsx_writew(ft, (unsigned) padded_comment_size); + lsx_writes(ft, comment); + if (comment_size != padded_comment_size) + lsx_writes(ft, " "); + } + free(comment); + + /* COMM chunk -- describes encoding (and #frames) */ + lsx_writes(ft, "COMM"); + lsx_writedw(ft, 18); /* COMM chunk size */ + lsx_writew(ft, ft->signal.channels); /* nchannels */ + lsx_writedw(ft, (unsigned) nframes); /* number of frames */ + lsx_writew(ft, bits); /* sample width, in bits */ + write_ieee_extended(ft, (double)ft->signal.rate); + + /* MARK chunk -- set markers */ + if (ft->oob.instr.nloops) { + lsx_writes(ft, "MARK"); + if (ft->oob.instr.nloops > 2) + ft->oob.instr.nloops = 2; + lsx_writedw(ft, 2 + 16u*ft->oob.instr.nloops); + lsx_writew(ft, ft->oob.instr.nloops); + + for(i = 0; i < ft->oob.instr.nloops; i++) { + unsigned start = ft->oob.loops[i].start > UINT_MAX + ? UINT_MAX + : ft->oob.loops[i].start; + unsigned end = ft->oob.loops[i].start + ft->oob.loops[i].length > UINT_MAX + ? UINT_MAX + : ft->oob.loops[i].start + ft->oob.loops[i].length; + lsx_writew(ft, i + 1); + lsx_writedw(ft, start); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writew(ft, i*2 + 1); + lsx_writedw(ft, end); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + } + + lsx_writes(ft, "INST"); + lsx_writedw(ft, 20); + /* random MIDI shit that we default on */ + lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDInote); + lsx_writeb(ft, 0); /* detune */ + lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIlow); + lsx_writeb(ft, (uint8_t)ft->oob.instr.MIDIhi); + lsx_writeb(ft, 1); /* low velocity */ + lsx_writeb(ft, 127); /* hi velocity */ + lsx_writew(ft, 0); /* gain */ + + /* sustain loop */ + lsx_writew(ft, ft->oob.loops[0].type); + lsx_writew(ft, 1); /* marker 1 */ + lsx_writew(ft, 3); /* marker 3 */ + /* release loop, if there */ + if (ft->oob.instr.nloops == 2) { + lsx_writew(ft, ft->oob.loops[1].type); + lsx_writew(ft, 2); /* marker 2 */ + lsx_writew(ft, 4); /* marker 4 */ + } else { + lsx_writew(ft, 0); /* no release loop */ + lsx_writew(ft, 0); + lsx_writew(ft, 0); + } + } + + /* SSND chunk -- describes data */ + lsx_writes(ft, "SSND"); + /* chunk size */ + lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3))); + lsx_writedw(ft, 0); /* offset */ + lsx_writedw(ft, 0); /* block size */ + return(SOX_SUCCESS); +} + +int lsx_aifcstartwrite(sox_format_t * ft) +{ + int rc; + + /* Needed because lsx_rawwrite() */ + rc = lsx_rawstartwrite(ft); + if (rc) + return rc; + + /* Compute the "very large number" so that a maximum number + of samples can be transmitted through a pipe without the + risk of causing overflow when calculating the number of bytes. + At 48 kHz, 16 bits stereo, this gives ~3 hours of music. + Sorry, the AIFC format does not provide for an "infinite" + number of samples. */ + return(aifcwriteheader(ft, (uint64_t) 0x7f000000 / ((ft->encoding.bits_per_sample >> 3)*ft->signal.channels))); +} + +int lsx_aifcstopwrite(sox_format_t * ft) +{ + /* If we've written an odd number of bytes, write a padding + NUL */ + if (ft->olength % 2 == 1 && ft->encoding.bits_per_sample == 8 && ft->signal.channels == 1) + { + sox_sample_t buf = 0; + lsx_rawwrite(ft, &buf, (size_t) 1); + } + + if (!ft->seekable) + { + lsx_fail_errno(ft,SOX_EOF,"Non-seekable file."); + return(SOX_EOF); + } + if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0) + { + lsx_fail_errno(ft,errno,"can't rewind output file to rewrite AIFC header"); + return(SOX_EOF); + } + return(aifcwriteheader(ft, ft->olength / ft->signal.channels)); +} + +static int aifcwriteheader(sox_format_t * ft, uint64_t nframes) +{ + unsigned hsize; + unsigned bits = 0; + uint64_t size; + char *ctype = NULL, *cname = NULL; + unsigned cname_len = 0, comm_len = 0, comm_padding = 0; + + if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 8) + bits = 8; + else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 16) + bits = 16; + else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 24) + bits = 24; + else if (ft->encoding.encoding == SOX_ENCODING_SIGN2 && + ft->encoding.bits_per_sample == 32) + bits = 32; + else if (ft->encoding.encoding == SOX_ENCODING_FLOAT && + ft->encoding.bits_per_sample == 32) + bits = 32; + else if (ft->encoding.encoding == SOX_ENCODING_FLOAT && + ft->encoding.bits_per_sample == 64) + bits = 64; + else + { + lsx_fail_errno(ft,SOX_EFMT,"unsupported output encoding/size for AIFC header"); + return(SOX_EOF); + } + + /* calculate length of COMM chunk (without header) */ + switch (ft->encoding.encoding) { + case SOX_ENCODING_SIGN2: + ctype = "NONE"; + cname = "not compressed"; + break; + case SOX_ENCODING_FLOAT: + if (bits == 32) { + ctype = "fl32"; + cname = "32-bit floating point"; + } else { + ctype = "fl64"; + cname = "64-bit floating point"; + } + break; + default: /* can't happen */ + break; + } + cname_len = strlen(cname); + comm_len = 18+4+1+cname_len; + comm_padding = comm_len%2; + + hsize = 12 /*FVER*/ + 8 /*COMM hdr*/ + comm_len+comm_padding /*COMM chunk*/ + + 8 /*SSND hdr*/ + 12 /*SSND chunk*/; + + lsx_writes(ft, "FORM"); /* IFF header */ + /* file size */ + size = hsize + nframes * (ft->encoding.bits_per_sample >> 3) * ft->signal.channels; + if (size > UINT_MAX) + { + lsx_warn("file size too big for accurate AIFC header"); + size = UINT_MAX; + } + lsx_writedw(ft, (unsigned)size); + lsx_writes(ft, "AIFC"); /* File type */ + + /* FVER chunk */ + lsx_writes(ft, "FVER"); + lsx_writedw(ft, 4); /* FVER chunk size */ + lsx_writedw(ft, 0xa2805140); /* version_date(May23,1990,2:40pm) */ + + /* COMM chunk -- describes encoding (and #frames) */ + lsx_writes(ft, "COMM"); + lsx_writedw(ft, comm_len+comm_padding); /* COMM chunk size */ + lsx_writew(ft, ft->signal.channels); /* nchannels */ + lsx_writedw(ft, (unsigned) nframes); /* number of frames */ + lsx_writew(ft, bits); /* sample width, in bits */ + write_ieee_extended(ft, (double)ft->signal.rate); + + lsx_writes(ft, ctype); /*compression_type*/ + lsx_writeb(ft, cname_len); + lsx_writes(ft, cname); + if (comm_padding) + lsx_writeb(ft, 0); + + /* SSND chunk -- describes data */ + lsx_writes(ft, "SSND"); + /* chunk size */ + lsx_writedw(ft, (unsigned) (8 + nframes * ft->signal.channels * (ft->encoding.bits_per_sample >> 3))); + lsx_writedw(ft, 0); /* offset */ + lsx_writedw(ft, 0); /* block size */ + + /* Any Private chunks shall appear after the required chunks (FORM,FVER,COMM,SSND) */ + return(SOX_SUCCESS); +} + +static double read_ieee_extended(sox_format_t * ft) +{ + unsigned char buf[10]; + if (lsx_readbuf(ft, buf, (size_t)10) != 10) + { + lsx_fail_errno(ft,SOX_EOF,"EOF while reading IEEE extended number"); + return(SOX_EOF); + } + return ConvertFromIeeeExtended(buf); +} + +static void write_ieee_extended(sox_format_t * ft, double x) +{ + char buf[10]; + ConvertToIeeeExtended(x, buf); + lsx_debug_more("converted %g to %o %o %o %o %o %o %o %o %o %o", + x, + buf[0], buf[1], buf[2], buf[3], buf[4], + buf[5], buf[6], buf[7], buf[8], buf[9]); + (void)lsx_writebuf(ft, buf, (size_t) 10); +} + + +/* + * C O N V E R T T O I E E E E X T E N D E D + */ + +/* Copyright (C) 1988-1991 Apple Computer, Inc. + * + * All rights reserved. + * + * Warranty Information + * Even though Apple has reviewed this software, Apple makes no warranty + * or representation, either express or implied, with respect to this + * software, its quality, accuracy, merchantability, or fitness for a + * particular purpose. As a result, this software is provided "as is," + * and you, its user, are assuming the entire risk as to its quality + * and accuracy. + * + * Machine-independent I/O routines for IEEE floating-point numbers. + * + * NaN's and infinities are converted to HUGE_VAL, which + * happens to be infinity on IEEE machines. Unfortunately, it is + * impossible to preserve NaN's in a machine-independent way. + * Infinities are, however, preserved on IEEE machines. + * + * These routines have been tested on the following machines: + * Apple Macintosh, MPW 3.1 C compiler + * Apple Macintosh, THINK C compiler + * Silicon Graphics IRIS, MIPS compiler + * Cray X/MP and Y/MP + * Digital Equipment VAX + * + * + * Implemented by Malcolm Slaney and Ken Turkowski. + * + * Malcolm Slaney contributions during 1988-1990 include big- and little- + * endian file I/O, conversion to and from Motorola's extended 80-bit + * floating-point format, and conversions to and from IEEE single- + * precision floating-point format. + * + * In 1991, Ken Turkowski implemented the conversions to and from + * IEEE double-precision format, added more precision to the extended + * conversions, and accommodated conversions involving +/- infinity, + * NaN's, and denormalized numbers. + */ + +#define FloatToUnsigned(f) ((uint32_t)(((int32_t)(f - 2147483648.0)) + 2147483647) + 1) + +static void ConvertToIeeeExtended(double num, char *bytes) +{ + int sign; + int expon; + double fMant, fsMant; + uint32_t hiMant, loMant; + + if (num < 0) { + sign = 0x8000; + num *= -1; + } else { + sign = 0; + } + + if (num == 0) { + expon = 0; hiMant = 0; loMant = 0; + } + else { + fMant = frexp(num, &expon); + if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */ + expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */ + } + else { /* Finite */ + expon += 16382; + if (expon < 0) { /* denormalized */ + fMant = ldexp(fMant, expon); + expon = 0; + } + expon |= sign; + fMant = ldexp(fMant, 32); + fsMant = floor(fMant); + hiMant = FloatToUnsigned(fsMant); + fMant = ldexp(fMant - fsMant, 32); + fsMant = floor(fMant); + loMant = FloatToUnsigned(fsMant); + } + } + + bytes[0] = expon >> 8; + bytes[1] = expon; + bytes[2] = hiMant >> 24; + bytes[3] = hiMant >> 16; + bytes[4] = hiMant >> 8; + bytes[5] = hiMant; + bytes[6] = loMant >> 24; + bytes[7] = loMant >> 16; + bytes[8] = loMant >> 8; + bytes[9] = loMant; +} + + +/* + * C O N V E R T F R O M I E E E E X T E N D E D + */ + +/* + * Copyright (C) 1988-1991 Apple Computer, Inc. + * + * All rights reserved. + * + * Warranty Information + * Even though Apple has reviewed this software, Apple makes no warranty + * or representation, either express or implied, with respect to this + * software, its quality, accuracy, merchantability, or fitness for a + * particular purpose. As a result, this software is provided "as is," + * and you, its user, are assuming the entire risk as to its quality + * and accuracy. + * + * This code may be used and freely distributed as long as it includes + * this copyright notice and the above warranty information. + * + * Machine-independent I/O routines for IEEE floating-point numbers. + * + * NaN's and infinities are converted to HUGE_VAL, which + * happens to be infinity on IEEE machines. Unfortunately, it is + * impossible to preserve NaN's in a machine-independent way. + * Infinities are, however, preserved on IEEE machines. + * + * These routines have been tested on the following machines: + * Apple Macintosh, MPW 3.1 C compiler + * Apple Macintosh, THINK C compiler + * Silicon Graphics IRIS, MIPS compiler + * Cray X/MP and Y/MP + * Digital Equipment VAX + * + * + * Implemented by Malcolm Slaney and Ken Turkowski. + * + * Malcolm Slaney contributions during 1988-1990 include big- and little- + * endian file I/O, conversion to and from Motorola's extended 80-bit + * floating-point format, and conversions to and from IEEE single- + * precision floating-point format. + * + * In 1991, Ken Turkowski implemented the conversions to and from + * IEEE double-precision format, added more precision to the extended + * conversions, and accommodated conversions involving +/- infinity, + * NaN's, and denormalized numbers. + */ + +#define UnsignedToFloat(u) (((double)((int32_t)(u - 2147483647 - 1))) + 2147483648.0) + +/**************************************************************** + * Extended precision IEEE floating-point conversion routine. + ****************************************************************/ + +static double ConvertFromIeeeExtended(unsigned char *bytes) +{ + double f; + int expon; + uint32_t hiMant, loMant; + + expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); + hiMant = ((uint32_t)(bytes[2] & 0xFF) << 24) + | ((uint32_t)(bytes[3] & 0xFF) << 16) + | ((uint32_t)(bytes[4] & 0xFF) << 8) + | ((uint32_t)(bytes[5] & 0xFF)); + loMant = ((uint32_t)(bytes[6] & 0xFF) << 24) + | ((uint32_t)(bytes[7] & 0xFF) << 16) + | ((uint32_t)(bytes[8] & 0xFF) << 8) + | ((uint32_t)(bytes[9] & 0xFF)); + + if (expon == 0 && hiMant == 0 && loMant == 0) { + f = 0; + } + else { + if (expon == 0x7FFF) { /* Infinity or NaN */ + f = HUGE_VAL; + } + else { + expon -= 16383; + f = ldexp(UnsignedToFloat(hiMant), expon-=31); + f += ldexp(UnsignedToFloat(loMant), expon-=32); + } + } + + if (bytes[0] & 0x80) + return -f; + else + return f; +} diff --git a/app/src/main/cpp/sox/aiff.h b/app/src/main/cpp/sox/aiff.h new file mode 100644 index 0000000..471de06 --- /dev/null +++ b/app/src/main/cpp/sox/aiff.h @@ -0,0 +1,22 @@ +/* libSoX SGI/Amiga AIFF format. + * Copyright 1991-2007 Guido van Rossum And Sundry Contributors + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Guido van Rossum And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * Used by SGI on 4D/35 and Indigo. + * This is a subformat of the EA-IFF-85 format. + * This is related to the IFF format used by the Amiga. + * But, apparently, not the same. + * Also AIFF-C format output that is defined in DAVIC 1.4 Part 9 Annex B + * (usable for japanese-data-broadcasting, specified by ARIB STD-B24.) + */ + +int lsx_aiffstartread(sox_format_t * ft); +int lsx_aiffstopread(sox_format_t * ft); +int lsx_aiffstartwrite(sox_format_t * ft); +int lsx_aiffstopwrite(sox_format_t * ft); +int lsx_aifcstartwrite(sox_format_t * ft); +int lsx_aifcstopwrite(sox_format_t * ft); diff --git a/app/src/main/cpp/sox/al-fmt.c b/app/src/main/cpp/sox/al-fmt.c new file mode 100644 index 0000000..fddf94d --- /dev/null +++ b/app/src/main/cpp/sox/al-fmt.c @@ -0,0 +1,21 @@ +/* File format: raw A-law (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT(al, 8, 0, ALAW) diff --git a/app/src/main/cpp/sox/alsa.c b/app/src/main/cpp/sox/alsa.c new file mode 100644 index 0000000..daf040a --- /dev/null +++ b/app/src/main/cpp/sox/alsa.c @@ -0,0 +1,379 @@ +/* libSoX device driver: ALSA (c) 2006-2012 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +typedef struct { + snd_pcm_uframes_t buf_len, period; + snd_pcm_t * pcm; + char * buf; + unsigned int format; +} priv_t; + +static const + struct { + unsigned int bits; + enum _snd_pcm_format alsa_fmt; + unsigned int bytes; /* occupied in the buffer per sample */ + sox_encoding_t enc; + } formats[] = { + /* order by # of bits; within that, preferred first */ + { 8, SND_PCM_FORMAT_S8, 1, SOX_ENCODING_SIGN2 }, + { 8, SND_PCM_FORMAT_U8, 1, SOX_ENCODING_UNSIGNED }, + { 16, SND_PCM_FORMAT_S16, 2, SOX_ENCODING_SIGN2 }, + { 16, SND_PCM_FORMAT_U16, 2, SOX_ENCODING_UNSIGNED }, + { 24, SND_PCM_FORMAT_S24, 4, SOX_ENCODING_SIGN2 }, + { 24, SND_PCM_FORMAT_U24, 4, SOX_ENCODING_UNSIGNED }, + { 24, SND_PCM_FORMAT_S24_3LE, 3, SOX_ENCODING_SIGN2 }, + { 32, SND_PCM_FORMAT_S32, 4, SOX_ENCODING_SIGN2 }, + { 32, SND_PCM_FORMAT_U32, 4, SOX_ENCODING_UNSIGNED }, + { 0, 0, 0, SOX_ENCODING_UNKNOWN } /* end of list */ + }; + +static int select_format( + sox_encoding_t * encoding_, + unsigned * nbits_, + snd_pcm_format_mask_t const * mask, + unsigned int * format) +{ + unsigned int from = 0, to; /* NB: "to" actually points one after the last */ + int cand = -1; + + while (formats[from].bits < *nbits_ && formats[from].bits != 0) + from++; /* find the first entry with at least *nbits_ bits */ + for (to = from; formats[to].bits != 0; to++) ; /* find end of list */ + + while (to > 0) { + unsigned int i, bits_next = 0; + for (i = from; i < to; i++) { + lsx_debug_most("select_format: trying #%u", i); + if (snd_pcm_format_mask_test(mask, formats[i].alsa_fmt)) { + if (formats[i].enc == *encoding_) { + cand = i; + break; /* found a match */ + } else if (cand == -1) /* don't overwrite a candidate that + was earlier in the list */ + cand = i; /* will work, but encoding differs */ + } + } + if (cand != -1) + break; + /* no candidate found yet; now try formats with less bits: */ + to = from; + if (from > 0) + bits_next = formats[from-1].bits; + while (from && formats[from-1].bits == bits_next) + from--; /* go back to the first entry with bits_next bits */ + } + + if (cand == -1) { + lsx_debug("select_format: no suitable ALSA format found"); + return -1; + } + + if (*nbits_ != formats[cand].bits || *encoding_ != formats[cand].enc) { + lsx_warn("can't encode %u-bit %s", *nbits_, + sox_encodings_info[*encoding_].desc); + *nbits_ = formats[cand].bits; + *encoding_ = formats[cand].enc; + } + lsx_debug("selecting format %d: %s (%s)", cand, + snd_pcm_format_name(formats[cand].alsa_fmt), + snd_pcm_format_description(formats[cand].alsa_fmt)); + *format = cand; + return 0; +} + +#define _(x,y) do {if ((err = x y) < 0) {lsx_fail_errno(ft, SOX_EPERM, #x " error: %s", snd_strerror(err)); goto error;} } while (0) +static int setup(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + snd_pcm_hw_params_t * params = NULL; + snd_pcm_format_mask_t * mask = NULL; + snd_pcm_uframes_t min, max; + unsigned n; + int err; + + _(snd_pcm_open, (&p->pcm, ft->filename, ft->mode == 'r'? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0)); + _(snd_pcm_hw_params_malloc, (¶ms)); + _(snd_pcm_hw_params_any, (p->pcm, params)); +#if SND_LIB_VERSION >= 0x010009 /* Disable alsa-lib resampling: */ + _(snd_pcm_hw_params_set_rate_resample, (p->pcm, params, 0)); +#endif + _(snd_pcm_hw_params_set_access, (p->pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED)); + + _(snd_pcm_format_mask_malloc, (&mask)); /* Set format: */ + snd_pcm_hw_params_get_format_mask(params, mask); + _(select_format, (&ft->encoding.encoding, &ft->encoding.bits_per_sample, mask, &p->format)); + _(snd_pcm_hw_params_set_format, (p->pcm, params, formats[p->format].alsa_fmt)); + snd_pcm_format_mask_free(mask), mask = NULL; + + n = ft->signal.rate; /* Set rate: */ + _(snd_pcm_hw_params_set_rate_near, (p->pcm, params, &n, 0)); + ft->signal.rate = n; + + n = ft->signal.channels; /* Set channels: */ + _(snd_pcm_hw_params_set_channels_near, (p->pcm, params, &n)); + ft->signal.channels = n; + + /* Get number of significant bits: */ + if ((err = snd_pcm_hw_params_get_sbits(params)) > 0) + ft->signal.precision = min(err, SOX_SAMPLE_PRECISION); + else lsx_debug("snd_pcm_hw_params_get_sbits can't tell precision: %s", + snd_strerror(err)); + + /* Set buf_len > > sox_globals.bufsiz for no underrun: */ + p->buf_len = sox_globals.bufsiz * 8 / formats[p->format].bytes / + ft->signal.channels; + _(snd_pcm_hw_params_get_buffer_size_min, (params, &min)); + _(snd_pcm_hw_params_get_buffer_size_max, (params, &max)); + p->period = range_limit(p->buf_len, min, max) / 8; + p->buf_len = p->period * 8; + _(snd_pcm_hw_params_set_period_size_near, (p->pcm, params, &p->period, 0)); + _(snd_pcm_hw_params_set_buffer_size_near, (p->pcm, params, &p->buf_len)); + if (p->period * 2 > p->buf_len) { + lsx_fail_errno(ft, SOX_EPERM, "buffer too small"); + goto error; + } + + _(snd_pcm_hw_params, (p->pcm, params)); /* Configure ALSA */ + snd_pcm_hw_params_free(params), params = NULL; + _(snd_pcm_prepare, (p->pcm)); + p->buf_len *= ft->signal.channels; /* No longer in `frames' */ + p->buf = lsx_malloc(p->buf_len * formats[p->format].bytes); + return SOX_SUCCESS; + +error: + if (mask) snd_pcm_format_mask_free(mask); + if (params) snd_pcm_hw_params_free(params); + return SOX_EOF; +} + +static int recover(sox_format_t * ft, snd_pcm_t * pcm, int err) +{ + if (err == -EPIPE) + lsx_warn("%s-run", ft->mode == 'r'? "over" : "under"); + else if (err != -ESTRPIPE) + lsx_warn("%s", snd_strerror(err)); + else while ((err = snd_pcm_resume(pcm)) == -EAGAIN) { + lsx_report("suspended"); + sleep(1); /* Wait until the suspend flag is released */ + } + if (err < 0 && (err = snd_pcm_prepare(pcm)) < 0) + lsx_fail_errno(ft, SOX_EPERM, "%s", snd_strerror(err)); + return err; +} + +static size_t read_(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + priv_t * p = (priv_t *)ft->priv; + snd_pcm_sframes_t i, n; + size_t done; + + len = min(len, p->buf_len); + for (done = 0; done < len; done += n) { + do { + n = snd_pcm_readi(p->pcm, p->buf, (len - done) / ft->signal.channels); + if (n < 0 && recover(ft, p->pcm, (int)n) < 0) + return 0; + } while (n <= 0); + + i = n *= ft->signal.channels; + switch (formats[p->format].alsa_fmt) { + case SND_PCM_FORMAT_S8: { + int8_t * buf1 = (int8_t *)p->buf; + while (i--) *buf++ = SOX_SIGNED_8BIT_TO_SAMPLE(*buf1++,); + break; + } + case SND_PCM_FORMAT_U8: { + uint8_t * buf1 = (uint8_t *)p->buf; + while (i--) *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(*buf1++,); + break; + } + case SND_PCM_FORMAT_S16: { + int16_t * buf1 = (int16_t *)p->buf; + if (ft->encoding.reverse_bytes) while (i--) + *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),); + else + while (i--) *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(*buf1++,); + break; + } + case SND_PCM_FORMAT_U16: { + uint16_t * buf1 = (uint16_t *)p->buf; + if (ft->encoding.reverse_bytes) while (i--) + *buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(lsx_swapw(*buf1++),); + else + while (i--) *buf++ = SOX_UNSIGNED_16BIT_TO_SAMPLE(*buf1++,); + break; + } + case SND_PCM_FORMAT_S24: { + sox_int24_t * buf1 = (sox_int24_t *)p->buf; + while (i--) *buf++ = SOX_SIGNED_24BIT_TO_SAMPLE(*buf1++,); + break; + } + case SND_PCM_FORMAT_S24_3LE: { + unsigned char *buf1 = (unsigned char *)p->buf; + while (i--) { + uint32_t temp; + temp = *buf1++; + temp |= *buf1++ << 8; + temp |= *buf1++ << 16; + *buf++ = SOX_SIGNED_24BIT_TO_SAMPLE((sox_int24_t)temp,); + } + break; + } + case SND_PCM_FORMAT_U24: { + sox_uint24_t * buf1 = (sox_uint24_t *)p->buf; + while (i--) *buf++ = SOX_UNSIGNED_24BIT_TO_SAMPLE(*buf1++,); + break; + } + case SND_PCM_FORMAT_S32: { + int32_t * buf1 = (int32_t *)p->buf; + while (i--) *buf++ = SOX_SIGNED_32BIT_TO_SAMPLE(*buf1++,); + break; + } + case SND_PCM_FORMAT_U32: { + uint32_t * buf1 = (uint32_t *)p->buf; + while (i--) *buf++ = SOX_UNSIGNED_32BIT_TO_SAMPLE(*buf1++,); + break; + } + default: lsx_fail_errno(ft, SOX_EFMT, "invalid format"); + return 0; + } + } + return len; +} + +static size_t write_(sox_format_t * ft, sox_sample_t const * buf, size_t len) +{ + priv_t * p = (priv_t *)ft->priv; + size_t done, i, n; + snd_pcm_sframes_t actual; + SOX_SAMPLE_LOCALS; + + for (done = 0; done < len; done += n) { + i = n = min(len - done, p->buf_len); + switch (formats[p->format].alsa_fmt) { + case SND_PCM_FORMAT_S8: { + int8_t * buf1 = (int8_t *)p->buf; + while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_8BIT(*buf++, ft->clips); + break; + } + case SND_PCM_FORMAT_U8: { + uint8_t * buf1 = (uint8_t *)p->buf; + while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips); + break; + } + case SND_PCM_FORMAT_S16: { + int16_t * buf1 = (int16_t *)p->buf; + if (ft->encoding.reverse_bytes) while (i--) + *buf1++ = lsx_swapw(SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips)); + else + while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips); + break; + } + case SND_PCM_FORMAT_U16: { + uint16_t * buf1 = (uint16_t *)p->buf; + if (ft->encoding.reverse_bytes) while (i--) + *buf1++ = lsx_swapw(SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips)); + else + while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_16BIT(*buf++, ft->clips); + break; + } + case SND_PCM_FORMAT_S24: { + sox_int24_t * buf1 = (sox_int24_t *)p->buf; + while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips); + break; + } + case SND_PCM_FORMAT_S24_3LE: { + unsigned char *buf1 = (unsigned char *)p->buf; + while (i--) { + uint32_t temp = (uint32_t)SOX_SAMPLE_TO_SIGNED_24BIT(*buf++, ft->clips); + *buf1++ = (temp & 0x000000FF); + *buf1++ = (temp & 0x0000FF00) >> 8; + *buf1++ = (temp & 0x00FF0000) >> 16; + } + break; + } + case SND_PCM_FORMAT_U24: { + sox_uint24_t * buf1 = (sox_uint24_t *)p->buf; + while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_24BIT(*buf++, ft->clips); + break; + } + case SND_PCM_FORMAT_S32: { + int32_t * buf1 = (int32_t *)p->buf; + while (i--) *buf1++ = SOX_SAMPLE_TO_SIGNED_32BIT(*buf++, ft->clips); + break; + } + case SND_PCM_FORMAT_U32: { + uint32_t * buf1 = (uint32_t *)p->buf; + while (i--) *buf1++ = SOX_SAMPLE_TO_UNSIGNED_32BIT(*buf++, ft->clips); + break; + } + default: lsx_fail_errno(ft, SOX_EFMT, "invalid format"); + return 0; + } + for (i = 0; i < n; i += actual * ft->signal.channels) do { + actual = snd_pcm_writei(p->pcm, + p->buf + i * formats[p->format].bytes, + (n - i) / ft->signal.channels); + if (errno == EAGAIN) /* Happens naturally; don't report it: */ + errno = 0; + if (actual < 0 && recover(ft, p->pcm, (int)actual) < 0) + return 0; + } while (actual < 0); + } + return len; +} + +static int stop(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + snd_pcm_close(p->pcm); + free(p->buf); + return SOX_SUCCESS; +} + +static int stop_write(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + size_t n = ft->signal.channels * p->period, npad = n - (ft->olength % n); + sox_sample_t * buf = lsx_calloc(npad, sizeof(*buf)); /* silent samples */ + + if (npad != n) /* pad to hardware period: */ + write_(ft, buf, npad); + free(buf); + snd_pcm_drain(p->pcm); + return stop(ft); +} + +LSX_FORMAT_HANDLER(alsa) +{ + static char const * const names[] = {"alsa", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2 , 32, 24, 16, 8, 0, + SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Advanced Linux Sound Architecture device driver", + names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + setup, read_, stop, setup, write_, stop_write, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/amr-nb.c b/app/src/main/cpp/sox/amr-nb.c new file mode 100644 index 0000000..b4181ce --- /dev/null +++ b/app/src/main/cpp/sox/amr-nb.c @@ -0,0 +1,90 @@ +/* File format: AMR-NB (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * In order to use the AMR format with SoX, you need to have an + * AMR library installed at SoX build time. The SoX build system + * recognizes the AMR implementations available from + * http://opencore-amr.sourceforge.net/ + */ + +#include "sox_i.h" + +/* Common definitions: */ + +enum amrnb_mode { amrnb_mode_dummy }; + +static const unsigned amrnb_block_size[] = {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1}; +static char const amrnb_magic[] = "#!AMR\n"; +#define amr_block_size amrnb_block_size +#define amr_magic amrnb_magic +#define amr_priv_t amrnb_priv_t +#define amr_opencore_funcs amrnb_opencore_funcs +#define amr_gp3_funcs amrnb_gp3_funcs + +#define AMR_CODED_MAX 32 /* max coded size */ +#define AMR_ENCODING SOX_ENCODING_AMR_NB +#define AMR_FORMAT_FN lsx_amr_nb_format_fn +#define AMR_FRAME 160 /* 20ms @ 8kHz */ +#define AMR_MODE_MAX 7 +#define AMR_NAMES "amr-nb", "anb" +#define AMR_RATE 8000 +#define AMR_DESC "3GPP Adaptive Multi Rate Narrow-Band (AMR-NB) lossy speech compressor" + +#ifdef DL_OPENCORE_AMRNB + #define AMR_FUNC LSX_DLENTRY_DYNAMIC +#else + #define AMR_FUNC LSX_DLENTRY_STATIC +#endif /* DL_AMRNB */ + +/* OpenCore definitions: */ + +#define AMR_OPENCORE 1 +#define AMR_OPENCORE_ENABLE_ENCODE 1 + +#define AMR_OPENCORE_FUNC_ENTRIES(f,x) \ + AMR_FUNC(f,x, void*, Encoder_Interface_init, (int dtx)) \ + AMR_FUNC(f,x, int, Encoder_Interface_Encode, (void* state, enum amrnb_mode mode, const short* in, unsigned char* out, int forceSpeech)) \ + AMR_FUNC(f,x, void, Encoder_Interface_exit, (void* state)) \ + AMR_FUNC(f,x, void*, Decoder_Interface_init, (void)) \ + AMR_FUNC(f,x, void, Decoder_Interface_Decode, (void* state, const unsigned char* in, short* out, int bfi)) \ + AMR_FUNC(f,x, void, Decoder_Interface_exit, (void* state)) \ + +#define AmrEncoderInit() \ + Encoder_Interface_init(1) +#define AmrEncoderEncode(state, mode, in, out, forceSpeech) \ + Encoder_Interface_Encode(state, mode, in, out, forceSpeech) +#define AmrEncoderExit(state) \ + Encoder_Interface_exit(state) +#define AmrDecoderInit() \ + Decoder_Interface_init() +#define AmrDecoderDecode(state, in, out, bfi) \ + Decoder_Interface_Decode(state, in, out, bfi) +#define AmrDecoderExit(state) \ + Decoder_Interface_exit(state) + +#define AMR_OPENCORE_DESC "amr-nb OpenCore library" +static const char* const amr_opencore_library_names[] = +{ +#ifdef DL_OPENCORE_AMRNB + "libopencore-amrnb", + "libopencore-amrnb-0", +#endif + NULL +}; + +#include "amr.h" diff --git a/app/src/main/cpp/sox/amr-wb.c b/app/src/main/cpp/sox/amr-wb.c new file mode 100644 index 0000000..7824f67 --- /dev/null +++ b/app/src/main/cpp/sox/amr-wb.c @@ -0,0 +1,115 @@ +/* File format: AMR-WB (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * In order to use the AMR format with SoX, you need to have an + * AMR library installed at SoX build time. The SoX build system + * recognizes the AMR implementations available from + * http://opencore-amr.sourceforge.net/ + */ + +#include "sox_i.h" + +/* Common definitions: */ + +static const uint8_t amrwb_block_size[] = {18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1}; +static char const amrwb_magic[] = "#!AMR-WB\n"; +#define amr_block_size amrwb_block_size +#define amr_magic amrwb_magic +#define amr_priv_t amrwb_priv_t +#define amr_opencore_funcs amrwb_opencore_funcs +#define amr_vo_funcs amrwb_vo_funcs + +#define AMR_CODED_MAX 61 /* NB_SERIAL_MAX */ +#define AMR_ENCODING SOX_ENCODING_AMR_WB +#define AMR_FORMAT_FN lsx_amr_wb_format_fn +#define AMR_FRAME 320 /* L_FRAME16k */ +#define AMR_MODE_MAX 8 +#define AMR_NAMES "amr-wb", "awb" +#define AMR_RATE 16000 +#define AMR_DESC "3GPP Adaptive Multi Rate Wide-Band (AMR-WB) lossy speech compressor" + +/* OpenCore definitions: */ + +#ifdef DL_OPENCORE_AMRWB + #define AMR_OC_FUNC LSX_DLENTRY_DYNAMIC +#else + #define AMR_OC_FUNC LSX_DLENTRY_STATIC +#endif + +#if defined(HAVE_OPENCORE_AMRWB_DEC_IF_H) || defined(DL_OPENCORE_AMRWB) + #define AMR_OPENCORE 1 + #define AMR_OPENCORE_ENABLE_ENCODE 0 +#endif + +#define AMR_OPENCORE_FUNC_ENTRIES(f,x) \ + AMR_OC_FUNC(f,x, void*, D_IF_init, (void)) \ + AMR_OC_FUNC(f,x, void, D_IF_decode, (void* state, const unsigned char* in, short* out, int bfi)) \ + AMR_OC_FUNC(f,x, void, D_IF_exit, (void* state)) \ + +#define AmrDecoderInit() \ + D_IF_init() +#define AmrDecoderDecode(state, in, out, bfi) \ + D_IF_decode(state, in, out, bfi) +#define AmrDecoderExit(state) \ + D_IF_exit(state) + +#define AMR_OPENCORE_DESC "amr-wb OpenCore library" +static const char* const amr_opencore_library_names[] = +{ +#ifdef DL_OPENCORE_AMRWB + "libopencore-amrwb", + "libopencore-amrwb-0", +#endif + NULL +}; + +/* VO definitions: */ + +#ifdef DL_VO_AMRWBENC + #define AMR_VO_FUNC LSX_DLENTRY_DYNAMIC +#else + #define AMR_VO_FUNC LSX_DLENTRY_STATIC +#endif + +#if defined(HAVE_VO_AMRWBENC_ENC_IF_H) || defined(DL_VO_AMRWBENC) + #define AMR_VO 1 +#endif + +#define AMR_VO_FUNC_ENTRIES(f,x) \ + AMR_VO_FUNC(f,x, void*, E_IF_init, (void)) \ + AMR_VO_FUNC(f,x, int, E_IF_encode,(void* state, int16_t mode, int16_t* in, uint8_t* out, int16_t dtx)) \ + AMR_VO_FUNC(f,x, void, E_IF_exit, (void* state)) \ + +#define AmrEncoderInit() \ + E_IF_init() +#define AmrEncoderEncode(state, mode, in, out, forceSpeech) \ + E_IF_encode(state, mode, in, out, forceSpeech) +#define AmrEncoderExit(state) \ + E_IF_exit(state) + +#define AMR_VO_DESC "amr-wb VisualOn library" +static const char* const amr_vo_library_names[] = +{ +#ifdef DL_VO_AMRWBENC + "libvo-amrwbenc", + "libvo-amrwbenc-0", +#endif + NULL +}; + +#include "amr.h" diff --git a/app/src/main/cpp/sox/amr.h b/app/src/main/cpp/sox/amr.h new file mode 100644 index 0000000..fe4ef36 --- /dev/null +++ b/app/src/main/cpp/sox/amr.h @@ -0,0 +1,335 @@ +/* File format: AMR (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#ifdef AMR_OPENCORE + +LSX_DLENTRIES_TO_FUNCTIONS(AMR_OPENCORE_FUNC_ENTRIES) + +typedef struct amr_opencore_funcs { + LSX_DLENTRIES_TO_PTRS(AMR_OPENCORE_FUNC_ENTRIES, amr_dl); +} amr_opencore_funcs; + +#endif /* AMR_OPENCORE */ + +#ifdef AMR_VO + +LSX_DLENTRIES_TO_FUNCTIONS(AMR_VO_FUNC_ENTRIES) + +typedef struct amr_vo_funcs { + LSX_DLENTRIES_TO_PTRS(AMR_VO_FUNC_ENTRIES, amr_dl); +} amr_vo_funcs; + +#endif /* AMR_VO */ + +#define AMR_CALL(p, func, args) ((p)->opencore.func args) + +#ifdef AMR_VO + #define AMR_CALL_ENCODER(p, func, args) ((p)->vo.func args) +#else + #define AMR_CALL_ENCODER(p, func, args) ((p)->opencore.func args) +#endif + +typedef struct amr_priv_t { + void* state; + unsigned mode; + size_t pcm_index; +#ifdef AMR_OPENCORE + amr_opencore_funcs opencore; +#endif /* AMR_OPENCORE */ +#ifdef AMR_VO + amr_vo_funcs vo; +#endif /* AMR_VO */ + short pcm[AMR_FRAME]; +} priv_t; + +#ifdef AMR_OPENCORE +static size_t decode_1_frame(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + size_t n; + uint8_t coded[AMR_CODED_MAX]; + + if (lsx_readbuf(ft, &coded[0], (size_t)1) != 1) + return AMR_FRAME; + n = amr_block_size[(coded[0] >> 3) & 0x0F]; + if (!n) { + lsx_fail("invalid block type"); + return AMR_FRAME; + } + n--; + if (lsx_readbuf(ft, &coded[1], n) != n) + return AMR_FRAME; + AMR_CALL(p, AmrDecoderDecode, (p->state, coded, p->pcm, 0)); + return 0; +} +#endif + +static int openlibrary(priv_t* p, int encoding) +{ + int open_library_result; + + (void)encoding; +#ifdef AMR_OPENCORE + if (AMR_OPENCORE_ENABLE_ENCODE || !encoding) + { + LSX_DLLIBRARY_TRYOPEN( + 0, + &p->opencore, + amr_dl, + AMR_OPENCORE_FUNC_ENTRIES, + AMR_OPENCORE_DESC, + amr_opencore_library_names, + open_library_result); + if (!open_library_result) + return SOX_SUCCESS; + lsx_fail("Unable to open " AMR_OPENCORE_DESC); + return SOX_EOF; + } +#endif /* AMR_OPENCORE */ + +#ifdef AMR_VO + if (encoding) { + LSX_DLLIBRARY_TRYOPEN( + 0, + &p->vo, + amr_dl, + AMR_VO_FUNC_ENTRIES, + AMR_VO_DESC, + amr_vo_library_names, + open_library_result); + if (!open_library_result) + return SOX_SUCCESS; + lsx_fail("Unable to open " AMR_VO_DESC); + } +#endif /* AMR_VO */ + + return SOX_EOF; +} + +static void closelibrary(priv_t* p) +{ +#ifdef AMR_OPENCORE + LSX_DLLIBRARY_CLOSE(&p->opencore, amr_dl); +#endif +#ifdef AMR_VO + LSX_DLLIBRARY_CLOSE(&p->vo, amr_dl); +#endif +} + +#ifdef AMR_OPENCORE +static size_t amr_duration_frames(sox_format_t * ft) +{ + off_t frame_size, data_start_offset = lsx_tell(ft); + size_t frames; + uint8_t coded; + + for (frames = 0; lsx_readbuf(ft, &coded, (size_t)1) == 1; ++frames) { + frame_size = amr_block_size[coded >> 3 & 15]; + if (!frame_size) { + lsx_fail("invalid block type"); + break; + } + if (lsx_seeki(ft, frame_size - 1, SEEK_CUR)) { + lsx_fail("seek"); + break; + } + } + lsx_debug("frames=%lu", (unsigned long)frames); + lsx_seeki(ft, data_start_offset, SEEK_SET); + return frames; +} +#endif + +static int startread(sox_format_t * ft) +{ +#if !defined(AMR_OPENCORE) + lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB decoding support."); + return SOX_EOF; +#else + priv_t * p = (priv_t *)ft->priv; + char buffer[sizeof(amr_magic) - 1]; + int open_library_result; + + if (lsx_readchars(ft, buffer, sizeof(buffer))) + return SOX_EOF; + if (memcmp(buffer, amr_magic, sizeof(buffer))) { + lsx_fail_errno(ft, SOX_EHDR, "invalid magic number"); + return SOX_EOF; + } + + open_library_result = openlibrary(p, 0); + if (open_library_result != SOX_SUCCESS) + return open_library_result; + + p->pcm_index = AMR_FRAME; + p->state = AMR_CALL(p, AmrDecoderInit, ()); + if (!p->state) + { + closelibrary(p); + lsx_fail("AMR decoder failed to initialize."); + return SOX_EOF; + } + + ft->signal.rate = AMR_RATE; + ft->encoding.encoding = AMR_ENCODING; + ft->signal.channels = 1; + ft->signal.length = ft->signal.length != SOX_IGNORE_LENGTH && ft->seekable? + (size_t)(amr_duration_frames(ft) * .02 * ft->signal.rate +.5) : SOX_UNSPEC; + return SOX_SUCCESS; +#endif +} + +#ifdef AMR_OPENCORE + +static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + priv_t * p = (priv_t *)ft->priv; + size_t done; + + for (done = 0; done < len; done++) { + if (p->pcm_index >= AMR_FRAME) + p->pcm_index = decode_1_frame(ft); + if (p->pcm_index >= AMR_FRAME) + break; + *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(p->pcm[p->pcm_index++], ft->clips); + } + return done; +} + +static int stopread(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + AMR_CALL(p, AmrDecoderExit, (p->state)); + closelibrary(p); + return SOX_SUCCESS; +} + +#else + +#define read_samples NULL +#define stopread NULL + +#endif + +static int startwrite(sox_format_t * ft) +{ +#if !defined(AMR_VO) && !AMR_OPENCORE_ENABLE_ENCODE + lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB encoding support."); + return SOX_EOF; +#else + priv_t * p = (priv_t *)ft->priv; + int open_library_result; + + if (ft->encoding.compression != HUGE_VAL) { + p->mode = (unsigned)ft->encoding.compression; + if (p->mode != ft->encoding.compression || p->mode > AMR_MODE_MAX) { + lsx_fail_errno(ft, SOX_EINVAL, "compression level must be a whole number from 0 to %i", AMR_MODE_MAX); + return SOX_EOF; + } + } + else p->mode = 0; + + open_library_result = openlibrary(p, 1); + if (open_library_result != SOX_SUCCESS) + return open_library_result; + + p->state = AMR_CALL_ENCODER(p, AmrEncoderInit, ()); + if (!p->state) + { + closelibrary(p); + lsx_fail("AMR encoder failed to initialize."); + return SOX_EOF; + } + + lsx_writes(ft, amr_magic); + p->pcm_index = 0; + return SOX_SUCCESS; +#endif +} + +#if defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE + +static sox_bool encode_1_frame(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + uint8_t coded[AMR_CODED_MAX]; + int n = AMR_CALL_ENCODER(p, AmrEncoderEncode, (p->state, p->mode, p->pcm, coded, 1)); + sox_bool result = lsx_writebuf(ft, coded, (size_t) (size_t) (unsigned)n) == (unsigned)n; + if (!result) + lsx_fail_errno(ft, errno, "write error"); + return result; +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, size_t len) +{ + priv_t * p = (priv_t *)ft->priv; + size_t done; + + for (done = 0; done < len; ++done) { + SOX_SAMPLE_LOCALS; + p->pcm[p->pcm_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips); + if (p->pcm_index == AMR_FRAME) { + p->pcm_index = 0; + if (!encode_1_frame(ft)) + return 0; + } + } + return done; +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + int result = SOX_SUCCESS; + + if (p->pcm_index) { + do { + p->pcm[p->pcm_index++] = 0; + } while (p->pcm_index < AMR_FRAME); + if (!encode_1_frame(ft)) + result = SOX_EOF; + } + AMR_CALL_ENCODER(p, AmrEncoderExit, (p->state)); + return result; +} + +#else + +#define write_samples NULL +#define stopwrite NULL + +#endif /* defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE */ + +sox_format_handler_t const * AMR_FORMAT_FN(void); +sox_format_handler_t const * AMR_FORMAT_FN(void) +{ + static char const * const names[] = {AMR_NAMES, NULL}; + static sox_rate_t const write_rates[] = {AMR_RATE, 0}; + static unsigned const write_encodings[] = {AMR_ENCODING, 0, 0}; + static sox_format_handler_t handler = { + SOX_LIB_VERSION_CODE, + AMR_DESC, + names, SOX_FILE_MONO, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + NULL, write_encodings, write_rates, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/ao.c b/app/src/main/cpp/sox/ao.c new file mode 100644 index 0000000..4791d4e --- /dev/null +++ b/app/src/main/cpp/sox/ao.c @@ -0,0 +1,134 @@ +/* libao player support for sox + * (c) Reuben Thomas 2007 + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include +#include +#include +#include + +typedef struct { + int driver_id; + ao_device *device; + ao_sample_format format; + char *buf; + size_t buf_size; +} priv_t; + +static int startwrite(sox_format_t * ft) +{ + priv_t * ao = (priv_t *)ft->priv; + + ao->buf_size = sox_globals.bufsiz - (sox_globals.bufsiz % (ft->encoding.bits_per_sample >> 3)); + ao->buf_size *= (ft->encoding.bits_per_sample >> 3); + ao->buf = lsx_malloc(ao->buf_size); + + if (!ao->buf) + { + lsx_fail_errno(ft, SOX_ENOMEM, "Can not allocate memory for ao driver"); + return SOX_EOF; + } + + + ao_initialize(); + if (strcmp(ft->filename,"default") == 0) + { + if ((ao->driver_id = ao_default_driver_id()) < 0) { + lsx_fail("Could not find a default ao driver"); + return SOX_EOF; + } + } + else + { + if ((ao->driver_id = ao_driver_id(ft->filename)) < 0) { + lsx_fail("Could not find a ao driver %s", ft->filename); + return SOX_EOF; + } + } + + ao->format.bits = ft->encoding.bits_per_sample; + ao->format.rate = ft->signal.rate; + ao->format.channels = ft->signal.channels; + ao->format.byte_format = AO_FMT_NATIVE; + if ((ao->device = ao_open_live(ao->driver_id, &ao->format, NULL)) == NULL) { + lsx_fail("Could not open device: error %d", errno); + return SOX_EOF; + } + + return SOX_SUCCESS; +} + +static void sox_sw_write_buf(char *buf1, sox_sample_t const * buf2, size_t len, sox_bool swap, sox_uint64_t * clips) +{ + while (len--) + { + SOX_SAMPLE_LOCALS; + uint16_t datum = SOX_SAMPLE_TO_SIGNED_16BIT(*buf2++, *clips); + if (swap) + datum = lsx_swapw(datum); + *(uint16_t *)buf1 = datum; + buf1++; buf1++; + } +} + +static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t len) +{ + priv_t * ao = (priv_t *)ft->priv; + uint_32 aobuf_size; + + if (len > ao->buf_size / (ft->encoding.bits_per_sample >> 3)) + len = ao->buf_size / (ft->encoding.bits_per_sample >> 3); + + aobuf_size = (ft->encoding.bits_per_sample >> 3) * len; + + sox_sw_write_buf(ao->buf, buf, len, ft->encoding.reverse_bytes, + &(ft->clips)); + if (ao_play(ao->device, (void *)ao->buf, aobuf_size) == 0) + return 0; + + return len; +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * ao = (priv_t *)ft->priv; + + free(ao->buf); + + if (ao_close(ao->device) == 0) { + lsx_fail("Error closing libao output"); + return SOX_EOF; + } + ao_shutdown(); + + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(ao) +{ + static char const * const names[] = {"ao", NULL}; + static unsigned const encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Xiph's libao device driver", names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + NULL, NULL, NULL, + startwrite, write_samples, stopwrite, + NULL, encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/au.c b/app/src/main/cpp/sox/au.c new file mode 100644 index 0000000..a3d7629 --- /dev/null +++ b/app/src/main/cpp/sox/au.c @@ -0,0 +1,237 @@ +/* libSoX Sun format with header (SunOS 4.1; see /usr/demo/SOUND). + * Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors. + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Guido van Rossum And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * October 7, 1998 - cbagwell@sprynet.com + * G.723 was using incorrect # of bits. Corrected to 3 and 5 bits. + * + * NeXT uses this format also, but has more format codes defined. + * DEC uses a slight variation and swaps bytes. + * We support only the common formats, plus + * CCITT G.721 (32 kbit/s) and G.723 (24/40 kbit/s), + * courtesy of Sun's public domain implementation. + */ + +#include "sox_i.h" +#include "g72x.h" +#include + +/* Magic numbers used in Sun and NeXT audio files */ +static struct {char str[4]; sox_bool reverse_bytes; char const * desc;} id[] = { + {"\x2e\x73\x6e\x64", MACHINE_IS_LITTLEENDIAN, "big-endian `.snd'"}, + {"\x64\x6e\x73\x2e", MACHINE_IS_BIGENDIAN , "little-endian `.snd'"}, + {"\x00\x64\x73\x2e", MACHINE_IS_BIGENDIAN , "little-endian `\\0ds.' (for DEC)"}, + {"\x2e\x73\x64\x00", MACHINE_IS_LITTLEENDIAN, "big-endian `\\0ds.'"}, + {" ", 0, NULL} +}; +#define FIXED_HDR 24 +#define SUN_UNSPEC ~0u /* Unspecified data size (this is legal) */ + +typedef enum { + Unspecified, Mulaw_8, Linear_8, Linear_16, Linear_24, Linear_32, Float, + Double, Indirect, Nested, Dsp_core, Dsp_data_8, Dsp_data_16, Dsp_data_24, + Dsp_data_32, Unknown, Display, Mulaw_squelch, Emphasized, Compressed, + Compressed_emphasized, Dsp_commands, Dsp_commands_samples, Adpcm_g721, + Adpcm_g722, Adpcm_g723_3, Adpcm_g723_5, Alaw_8, Unknown_other} ft_encoding_t; +static char const * const str[] = { + "Unspecified", "8-bit mu-law", "8-bit signed linear", "16-bit signed linear", + "24-bit signed linear", "32-bit signed linear", "Floating-point", + "Double precision float", "Fragmented sampled data", "Unknown", "DSP program", + "8-bit fixed-point", "16-bit fixed-point", "24-bit fixed-point", + "32-bit fixed-point", "Unknown", "Non-audio data", "Mu-law squelch", + "16-bit linear with emphasis", "16-bit linear with compression", + "16-bit linear with emphasis and compression", "Music Kit DSP commands", + "Music Kit DSP samples", "4-bit G.721 ADPCM", "G.722 ADPCM", + "3-bit G.723 ADPCM", "5-bit G.723 ADPCM", "8-bit a-law", "Unknown"}; + +static ft_encoding_t ft_enc(unsigned size, sox_encoding_t encoding) +{ + if (encoding == SOX_ENCODING_ULAW && size == 8) return Mulaw_8; + if (encoding == SOX_ENCODING_ALAW && size == 8) return Alaw_8; + if (encoding == SOX_ENCODING_SIGN2 && size == 8) return Linear_8; + if (encoding == SOX_ENCODING_SIGN2 && size == 16) return Linear_16; + if (encoding == SOX_ENCODING_SIGN2 && size == 24) return Linear_24; + if (encoding == SOX_ENCODING_SIGN2 && size == 32) return Linear_32; + if (encoding == SOX_ENCODING_FLOAT && size == 32) return Float; + if (encoding == SOX_ENCODING_FLOAT && size == 64) return Double; + return Unspecified; +} + +static sox_encoding_t sox_enc(uint32_t ft_encoding, unsigned * size) +{ + switch (ft_encoding) { + case Mulaw_8 : *size = 8; return SOX_ENCODING_ULAW; + case Alaw_8 : *size = 8; return SOX_ENCODING_ALAW; + case Linear_8 : *size = 8; return SOX_ENCODING_SIGN2; + case Linear_16 : *size = 16; return SOX_ENCODING_SIGN2; + case Linear_24 : *size = 24; return SOX_ENCODING_SIGN2; + case Linear_32 : *size = 32; return SOX_ENCODING_SIGN2; + case Float : *size = 32; return SOX_ENCODING_FLOAT; + case Double : *size = 64; return SOX_ENCODING_FLOAT; + case Adpcm_g721 : *size = 4; return SOX_ENCODING_G721; /* read-only */ + case Adpcm_g723_3: *size = 3; return SOX_ENCODING_G723; /* read-only */ + case Adpcm_g723_5: *size = 5; return SOX_ENCODING_G723; /* read-only */ + default: return SOX_ENCODING_UNKNOWN; + } +} + +typedef struct { /* For G72x decoding: */ + struct g72x_state state; + int (*dec_routine)(int i, int out_coding, struct g72x_state *state_ptr); + unsigned int in_buffer; + int in_bits; +} priv_t; + +/* + * Unpack input codes and pass them back as bytes. + * Returns 1 if there is residual input, returns -1 if eof, else returns 0. + * (Adapted from Sun's decode.c.) + */ +static int unpack_input(sox_format_t * ft, unsigned char *code) +{ + priv_t * p = (priv_t *) ft->priv; + unsigned char in_byte; + + if (p->in_bits < (int)ft->encoding.bits_per_sample) { + if (lsx_read_b_buf(ft, &in_byte, (size_t) 1) != 1) { + *code = 0; + return -1; + } + p->in_buffer |= (in_byte << p->in_bits); + p->in_bits += 8; + } + *code = p->in_buffer & ((1 << ft->encoding.bits_per_sample) - 1); + p->in_buffer >>= ft->encoding.bits_per_sample; + p->in_bits -= ft->encoding.bits_per_sample; + return p->in_bits > 0; +} + +static size_t dec_read(sox_format_t *ft, sox_sample_t *buf, size_t samp) +{ + priv_t * p = (priv_t *)ft->priv; + unsigned char code; + size_t done; + + for (done = 0; samp > 0 && unpack_input(ft, &code) >= 0; ++done, --samp) + *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE( + (*p->dec_routine)(code, AUDIO_ENCODING_LINEAR, &p->state),); + return done; +} + +static int startread(sox_format_t * ft) +{ + priv_t * p = (priv_t *) ft->priv; + char magic[4]; /* These 6 variables represent a Sun sound */ + uint32_t hdr_size; /* header on disk. The uint32_t are written as */ + uint32_t data_size; /* big-endians. At least extra bytes (totalling */ + uint32_t ft_encoding; /* hdr_size - FIXED_HDR) are an "info" field of */ + uint32_t rate; /* unspecified nature, usually a string. By */ + uint32_t channels; /* convention the header size is a multiple of 4. */ + unsigned i, bits_per_sample; + sox_encoding_t encoding; + + if (lsx_readchars(ft, magic, sizeof(magic))) + return SOX_EOF; + + for (i = 0; id[i].desc && memcmp(magic, id[i].str, sizeof(magic)); ++i); + if (!id[i].desc) { + lsx_fail_errno(ft, SOX_EHDR, "au: can't find Sun/NeXT/DEC identifier"); + return SOX_EOF; + } + lsx_report("found %s identifier", id[i].desc); + ft->encoding.reverse_bytes = id[i].reverse_bytes; + + if (lsx_readdw(ft, &hdr_size) || + lsx_readdw(ft, &data_size) || /* Can be SUN_UNSPEC */ + lsx_readdw(ft, &ft_encoding) || + lsx_readdw(ft, &rate) || + lsx_readdw(ft, &channels)) + return SOX_EOF; + + if (hdr_size < FIXED_HDR) { + lsx_fail_errno(ft, SOX_EHDR, "header size %u is too small", hdr_size); + return SOX_EOF; + } + if (hdr_size < FIXED_HDR + 4) + lsx_warn("header size %u is too small", hdr_size); + + if (!(encoding = sox_enc(ft_encoding, &bits_per_sample))) { + int n = min(ft_encoding, Unknown_other); + lsx_fail_errno(ft, SOX_EFMT, "unsupported encoding `%s' (%#x)", str[n], ft_encoding); + return SOX_EOF; + } + + switch (ft_encoding) { + case Adpcm_g721 : p->dec_routine = g721_decoder ; break; + case Adpcm_g723_3: p->dec_routine = g723_24_decoder; break; + case Adpcm_g723_5: p->dec_routine = g723_40_decoder; break; + } + if (p->dec_routine) { + g72x_init_state(&p->state); + ft->handler.seek = NULL; + ft->handler.read = dec_read; + } + + if (hdr_size > FIXED_HDR) { + size_t info_size = hdr_size - FIXED_HDR; + char * buf = lsx_calloc(1, info_size + 1); /* +1 ensures null-terminated */ + if (lsx_readchars(ft, buf, info_size) != SOX_SUCCESS) { + free(buf); + return SOX_EOF; + } + sox_append_comments(&ft->oob.comments, buf); + free(buf); + } + if (data_size == SUN_UNSPEC) + data_size = SOX_UNSPEC; + return lsx_check_read_params(ft, channels, (sox_rate_t)rate, encoding, + bits_per_sample, div_bits(data_size, bits_per_sample), sox_true); +} + +static int write_header(sox_format_t * ft) +{ + char * comment = lsx_cat_comments(ft->oob.comments); + size_t len = strlen(comment) + 1; /* Write out null-terminated */ + size_t info_len = max(4, (len + 3) & ~3u); /* Minimum & multiple of 4 bytes */ + int i = ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? 2 : 0; + uint64_t size64 = ft->olength ? ft->olength : ft->signal.length; + unsigned size = size64 == SOX_UNSPEC + ? SUN_UNSPEC + : size64*(ft->encoding.bits_per_sample >> 3) > UINT_MAX + ? SUN_UNSPEC + : (unsigned)(size64*(ft->encoding.bits_per_sample >> 3)); + sox_bool error = sox_false + ||lsx_writechars(ft, id[i].str, sizeof(id[i].str)) + ||lsx_writedw(ft, FIXED_HDR + (unsigned)info_len) + ||lsx_writedw(ft, size) + ||lsx_writedw(ft, ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding)) + ||lsx_writedw(ft, (unsigned)(ft->signal.rate + .5)) + ||lsx_writedw(ft, ft->signal.channels) + ||lsx_writechars(ft, comment, len) + ||lsx_padbytes(ft, info_len - len); + free(comment); + return error? SOX_EOF: SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(au) +{ + static char const * const names[] = {"au", "snd", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "PCM file format used widely on Sun systems", + names, SOX_FILE_BIG_END | SOX_FILE_REWIND, + startread, lsx_rawread, NULL, + write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/avr.c b/app/src/main/cpp/sox/avr.c new file mode 100644 index 0000000..ab403a1 --- /dev/null +++ b/app/src/main/cpp/sox/avr.c @@ -0,0 +1,287 @@ +/* AVR file format handler for SoX + * Copyright (C) 1999 Jan Paul Schmidt + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include +#include + +#define AVR_MAGIC "2BIT" + +/* Taken from the Audio File Formats FAQ */ + +typedef struct { + char magic [5]; /* 2BIT */ + char name [8]; /* null-padded sample name */ + unsigned short mono; /* 0 = mono, 0xffff = stereo */ + unsigned short rez; /* 8 = 8 bit, 16 = 16 bit */ + unsigned short sign; /* 0 = unsigned, 0xffff = signed */ + unsigned short loop; /* 0 = no loop, 0xffff = looping sample */ + unsigned short midi; /* 0xffff = no MIDI note assigned, + 0xffXX = single key note assignment + 0xLLHH = key split, low/hi note */ + uint32_t rate; /* sample frequency in hertz */ + uint32_t size; /* sample length in bytes or words (see rez) */ + uint32_t lbeg; /* offset to start of loop in bytes or words. + set to zero if unused. */ + uint32_t lend; /* offset to end of loop in bytes or words. + set to sample length if unused. */ + unsigned short res1; /* Reserved, MIDI keyboard split */ + unsigned short res2; /* Reserved, sample compression */ + unsigned short res3; /* Reserved */ + char ext[20]; /* Additional filename space, used + if (name[7] != 0) */ + char user[64]; /* User defined. Typically ASCII message. */ +} priv_t; + + + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ + + +static int startread(sox_format_t * ft) +{ + priv_t * avr = (priv_t *)ft->priv; + int rc; + + lsx_reads(ft, avr->magic, (size_t)4); + + if (strncmp (avr->magic, AVR_MAGIC, (size_t)4)) { + lsx_fail_errno(ft,SOX_EHDR,"AVR: unknown header"); + return(SOX_EOF); + } + + lsx_readbuf(ft, avr->name, sizeof(avr->name)); + + lsx_readw (ft, &(avr->mono)); + if (avr->mono) { + ft->signal.channels = 2; + } + else { + ft->signal.channels = 1; + } + + lsx_readw (ft, &(avr->rez)); + if (avr->rez == 8) { + ft->encoding.bits_per_sample = 8; + } + else if (avr->rez == 16) { + ft->encoding.bits_per_sample = 16; + } + else { + lsx_fail_errno(ft,SOX_EFMT,"AVR: unsupported sample resolution"); + return(SOX_EOF); + } + + lsx_readw (ft, &(avr->sign)); + if (avr->sign) { + ft->encoding.encoding = SOX_ENCODING_SIGN2; + } + else { + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + } + + lsx_readw (ft, &(avr->loop)); + + lsx_readw (ft, &(avr->midi)); + + lsx_readdw (ft, &(avr->rate)); + /* + * No support for AVRs created by ST-Replay, + * Replay Proffesional and PRO-Series 12. + * + * Just masking the upper byte out. + */ + ft->signal.rate = (avr->rate & 0x00ffffff); + + lsx_readdw (ft, &(avr->size)); + + lsx_readdw (ft, &(avr->lbeg)); + + lsx_readdw (ft, &(avr->lend)); + + lsx_readw (ft, &(avr->res1)); + + lsx_readw (ft, &(avr->res2)); + + lsx_readw (ft, &(avr->res3)); + + lsx_readbuf(ft, avr->ext, sizeof(avr->ext)); + + lsx_readbuf(ft, avr->user, sizeof(avr->user)); + + rc = lsx_rawstartread (ft); + if (rc) + return rc; + + return(SOX_SUCCESS); +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * avr = (priv_t *)ft->priv; + int rc; + + if (!ft->seekable) { + lsx_fail_errno(ft,SOX_EOF,"AVR: file is not seekable"); + return(SOX_EOF); + } + + rc = lsx_rawstartwrite (ft); + if (rc) + return rc; + + /* magic */ + lsx_writes(ft, AVR_MAGIC); + + /* name */ + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + + /* mono */ + if (ft->signal.channels == 1) { + lsx_writew (ft, 0); + } + else if (ft->signal.channels == 2) { + lsx_writew (ft, 0xffff); + } + else { + lsx_fail_errno(ft,SOX_EFMT,"AVR: number of channels not supported"); + return(0); + } + + /* rez */ + if (ft->encoding.bits_per_sample == 8) { + lsx_writew (ft, 8); + } + else if (ft->encoding.bits_per_sample == 16) { + lsx_writew (ft, 16); + } + else { + lsx_fail_errno(ft,SOX_EFMT,"AVR: unsupported sample resolution"); + return(SOX_EOF); + } + + /* sign */ + if (ft->encoding.encoding == SOX_ENCODING_SIGN2) { + lsx_writew (ft, 0xffff); + } + else if (ft->encoding.encoding == SOX_ENCODING_UNSIGNED) { + lsx_writew (ft, 0); + } + else { + lsx_fail_errno(ft,SOX_EFMT,"AVR: unsupported encoding"); + return(SOX_EOF); + } + + /* loop */ + lsx_writew (ft, 0xffff); + + /* midi */ + lsx_writew (ft, 0xffff); + + /* rate */ + lsx_writedw(ft, (unsigned)(ft->signal.rate + .5)); + + /* size */ + /* Don't know the size yet. */ + lsx_writedw (ft, 0); + + /* lbeg */ + lsx_writedw (ft, 0); + + /* lend */ + /* Don't know the size yet, so we can't set lend, either. */ + lsx_writedw (ft, 0); + + /* res1 */ + lsx_writew (ft, 0); + + /* res2 */ + lsx_writew (ft, 0); + + /* res3 */ + lsx_writew (ft, 0); + + /* ext */ + lsx_writebuf(ft, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", sizeof(avr->ext)); + + /* user */ + lsx_writebuf(ft, + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0", sizeof (avr->user)); + + return(SOX_SUCCESS); +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp) +{ + priv_t * avr = (priv_t *)ft->priv; + + avr->size += nsamp; + + return (lsx_rawwrite (ft, buf, nsamp)); +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * avr = (priv_t *)ft->priv; + + unsigned size = avr->size / ft->signal.channels; + + /* Fix size */ + lsx_seeki(ft, (off_t)26, SEEK_SET); + lsx_writedw (ft, size); + + /* Fix lend */ + lsx_seeki(ft, (off_t)34, SEEK_SET); + lsx_writedw (ft, size); + + return(SOX_SUCCESS); +} + +LSX_FORMAT_HANDLER(avr) +{ + static char const * const names[] = { "avr", NULL }; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 8, 0, + SOX_ENCODING_UNSIGNED, 16, 8, 0, + 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Audio Visual Research format; used on the Mac", + names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_STEREO, + startread, lsx_rawread, NULL, + startwrite, write_samples, stopwrite, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/band.h b/app/src/main/cpp/sox/band.h new file mode 100644 index 0000000..5398ff4 --- /dev/null +++ b/app/src/main/cpp/sox/band.h @@ -0,0 +1,47 @@ +/* libSoX Bandpass effect file. July 5, 1991 + * Copyright 1991 Lance Norskog And Sundry Contributors + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * Algorithm: 2nd order recursive filter. + * Formula stolen from MUSIC56K, a toolkit of 56000 assembler stuff. + * Quote: + * This is a 2nd order recursive band pass filter of the form. + * y(n)= a * x(n) - b * y(n-1) - c * y(n-2) + * where : + * x(n) = "IN" + * "OUT" = y(n) + * c = EXP(-2*pi*cBW/S_RATE) + * b = -4*c/(1+c)*COS(2*pi*cCF/S_RATE) + * if cSCL=2 (i.e. noise input) + * a = SQT(((1+c)*(1+c)-b*b)*(1-c)/(1+c)) + * else + * a = SQT(1-b*b/(4*c))*(1-c) + * endif + * note : cCF is the center frequency in Hertz + * cBW is the band width in Hertz + * cSCL is a scale factor, use 1 for pitched sounds + * use 2 for noise. + * + * + * July 1, 1999 - Jan Paul Schmidt + * + * This looks like the resonator band pass in SPKit. It's a + * second order all-pole (IIR) band-pass filter described + * at the pages 186 - 189 in + * Dodge, Charles & Jerse, Thomas A. 1985: + * Computer Music -- Synthesis, Composition and Performance. + * New York: Schirmer Books. + * Reference from the SPKit manual. + */ + + p->a2 = exp(-2 * M_PI * bw_Hz / effp->in_signal.rate); + p->a1 = -4 * p->a2 / (1 + p->a2) * cos(2 * M_PI * p->fc / effp->in_signal.rate); + p->b0 = sqrt(1 - p->a1 * p->a1 / (4 * p->a2)) * (1 - p->a2); + if (p->filter_type == filter_BPF_SPK_N) { + mult = sqrt(((1+p->a2) * (1+p->a2) - p->a1*p->a1) * (1-p->a2) / (1+p->a2)) / p->b0; + p->b0 *= mult; + } diff --git a/app/src/main/cpp/sox/bend.c b/app/src/main/cpp/sox/bend.c new file mode 100644 index 0000000..889719e --- /dev/null +++ b/app/src/main/cpp/sox/bend.c @@ -0,0 +1,325 @@ +/* libSoX effect: Pitch Bend (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Portions based on http://www.dspdimension.com/download smbPitchShift.cpp: + * + * COPYRIGHT 1999-2006 Stephan M. Bernsee + * + * The Wide Open License (WOL) + * + * Permission to use, copy, modify, distribute and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice and this license appear in all source copies. + * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF + * ANY KIND. See http://www.dspguru.com/wol.htm for more information. + */ + +#ifdef NDEBUG /* Enable assert always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox_i.h" +#include + +#define MAX_FRAME_LENGTH 8192 + +typedef struct { + unsigned nbends; /* Number of bends requested */ + struct { + char *str; /* Command-line argument to parse for this bend */ + uint64_t start; /* Start bending when in_pos equals this */ + double cents; + uint64_t duration; /* Number of samples to bend */ + } *bends; + + unsigned frame_rate; + size_t in_pos; /* Number of samples read from the input stream */ + unsigned bends_pos; /* Number of bends completed so far */ + + double shift; + + float gInFIFO[MAX_FRAME_LENGTH]; + float gOutFIFO[MAX_FRAME_LENGTH]; + double gFFTworksp[2 * MAX_FRAME_LENGTH]; + float gLastPhase[MAX_FRAME_LENGTH / 2 + 1]; + float gSumPhase[MAX_FRAME_LENGTH / 2 + 1]; + float gOutputAccum[2 * MAX_FRAME_LENGTH]; + float gAnaFreq[MAX_FRAME_LENGTH]; + float gAnaMagn[MAX_FRAME_LENGTH]; + float gSynFreq[MAX_FRAME_LENGTH]; + float gSynMagn[MAX_FRAME_LENGTH]; + long gRover; + int fftFrameSize, ovsamp; +} priv_t; + +static int parse(sox_effect_t * effp, char **argv, sox_rate_t rate) +{ + priv_t *p = (priv_t *) effp->priv; + size_t i; + char const *next; + uint64_t last_seen = 0; + const uint64_t in_length = argv ? 0 : + (effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN); + + for (i = 0; i < p->nbends; ++i) { + if (argv) /* 1st parse only */ + p->bends[i].str = lsx_strdup(argv[i]); + + next = lsx_parseposition(rate, p->bends[i].str, + argv ? NULL : &p->bends[i].start, last_seen, in_length, '+'); + last_seen = p->bends[i].start; + if (next == NULL || *next != ',') + break; + + p->bends[i].cents = strtod(next + 1, (char **)&next); + if (p->bends[i].cents == 0 || *next != ',') + break; + + next = lsx_parseposition(rate, next + 1, + argv ? NULL : &p->bends[i].duration, last_seen, in_length, '+'); + last_seen = p->bends[i].duration; + if (next == NULL || *next != '\0') + break; + + /* sanity checks */ + if (!argv && p->bends[i].duration < p->bends[i].start) { + lsx_fail("Bend %" PRIuPTR " has negative width", i+1); + break; + } + if (!argv && i && p->bends[i].start < p->bends[i-1].start) { + lsx_fail("Bend %" PRIuPTR " overlaps with previous one", i+1); + break; + } + + p->bends[i].duration -= p->bends[i].start; + } + if (i < p->nbends) + return lsx_usage(effp); + return SOX_SUCCESS; +} + +static int create(sox_effect_t * effp, int argc, char **argv) +{ + priv_t *p = (priv_t *) effp->priv; + char const * opts = "f:o:"; + int c; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_none, 1, &optstate); + + p->frame_rate = 25; + p->ovsamp = 16; + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + GETOPT_NUMERIC(optstate, 'f', frame_rate, 10 , 80) + GETOPT_NUMERIC(optstate, 'o', ovsamp, 4 , 32) + default: lsx_fail("unknown option `-%c'", optstate.opt); return lsx_usage(effp); + } + argc -= optstate.ind, argv += optstate.ind; + + p->nbends = argc; + p->bends = lsx_calloc(p->nbends, sizeof(*p->bends)); + return parse(effp, argv, 0.); /* No rate yet; parse with dummy */ +} + +static int start(sox_effect_t * effp) +{ + priv_t *p = (priv_t *) effp->priv; + unsigned i; + + int n = effp->in_signal.rate / p->frame_rate + .5; + for (p->fftFrameSize = 2; n > 2; p->fftFrameSize <<= 1, n >>= 1); + assert(p->fftFrameSize <= MAX_FRAME_LENGTH); + p->shift = 1; + parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */ + p->in_pos = p->bends_pos = 0; + for (i = 0; i < p->nbends; ++i) + if (p->bends[i].duration) + return SOX_SUCCESS; + return SOX_EFF_NULL; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t *p = (priv_t *) effp->priv; + size_t i, len = *isamp = *osamp = min(*isamp, *osamp); + double magn, phase, tmp, window, real, imag; + double freqPerBin, expct; + long k, qpd, index, inFifoLatency, stepSize, fftFrameSize2; + float pitchShift = p->shift; + + /* set up some handy variables */ + fftFrameSize2 = p->fftFrameSize / 2; + stepSize = p->fftFrameSize / p->ovsamp; + freqPerBin = effp->in_signal.rate / p->fftFrameSize; + expct = 2. * M_PI * (double) stepSize / (double) p->fftFrameSize; + inFifoLatency = p->fftFrameSize - stepSize; + if (!p->gRover) + p->gRover = inFifoLatency; + + /* main processing loop */ + for (i = 0; i < len; i++) { + SOX_SAMPLE_LOCALS; + ++p->in_pos; + + /* As long as we have not yet collected enough data just read in */ + p->gInFIFO[p->gRover] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i], effp->clips); + obuf[i] = SOX_FLOAT_32BIT_TO_SAMPLE( + p->gOutFIFO[p->gRover - inFifoLatency], effp->clips); + p->gRover++; + + /* now we have enough data for processing */ + if (p->gRover >= p->fftFrameSize) { + if (p->bends_pos != p->nbends && p->in_pos >= + p->bends[p->bends_pos].start + p->bends[p->bends_pos].duration) { + pitchShift = p->shift *= pow(2., p->bends[p->bends_pos].cents / 1200); + ++p->bends_pos; + } + if (p->bends_pos != p->nbends && p->in_pos >= p->bends[p->bends_pos].start) { + double progress = (double)(p->in_pos - p->bends[p->bends_pos].start) / + p->bends[p->bends_pos].duration; + progress = 1 - cos(M_PI * progress); + progress *= p->bends[p->bends_pos].cents * (.5 / 1200); + pitchShift = p->shift * pow(2., progress); + } + + p->gRover = inFifoLatency; + + /* do windowing and re,im interleave */ + for (k = 0; k < p->fftFrameSize; k++) { + window = -.5 * cos(2 * M_PI * k / (double) p->fftFrameSize) + .5; + p->gFFTworksp[2 * k] = p->gInFIFO[k] * window; + p->gFFTworksp[2 * k + 1] = 0.; + } + + /* ***************** ANALYSIS ******************* */ + lsx_safe_cdft(2 * p->fftFrameSize, 1, p->gFFTworksp); + + /* this is the analysis step */ + for (k = 0; k <= fftFrameSize2; k++) { + /* de-interlace FFT buffer */ + real = p->gFFTworksp[2 * k]; + imag = - p->gFFTworksp[2 * k + 1]; + + /* compute magnitude and phase */ + magn = 2. * sqrt(real * real + imag * imag); + phase = atan2(imag, real); + + /* compute phase difference */ + tmp = phase - p->gLastPhase[k]; + p->gLastPhase[k] = phase; + + tmp -= (double) k *expct; /* subtract expected phase difference */ + + /* map delta phase into +/- Pi interval */ + qpd = tmp / M_PI; + if (qpd >= 0) + qpd += qpd & 1; + else qpd -= qpd & 1; + tmp -= M_PI * (double) qpd; + + /* get deviation from bin frequency from the +/- Pi interval */ + tmp = p->ovsamp * tmp / (2. * M_PI); + + /* compute the k-th partials' true frequency */ + tmp = (double) k *freqPerBin + tmp * freqPerBin; + + /* store magnitude and true frequency in analysis arrays */ + p->gAnaMagn[k] = magn; + p->gAnaFreq[k] = tmp; + + } + + /* this does the actual pitch shifting */ + memset(p->gSynMagn, 0, p->fftFrameSize * sizeof(float)); + memset(p->gSynFreq, 0, p->fftFrameSize * sizeof(float)); + for (k = 0; k <= fftFrameSize2; k++) { + index = k * pitchShift; + if (index <= fftFrameSize2) { + p->gSynMagn[index] += p->gAnaMagn[k]; + p->gSynFreq[index] = p->gAnaFreq[k] * pitchShift; + } + } + + for (k = 0; k <= fftFrameSize2; k++) { /* SYNTHESIS */ + /* get magnitude and true frequency from synthesis arrays */ + magn = p->gSynMagn[k], tmp = p->gSynFreq[k]; + tmp -= (double) k *freqPerBin; /* subtract bin mid frequency */ + tmp /= freqPerBin; /* get bin deviation from freq deviation */ + tmp = 2. * M_PI * tmp / p->ovsamp; /* take p->ovsamp into account */ + tmp += (double) k *expct; /* add the overlap phase advance back in */ + p->gSumPhase[k] += tmp; /* accumulate delta phase to get bin phase */ + phase = p->gSumPhase[k]; + /* get real and imag part and re-interleave */ + p->gFFTworksp[2 * k] = magn * cos(phase); + p->gFFTworksp[2 * k + 1] = - magn * sin(phase); + } + + for (k = p->fftFrameSize + 2; k < 2 * p->fftFrameSize; k++) + p->gFFTworksp[k] = 0.; /* zero negative frequencies */ + + lsx_safe_cdft(2 * p->fftFrameSize, -1, p->gFFTworksp); + + /* do windowing and add to output accumulator */ + for (k = 0; k < p->fftFrameSize; k++) { + window = + -.5 * cos(2. * M_PI * (double) k / (double) p->fftFrameSize) + .5; + p->gOutputAccum[k] += + 2. * window * p->gFFTworksp[2 * k] / (fftFrameSize2 * p->ovsamp); + } + for (k = 0; k < stepSize; k++) + p->gOutFIFO[k] = p->gOutputAccum[k]; + + memmove(p->gOutputAccum, /* shift accumulator */ + p->gOutputAccum + stepSize, p->fftFrameSize * sizeof(float)); + + for (k = 0; k < inFifoLatency; k++) /* move input FIFO */ + p->gInFIFO[k] = p->gInFIFO[k + stepSize]; + } + } + return SOX_SUCCESS; +} + +static int stop(sox_effect_t * effp) +{ + priv_t *p = (priv_t *) effp->priv; + + if (p->bends_pos != p->nbends) + lsx_warn("Input audio too short; bends not applied: %u", + p->nbends - p->bends_pos); + return SOX_SUCCESS; +} + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t *p = (priv_t *) effp->priv; + unsigned i; + + for (i = 0; i < p->nbends; ++i) + free(p->bends[i].str); + free(p->bends); + return SOX_SUCCESS; +} + +sox_effect_handler_t const *lsx_bend_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "bend", "[-f frame-rate(25)] [-o over-sample(16)] {start,cents,end}", + 0, create, start, flow, 0, stop, lsx_kill, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/biquad.c b/app/src/main/cpp/sox/biquad.c new file mode 100644 index 0000000..c57f190 --- /dev/null +++ b/app/src/main/cpp/sox/biquad.c @@ -0,0 +1,178 @@ +/* libSoX Biquad filter common functions (c) 2006-7 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "biquad.h" +#include + +typedef biquad_t priv_t; + +static char const * const width_str[] = { + "band-width(Hz)", + "band-width(kHz)", + "band-width(Hz, no warp)", /* deprecated */ + "band-width(octaves)", + "Q", + "slope", +}; +static char const all_width_types[] = "hkboqs"; + + +int lsx_biquad_getopts(sox_effect_t * effp, int argc, char **argv, + int min_args, int max_args, int fc_pos, int width_pos, int gain_pos, + char const * allowed_width_types, filter_t filter_type) +{ + priv_t * p = (priv_t *)effp->priv; + char width_type = *allowed_width_types; + char dummy, * dummy_p; /* To check for extraneous chars. */ + --argc, ++argv; + + p->filter_type = filter_type; + if (argc < min_args || argc > max_args || + (argc > fc_pos && ((p->fc = lsx_parse_frequency(argv[fc_pos], &dummy_p)) <= 0 || *dummy_p)) || + (argc > width_pos && ((unsigned)(sscanf(argv[width_pos], "%lf%c %c", &p->width, &width_type, &dummy)-1) > 1 || p->width <= 0)) || + (argc > gain_pos && sscanf(argv[gain_pos], "%lf %c", &p->gain, &dummy) != 1) || + !strchr(allowed_width_types, width_type) || (width_type == 's' && p->width > 1)) + return lsx_usage(effp); + p->width_type = strchr(all_width_types, width_type) - all_width_types; + if ((size_t)p->width_type >= strlen(all_width_types)) + p->width_type = 0; + if (p->width_type == width_bw_kHz) { + p->width *= 1000; + p->width_type = width_bw_Hz; + } + return SOX_SUCCESS; +} + + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + /* Simplify: */ + p->b2 /= p->a0; + p->b1 /= p->a0; + p->b0 /= p->a0; + p->a2 /= p->a0; + p->a1 /= p->a0; + + p->o2 = p->o1 = p->i2 = p->i1 = 0; + return SOX_SUCCESS; +} + + +int lsx_biquad_start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + + start(effp); + + if (effp->global_info->plot == sox_plot_octave) { + printf( + "%% GNU Octave file (may also work with MATLAB(R) )\n" + "Fs=%g;minF=10;maxF=Fs/2;\n" + "sweepF=logspace(log10(minF),log10(maxF),200);\n" + "[h,w]=freqz([%.15e %.15e %.15e],[1 %.15e %.15e],sweepF,Fs);\n" + "semilogx(w,20*log10(h))\n" + "title('SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)')\n" + "xlabel('Frequency (Hz)')\n" + "ylabel('Amplitude Response (dB)')\n" + "axis([minF maxF -35 25])\n" + "grid on\n" + "disp('Hit return to continue')\n" + "pause\n" + , effp->in_signal.rate, p->b0, p->b1, p->b2, p->a1, p->a2 + , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width + , effp->in_signal.rate); + return SOX_EOF; + } + if (effp->global_info->plot == sox_plot_gnuplot) { + printf( + "# gnuplot file\n" + "set title 'SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)'\n" + "set xlabel 'Frequency (Hz)'\n" + "set ylabel 'Amplitude Response (dB)'\n" + "Fs=%g\n" + "b0=%.15e; b1=%.15e; b2=%.15e; a1=%.15e; a2=%.15e\n" + "o=2*pi/Fs\n" + "H(f)=sqrt((b0*b0+b1*b1+b2*b2+2.*(b0*b1+b1*b2)*cos(f*o)+2.*(b0*b2)*cos(2.*f*o))/(1.+a1*a1+a2*a2+2.*(a1+a1*a2)*cos(f*o)+2.*a2*cos(2.*f*o)))\n" + "set logscale x\n" + "set samples 250\n" + "set grid xtics ytics\n" + "set key off\n" + "plot [f=10:Fs/2] [-35:25] 20*log10(H(f))\n" + "pause -1 'Hit return to continue'\n" + , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width + , effp->in_signal.rate, effp->in_signal.rate + , p->b0, p->b1, p->b2, p->a1, p->a2); + return SOX_EOF; + } + if (effp->global_info->plot == sox_plot_data) { + printf("# SoX effect: %s gain=%g frequency=%g %s=%g (rate=%g)\n" + "# IIR filter\n" + "# rate: %g\n" + "# name: b\n" + "# type: matrix\n" + "# rows: 3\n" + "# columns: 1\n" + "%24.16e\n%24.16e\n%24.16e\n" + "# name: a\n" + "# type: matrix\n" + "# rows: 3\n" + "# columns: 1\n" + "%24.16e\n%24.16e\n%24.16e\n" + , effp->handler.name, p->gain, p->fc, width_str[p->width_type], p->width + , effp->in_signal.rate, effp->in_signal.rate + , p->b0, p->b1, p->b2, 1. /* a0 */, p->a1, p->a2); + return SOX_EOF; + } + return SOX_SUCCESS; +} + + +int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf, + sox_sample_t *obuf, size_t *isamp, size_t *osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len = *isamp = *osamp = min(*isamp, *osamp); + while (len--) { + double o0 = *ibuf*p->b0 + p->i1*p->b1 + p->i2*p->b2 - p->o1*p->a1 - p->o2*p->a2; + p->i2 = p->i1, p->i1 = *ibuf++; + p->o2 = p->o1, p->o1 = o0; + *obuf++ = SOX_ROUND_CLIP_COUNT(o0, effp->clips); + } + return SOX_SUCCESS; +} + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + double * d = &p->b0; + char c; + + --argc, ++argv; + if (argc == 6) + for (; argc && sscanf(*argv, "%lf%c", d, &c) == 1; --argc, ++argv, ++d); + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_biquad_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "biquad", "b0 b1 b2 a0 a1 a2", 0, + create, lsx_biquad_start, lsx_biquad_flow, NULL, NULL, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/biquad.h b/app/src/main/cpp/sox/biquad.h new file mode 100644 index 0000000..8786ac8 --- /dev/null +++ b/app/src/main/cpp/sox/biquad.h @@ -0,0 +1,78 @@ +/* libSoX Biquad filter common definitions (c) 2006-7 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef biquad_included +#define biquad_included + +#define LSX_EFF_ALIAS +#include "sox_i.h" + +typedef enum { + filter_LPF, + filter_HPF, + filter_BPF_CSG, + filter_BPF, + filter_notch, + filter_APF, + filter_peakingEQ, + filter_lowShelf, + filter_highShelf, + filter_LPF_1, + filter_HPF_1, + filter_BPF_SPK, + filter_BPF_SPK_N, + filter_AP1, + filter_AP2, + filter_deemph, + filter_riaa +} filter_t; + +typedef enum { + width_bw_Hz, + width_bw_kHz, + /* The old, non-RBJ, non-freq-warped band-pass/reject response; + * leaving here for now just in case anybody misses it: */ + width_bw_old, + width_bw_oct, + width_Q, + width_slope +} width_t; + +/* Private data for the biquad filter effects */ +typedef struct { + double gain; /* For EQ filters */ + double fc; /* Centre/corner/cutoff frequency */ + double width; /* Filter width; interpreted as per width_type */ + width_t width_type; + + filter_t filter_type; + + double b0, b1, b2; /* Filter coefficients */ + double a0, a1, a2; /* Filter coefficients */ + + sox_sample_t i1, i2; /* Filter memory */ + double o1, o2; /* Filter memory */ +} biquad_t; + +int lsx_biquad_getopts(sox_effect_t * effp, int n, char **argv, + int min_args, int max_args, int fc_pos, int width_pos, int gain_pos, + char const * allowed_width_types, filter_t filter_type); +int lsx_biquad_start(sox_effect_t * effp); +int lsx_biquad_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp); + +#endif diff --git a/app/src/main/cpp/sox/biquads.c b/app/src/main/cpp/sox/biquads.c new file mode 100644 index 0000000..2b7ca73 --- /dev/null +++ b/app/src/main/cpp/sox/biquads.c @@ -0,0 +1,416 @@ +/* libSoX Biquad filter effects (c) 2006-8 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * + * 2-pole filters designed by Robert Bristow-Johnson + * see https://webaudio.github.io/Audio-EQ-Cookbook/audio-eq-cookbook.html + * + * 1-pole filters based on code (c) 2000 Chris Bagwell + * Algorithms: Recursive single pole low/high pass filter + * Reference: The Scientist and Engineer's Guide to Digital Signal Processing + * + * low-pass: output[N] = input[N] * A + output[N-1] * B + * X = exp(-2.0 * pi * Fc) + * A = 1 - X + * B = X + * Fc = cutoff freq / sample rate + * + * Mimics an RC low-pass filter: + * + * ---/\/\/\/\-----------> + * | + * --- C + * --- + * | + * | + * V + * + * high-pass: output[N] = A0 * input[N] + A1 * input[N-1] + B1 * output[N-1] + * X = exp(-2.0 * pi * Fc) + * A0 = (1 + X) / 2 + * A1 = -(1 + X) / 2 + * B1 = X + * Fc = cutoff freq / sample rate + * + * Mimics an RC high-pass filter: + * + * || C + * ----||---------> + * || | + * < + * > R + * < + * | + * V + */ + + +#include "biquad.h" +#include +#include + +typedef biquad_t priv_t; + + +static int hilo1_getopts(sox_effect_t * effp, int argc, char **argv) { + return lsx_biquad_getopts(effp, argc, argv, 1, 1, 0, 1, 2, "", + *effp->handler.name == 'l'? filter_LPF_1 : filter_HPF_1); +} + + +static int hilo2_getopts(sox_effect_t * effp, int argc, char **argv) { + priv_t * p = (priv_t *)effp->priv; + if (argc > 1 && strcmp(argv[1], "-1") == 0) + return hilo1_getopts(effp, argc - 1, argv + 1); + if (argc > 1 && strcmp(argv[1], "-2") == 0) + ++argv, --argc; + p->width = sqrt(0.5); /* Default to Butterworth */ + return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "qohk", + *effp->handler.name == 'l'? filter_LPF : filter_HPF); +} + + +static int bandpass_getopts(sox_effect_t * effp, int argc, char **argv) { + filter_t type = filter_BPF; + if (argc > 1 && strcmp(argv[1], "-c") == 0) + ++argv, --argc, type = filter_BPF_CSG; + return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", type); +} + + +static int bandrej_getopts(sox_effect_t * effp, int argc, char **argv) { + return lsx_biquad_getopts(effp, argc, argv, 2, 2, 0, 1, 2, "hkqob", filter_notch); +} + + +static int allpass_getopts(sox_effect_t * effp, int argc, char **argv) { + filter_t type = filter_APF; + int m; + if (argc > 1 && strcmp(argv[1], "-1") == 0) + ++argv, --argc, type = filter_AP1; + else if (argc > 1 && strcmp(argv[1], "-2") == 0) + ++argv, --argc, type = filter_AP2; + m = 1 + (type == filter_APF); + return lsx_biquad_getopts(effp, argc, argv, m, m, 0, 1, 2, "hkqo", type); +} + + +static int tone_getopts(sox_effect_t * effp, int argc, char **argv) { + priv_t * p = (priv_t *)effp->priv; + p->width = 0.5; + p->fc = *effp->handler.name == 'b'? 100 : 3000; + return lsx_biquad_getopts(effp, argc, argv, 1, 3, 1, 2, 0, "shkqo", + *effp->handler.name == 'b'? filter_lowShelf: filter_highShelf); +} + + +static int equalizer_getopts(sox_effect_t * effp, int argc, char **argv) { + return lsx_biquad_getopts(effp, argc, argv, 3, 3, 0, 1, 2, "qohk", filter_peakingEQ); +} + + +static int band_getopts(sox_effect_t * effp, int argc, char **argv) { + filter_t type = filter_BPF_SPK; + if (argc > 1 && strcmp(argv[1], "-n") == 0) + ++argv, --argc, type = filter_BPF_SPK_N; + return lsx_biquad_getopts(effp, argc, argv, 1, 2, 0, 1, 2, "hkqo", type); +} + + +static int deemph_getopts(sox_effect_t * effp, int argc, char **argv) { + return lsx_biquad_getopts(effp, argc, argv, 0, 0, 0, 1, 2, "s", filter_deemph); +} + + +static int riaa_getopts(sox_effect_t * effp, int argc, char **argv) { + priv_t * p = (priv_t *)effp->priv; + p->filter_type = filter_riaa; + (void)argv; + return --argc? lsx_usage(effp) : SOX_SUCCESS; +} + + +static void make_poly_from_roots( + double const * roots, size_t num_roots, double * poly) +{ + size_t i, j; + poly[0] = 1; + poly[1] = -roots[0]; + memset(poly + 2, 0, (num_roots + 1 - 2) * sizeof(*poly)); + for (i = 1; i < num_roots; ++i) + for (j = num_roots; j > 0; --j) + poly[j] -= poly[j - 1] * roots[i]; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + double w0, A, alpha, mult; + + if (p->filter_type == filter_deemph) { /* See deemph.plt for documentation */ + if (effp->in_signal.rate == 44100) { + p->fc = 5283; + p->width = 0.4845; + p->gain = -9.477; + } + else if (effp->in_signal.rate == 48000) { + p->fc = 5356; + p->width = 0.479; + p->gain = -9.62; + } + else { + lsx_fail("sample rate must be 44100 (audio-CD) or 48000 (DAT)"); + return SOX_EOF; + } + } + + w0 = 2 * M_PI * p->fc / effp->in_signal.rate; + A = exp(p->gain / 40 * log(10.)); + alpha = 0, mult = dB_to_linear(max(p->gain, 0)); + + if (w0 > M_PI) { + lsx_fail("frequency must be less than half the sample-rate (Nyquist rate)"); + return SOX_EOF; + } + + /* Set defaults: */ + p->b0 = p->b1 = p->b2 = p->a1 = p->a2 = 0; + p->a0 = 1; + + if (p->width) switch (p->width_type) { + case width_slope: + alpha = sin(w0)/2 * sqrt((A + 1/A)*(1/p->width - 1) + 2); + break; + + case width_Q: + alpha = sin(w0)/(2*p->width); + break; + + case width_bw_oct: + alpha = sin(w0)*sinh(log(2.)/2 * p->width * w0/sin(w0)); + break; + + case width_bw_Hz: + alpha = sin(w0)/(2*p->fc/p->width); + break; + + case width_bw_kHz: assert(0); /* Shouldn't get here */ + + case width_bw_old: + alpha = tan(M_PI * p->width / effp->in_signal.rate); + break; + } + switch (p->filter_type) { + case filter_LPF: /* H(s) = 1 / (s^2 + s/Q + 1) */ + p->b0 = (1 - cos(w0))/2; + p->b1 = 1 - cos(w0); + p->b2 = (1 - cos(w0))/2; + p->a0 = 1 + alpha; + p->a1 = -2*cos(w0); + p->a2 = 1 - alpha; + break; + + case filter_HPF: /* H(s) = s^2 / (s^2 + s/Q + 1) */ + p->b0 = (1 + cos(w0))/2; + p->b1 = -(1 + cos(w0)); + p->b2 = (1 + cos(w0))/2; + p->a0 = 1 + alpha; + p->a1 = -2*cos(w0); + p->a2 = 1 - alpha; + break; + + case filter_BPF_CSG: /* H(s) = s / (s^2 + s/Q + 1) (constant skirt gain, peak gain = Q) */ + p->b0 = sin(w0)/2; + p->b1 = 0; + p->b2 = -sin(w0)/2; + p->a0 = 1 + alpha; + p->a1 = -2*cos(w0); + p->a2 = 1 - alpha; + break; + + case filter_BPF: /* H(s) = (s/Q) / (s^2 + s/Q + 1) (constant 0 dB peak gain) */ + p->b0 = alpha; + p->b1 = 0; + p->b2 = -alpha; + p->a0 = 1 + alpha; + p->a1 = -2*cos(w0); + p->a2 = 1 - alpha; + break; + + case filter_notch: /* H(s) = (s^2 + 1) / (s^2 + s/Q + 1) */ + p->b0 = 1; + p->b1 = -2*cos(w0); + p->b2 = 1; + p->a0 = 1 + alpha; + p->a1 = -2*cos(w0); + p->a2 = 1 - alpha; + break; + + case filter_APF: /* H(s) = (s^2 - s/Q + 1) / (s^2 + s/Q + 1) */ + p->b0 = 1 - alpha; + p->b1 = -2*cos(w0); + p->b2 = 1 + alpha; + p->a0 = 1 + alpha; + p->a1 = -2*cos(w0); + p->a2 = 1 - alpha; + break; + + case filter_peakingEQ: /* H(s) = (s^2 + s*(A/Q) + 1) / (s^2 + s/(A*Q) + 1) */ + if (A == 1) + return SOX_EFF_NULL; + p->b0 = 1 + alpha*A; + p->b1 = -2*cos(w0); + p->b2 = 1 - alpha*A; + p->a0 = 1 + alpha/A; + p->a1 = -2*cos(w0); + p->a2 = 1 - alpha/A; + break; + + case filter_lowShelf: /* H(s) = A * (s^2 + (sqrt(A)/Q)*s + A)/(A*s^2 + (sqrt(A)/Q)*s + 1) */ + if (A == 1) + return SOX_EFF_NULL; + p->b0 = A*( (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha ); + p->b1 = 2*A*( (A-1) - (A+1)*cos(w0) ); + p->b2 = A*( (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha ); + p->a0 = (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha; + p->a1 = -2*( (A-1) + (A+1)*cos(w0) ); + p->a2 = (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha; + break; + + case filter_deemph: /* Falls through to high-shelf... */ + + case filter_highShelf: /* H(s) = A * (A*s^2 + (sqrt(A)/Q)*s + 1)/(s^2 + (sqrt(A)/Q)*s + A) */ + if (!A) + return SOX_EFF_NULL; + p->b0 = A*( (A+1) + (A-1)*cos(w0) + 2*sqrt(A)*alpha ); + p->b1 = -2*A*( (A-1) + (A+1)*cos(w0) ); + p->b2 = A*( (A+1) + (A-1)*cos(w0) - 2*sqrt(A)*alpha ); + p->a0 = (A+1) - (A-1)*cos(w0) + 2*sqrt(A)*alpha; + p->a1 = 2*( (A-1) - (A+1)*cos(w0) ); + p->a2 = (A+1) - (A-1)*cos(w0) - 2*sqrt(A)*alpha; + break; + + case filter_LPF_1: /* single-pole */ + p->a1 = -exp(-w0); + p->b0 = 1 + p->a1; + break; + + case filter_HPF_1: /* single-pole */ + p->a1 = -exp(-w0); + p->b0 = (1 - p->a1)/2; + p->b1 = -p->b0; + break; + + case filter_BPF_SPK: case filter_BPF_SPK_N: { + double bw_Hz; + if (!p->width) + p->width = p->fc / 2; + bw_Hz = p->width_type == width_Q? p->fc / p->width : + p->width_type == width_bw_Hz? p->width : + p->fc * (pow(2., p->width) - 1) * pow(2., -0.5 * p->width); /* bw_oct */ + #include "band.h" /* Has different licence */ + break; + } + + case filter_AP1: /* Experimental 1-pole all-pass from Tom Erbe @ UCSD */ + p->b0 = exp(-w0); + p->b1 = -1; + p->a1 = -exp(-w0); + break; + + case filter_AP2: /* Experimental 2-pole all-pass from Tom Erbe @ UCSD */ + p->b0 = 1 - sin(w0); + p->b1 = -2 * cos(w0); + p->b2 = 1 + sin(w0); + p->a0 = 1 + sin(w0); + p->a1 = -2 * cos(w0); + p->a2 = 1 - sin(w0); + break; + + case filter_riaa: /* http://www.dsprelated.com/showmessage/73300/3.php */ + if (effp->in_signal.rate == 44100) { + static const double zeros[] = {-0.2014898, 0.9233820}; + static const double poles[] = {0.7083149, 0.9924091}; + make_poly_from_roots(zeros, (size_t)2, &p->b0); + make_poly_from_roots(poles, (size_t)2, &p->a0); + } + else if (effp->in_signal.rate == 48000) { + static const double zeros[] = {-0.1766069, 0.9321590}; + static const double poles[] = {0.7396325, 0.9931330}; + make_poly_from_roots(zeros, (size_t)2, &p->b0); + make_poly_from_roots(poles, (size_t)2, &p->a0); + } + else if (effp->in_signal.rate == 88200) { + static const double zeros[] = {-0.1168735, 0.9648312}; + static const double poles[] = {0.8590646, 0.9964002}; + make_poly_from_roots(zeros, (size_t)2, &p->b0); + make_poly_from_roots(poles, (size_t)2, &p->a0); + } + else if (effp->in_signal.rate == 96000) { + static const double zeros[] = {-0.1141486, 0.9676817}; + static const double poles[] = {0.8699137, 0.9966946}; + make_poly_from_roots(zeros, (size_t)2, &p->b0); + make_poly_from_roots(poles, (size_t)2, &p->a0); + } + else if (effp->in_signal.rate == 192000) { + static const double zeros[] = {-0.1040610965, 0.9837523263}; + static const double poles[] = {0.9328992971, 0.9983633125}; + make_poly_from_roots(zeros, (size_t)2, &p->b0); + make_poly_from_roots(poles, (size_t)2, &p->a0); + } + else { + lsx_fail("Sample rate must be 44.1k, 48k, 88.2k, 96k, or 192k"); + return SOX_EOF; + } + { /* Normalise to 0dB at 1kHz (Thanks to Glenn Davis) */ + double y = 2 * M_PI * 1000 / effp->in_signal.rate; + double b_re = p->b0 + p->b1 * cos(-y) + p->b2 * cos(-2 * y); + double a_re = p->a0 + p->a1 * cos(-y) + p->a2 * cos(-2 * y); + double b_im = p->b1 * sin(-y) + p->b2 * sin(-2 * y); + double a_im = p->a1 * sin(-y) + p->a2 * sin(-2 * y); + double g = 1 / sqrt((sqr(b_re) + sqr(b_im)) / (sqr(a_re) + sqr(a_im))); + p->b0 *= g; p->b1 *= g; p->b2 *= g; + } + mult = (p->b0 + p->b1 + p->b2) / (p->a0 + p->a1 + p->a2); + lsx_debug("gain=%f", linear_to_dB(mult)); + break; + } + if (effp->in_signal.mult) + *effp->in_signal.mult /= mult; + return lsx_biquad_start(effp); +} + + +#define BIQUAD_EFFECT(name,group,usage,flags) \ +sox_effect_handler_t const * lsx_##name##_effect_fn(void) { \ + static sox_effect_handler_t handler = { \ + #name, usage, flags, \ + group##_getopts, start, lsx_biquad_flow, 0, 0, 0, sizeof(biquad_t)\ + }; \ + return &handler; \ +} + +BIQUAD_EFFECT(highpass, hilo2, "[-1|-2] frequency [width[q|o|h|k](0.707q)]", 0) +BIQUAD_EFFECT(lowpass, hilo2, "[-1|-2] frequency [width[q|o|h|k]](0.707q)", 0) +BIQUAD_EFFECT(bandpass, bandpass, "[-c] frequency width[h|k|q|o]", 0) +BIQUAD_EFFECT(bandreject,bandrej, "frequency width[h|k|q|o]", 0) +BIQUAD_EFFECT(allpass, allpass, "frequency width[h|k|q|o]", 0) +BIQUAD_EFFECT(bass, tone, "gain [frequency(100) [width[s|h|k|q|o]](0.5s)]", 0) +BIQUAD_EFFECT(treble, tone, "gain [frequency(3000) [width[s|h|k|q|o]](0.5s)]", 0) +BIQUAD_EFFECT(equalizer, equalizer,"frequency width[q|o|h|k] gain", 0) +BIQUAD_EFFECT(band, band, "[-n] center [width[h|k|q|o]]", 0) +BIQUAD_EFFECT(deemph, deemph, NULL, 0) +BIQUAD_EFFECT(riaa, riaa, NULL, 0) diff --git a/app/src/main/cpp/sox/bit-rot/CoreAudio/CoreAudio.h b/app/src/main/cpp/sox/bit-rot/CoreAudio/CoreAudio.h new file mode 100644 index 0000000..8936556 --- /dev/null +++ b/app/src/main/cpp/sox/bit-rot/CoreAudio/CoreAudio.h @@ -0,0 +1,273 @@ +#ifndef HAVE_COREAUDIO +/* + * SoX bit-rot detection file; cobbled together + */ + +enum { + kAudioHardwarePropertyProcessIsMaster, + kAudioHardwarePropertyIsInitingOrExiting, + kAudioHardwarePropertyDevices, + kAudioHardwarePropertyDefaultInputDevice, + kAudioHardwarePropertyDefaultOutputDevice, + kAudioHardwarePropertyDefaultSystemOutputDevice, + kAudioHardwarePropertyDeviceForUID, + kAudioHardwarePropertySleepingIsAllowed, + kAudioHardwarePropertyUnloadingIsAllowed, + kAudioHardwarePropertyHogModeIsAllowed, + kAudioHardwarePropertyRunLoop, + kAudioHardwarePropertyPlugInForBundleID +}; + +enum { + kAudioObjectPropertyClass, + kAudioObjectPropertyOwner, + kAudioObjectPropertyCreator, + kAudioObjectPropertyName, + kAudioObjectPropertyManufacturer, + kAudioObjectPropertyElementName, + kAudioObjectPropertyElementCategoryName, + kAudioObjectPropertyElementNumberName, + kAudioObjectPropertyOwnedObjects, + kAudioObjectPropertyListenerAdded, + kAudioObjectPropertyListenerRemoved +}; + +enum { + kAudioDevicePropertyDeviceName, + kAudioDevicePropertyDeviceNameCFString = kAudioObjectPropertyName, + kAudioDevicePropertyDeviceManufacturer, + kAudioDevicePropertyDeviceManufacturerCFString = + kAudioObjectPropertyManufacturer, + kAudioDevicePropertyRegisterBufferList, + kAudioDevicePropertyBufferSize, + kAudioDevicePropertyBufferSizeRange, + kAudioDevicePropertyChannelName, + kAudioDevicePropertyChannelNameCFString = kAudioObjectPropertyElementName, + kAudioDevicePropertyChannelCategoryName, + kAudioDevicePropertyChannelCategoryNameCFString = + kAudioObjectPropertyElementCategoryName, + kAudioDevicePropertyChannelNumberName, + kAudioDevicePropertyChannelNumberNameCFString = + kAudioObjectPropertyElementNumberName, + kAudioDevicePropertySupportsMixing, + kAudioDevicePropertyStreamFormat, + kAudioDevicePropertyStreamFormats, + kAudioDevicePropertyStreamFormatSupported, + kAudioDevicePropertyStreamFormatMatch, + kAudioDevicePropertyDataSourceNameForID, + kAudioDevicePropertyClockSourceNameForID, + kAudioDevicePropertyPlayThruDestinationNameForID, + kAudioDevicePropertyChannelNominalLineLevelNameForID +}; + +enum { + kAudioDevicePropertyPlugIn, + kAudioDevicePropertyConfigurationApplication, + kAudioDevicePropertyDeviceUID, + kAudioDevicePropertyModelUID, + kAudioDevicePropertyTransportType, + kAudioDevicePropertyRelatedDevices, + kAudioDevicePropertyClockDomain, + kAudioDevicePropertyDeviceIsAlive, + kAudioDevicePropertyDeviceHasChanged, + kAudioDevicePropertyDeviceIsRunning, + kAudioDevicePropertyDeviceIsRunningSomewhere, + kAudioDevicePropertyDeviceCanBeDefaultDevice, + kAudioDevicePropertyDeviceCanBeDefaultSystemDevice, + kAudioDeviceProcessorOverload, + kAudioDevicePropertyHogMode, + kAudioDevicePropertyLatency, + kAudioDevicePropertyBufferFrameSize, + kAudioDevicePropertyBufferFrameSizeRange, + kAudioDevicePropertyUsesVariableBufferFrameSizes, + kAudioDevicePropertyStreams, + kAudioDevicePropertySafetyOffset, + kAudioDevicePropertyIOCycleUsage, + kAudioDevicePropertyStreamConfiguration, + kAudioDevicePropertyIOProcStreamUsage, + kAudioDevicePropertyPreferredChannelsForStereo, + kAudioDevicePropertyPreferredChannelLayout, + kAudioDevicePropertyNominalSampleRate, + kAudioDevicePropertyAvailableNominalSampleRates, + kAudioDevicePropertyActualSampleRate +}; + +enum { + kAudioFormatLinearPCM, + kAudioFormatAC3, + kAudioFormat60958AC3, + kAudioFormatAppleIMA4, + kAudioFormatMPEG4AAC, + kAudioFormatMPEG4CELP, + kAudioFormatMPEG4HVXC, + kAudioFormatMPEG4TwinVQ, + kAudioFormatMACE3, + kAudioFormatMACE6, + kAudioFormatULaw, + kAudioFormatALaw, + kAudioFormatQDesign, + kAudioFormatQDesign2, + kAudioFormatQUALCOMM, + kAudioFormatMPEGLayer1, + kAudioFormatMPEGLayer2, + kAudioFormatMPEGLayer3, + kAudioFormatDVAudio, + kAudioFormatVariableDurationDVAudio, + kAudioFormatTimeCode, + kAudioFormatMIDIStream, + kAudioFormatParameterValueStream, + kAudioFormatAppleLossless +}; + +enum { + kAudioFormatFlagIsFloat = (1L << 0), + kAudioFormatFlagIsBigEndian = (1L << 1), + kAudioFormatFlagIsSignedInteger = (1L << 2), + kAudioFormatFlagIsPacked = (1L << 3), + kAudioFormatFlagIsAlignedHigh = (1L << 4), + kAudioFormatFlagIsNonInterleaved = (1L << 5), + kAudioFormatFlagIsNonMixable = (1L << 6), + + kLinearPCMFormatFlagIsFloat = kAudioFormatFlagIsFloat, + kLinearPCMFormatFlagIsBigEndian = kAudioFormatFlagIsBigEndian, + kLinearPCMFormatFlagIsSignedInteger = kAudioFormatFlagIsSignedInteger, + kLinearPCMFormatFlagIsPacked = kAudioFormatFlagIsPacked, + kLinearPCMFormatFlagIsAlignedHigh = kAudioFormatFlagIsAlignedHigh, + kLinearPCMFormatFlagIsNonInterleaved = kAudioFormatFlagIsNonInterleaved, + kLinearPCMFormatFlagIsNonMixable = kAudioFormatFlagIsNonMixable, + + kAppleLosslessFormatFlag_16BitSourceData = 1, + kAppleLosslessFormatFlag_20BitSourceData = 2, + kAppleLosslessFormatFlag_24BitSourceData = 3, + kAppleLosslessFormatFlag_32BitSourceData = 4 +}; + +enum { + kAudioFormatFlagsNativeEndian = kAudioFormatFlagIsBigEndian, + kAudioFormatFlagsNativeFloatPacked = + kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | + kAudioFormatFlagIsPacked +}; + +enum { + kAudioDeviceUnknown +}; + +enum { + kVariableLengthArray = 1 +}; + +enum { + kAudioHardwareNoError = 0, + noErr = kAudioHardwareNoError +}; + +enum { + false +}; + +typedef double Float64; +typedef float Float32; +typedef int SInt32; +typedef int Boolean; +typedef int OSErr; +typedef short SInt16; +typedef unsigned int UInt32; +typedef unsigned long int UInt64; + +typedef SInt32 OSStatus; +typedef UInt32 AudioObjectID; +typedef UInt32 AudioHardwarePropertyID; +typedef UInt32 AudioDevicePropertyID; +typedef AudioObjectID AudioDeviceID; + +struct AudioStreamBasicDescription { + Float64 mSampleRate; + UInt32 mFormatID; + UInt32 mFormatFlags; + UInt32 mBytesPerPacket; + UInt32 mFramesPerPacket; + UInt32 mBytesPerFrame; + UInt32 mChannelsPerFrame; + UInt32 mBitsPerChannel; + UInt32 mReserved; +}; +typedef struct AudioStreamBasicDescription AudioStreamBasicDescription; + + + +struct SMPTETime { + SInt16 mSubframes; + SInt16 mSubframeDivisor; + UInt32 mCounter; + UInt32 mType; + UInt32 mFlags; + SInt16 mHours; + SInt16 mMinutes; + SInt16 mSeconds; + SInt16 mFrames; +}; +typedef struct SMPTETime SMPTETime; + +struct AudioTimeStamp { + Float64 mSampleTime; + UInt64 mHostTime; + Float64 mRateScalar; + UInt64 mWordClockTime; + SMPTETime mSMPTETime; + UInt32 mFlags; + UInt32 mReserved; +}; +typedef struct AudioTimeStamp AudioTimeStamp; + +struct AudioBuffer { + UInt32 mNumberChannels; + UInt32 mDataByteSize; + void *mData; +}; +typedef struct AudioBuffer AudioBuffer; + +struct AudioBufferList { + UInt32 mNumberBuffers; + AudioBuffer mBuffers[kVariableLengthArray]; +}; +typedef struct AudioBufferList AudioBufferList; + +typedef OSStatus(*AudioDeviceIOProc) (AudioDeviceID inDevice, + const AudioTimeStamp * inNow, + const AudioBufferList * inInputData, + const AudioTimeStamp * inInputTime, + AudioBufferList * outOutputData, + const AudioTimeStamp * inOutputTime, + void *inClientData); + + + +OSStatus AudioHardwareGetProperty(AudioHardwarePropertyID inPropertyID, + UInt32 * ioPropertyDataSize, + void *outPropertyData); + +OSStatus AudioHardwareGetPropertyInfo(AudioHardwarePropertyID inPropertyID, + UInt32 * ioPropertyDataSize, + void *outPropertyData); + +OSStatus AudioDeviceSetProperty(AudioDeviceID inDevice, + const AudioTimeStamp * inWhen, + UInt32 inChannel, Boolean isInput, + AudioDevicePropertyID inPropertyID, + UInt32 inPropertyDataSize, + const void *inPropertyData); +OSStatus AudioDeviceGetProperty(AudioDeviceID inDevice, UInt32 inChannel, + Boolean isInput, + AudioDevicePropertyID inPropertyID, + UInt32 * ioPropertyDataSize, + void *outPropertyData); + + +OSStatus AudioDeviceAddIOProc(AudioDeviceID inDevice, + AudioDeviceIOProc inProc, void *inClientData); +OSStatus AudioDeviceStart(AudioDeviceID inDevice, AudioDeviceIOProc inProc); + + +OSStatus AudioDeviceStop(AudioDeviceID inDevice, AudioDeviceIOProc inProc); +#endif diff --git a/app/src/main/cpp/sox/bit-rot/mmreg.h b/app/src/main/cpp/sox/bit-rot/mmreg.h new file mode 100755 index 0000000..e69de29 diff --git a/app/src/main/cpp/sox/bit-rot/mmsystem.h b/app/src/main/cpp/sox/bit-rot/mmsystem.h new file mode 100644 index 0000000..c6b0e3b --- /dev/null +++ b/app/src/main/cpp/sox/bit-rot/mmsystem.h @@ -0,0 +1,89 @@ +/* + * SoX bit-rot detection file; cobbled together + */ +#define HWAVEIN HANDLE +#define HWAVEOUT HANDLE +#define MMRESULT UINT +#define MMVERSION UINT +#define UNALIGNED + +enum { + MMSYSERR_NOERROR, + MAXPNAMELEN, + WAVE_FORMAT_PCM, + WAVE_FORMAT_EXTENSIBLE, + WAVE_FORMAT_QUERY, + WAVE_MAPPER, + WAVERR_STILLPLAYING, + WHDR_DONE, + WHDR_INQUEUE +}; + +typedef struct wavehdr_tag { + LPSTR lpData; + DWORD dwBufferLength; + DWORD dwBytesRecorded; + DWORD dwUser; + DWORD dwFlags; + DWORD dwLoops; + struct wavehdr_tag *lpNext; + DWORD reserved; +} WAVEHDR,*PWAVEHDR,*LPWAVEHDR; + +typedef struct _WAVEFORMATEX { + WORD wFormatTag; + WORD nChannels; + DWORD nSamplesPerSec; + DWORD nAvgBytesPerSec; + WORD nBlockAlign; + WORD wBitsPerSample; + WORD cbSize; +} WAVEFORMATEX, *PWAVEFORMATEX, *NPWAVEFORMATEX, *LPWAVEFORMATEX; + +typedef struct tagWAVEINCAPSA { + WORD wMid; + WORD wPid; + MMVERSION vDriverVersion; + CHAR szPname[MAXPNAMELEN]; + DWORD dwFormats; + WORD wChannels; + WORD wReserved1; +} WAVEINCAPSA,*PWAVEINCAPSA,*LPWAVEINCAPSA; + +typedef struct tagWAVEOUTCAPSA { + WORD wMid; + WORD wPid; + MMVERSION vDriverVersion; + CHAR szPname[MAXPNAMELEN]; + DWORD dwFormats; + WORD wChannels; + WORD wReserved1; + DWORD dwSupport; +} WAVEOUTCAPSA,*PWAVEOUTCAPSA,*LPWAVEOUTCAPSA; + +MMRESULT WINAPI waveInAddBuffer(HWAVEIN,LPWAVEHDR,UINT); +MMRESULT WINAPI waveInClose(HWAVEIN); +MMRESULT WINAPI waveInGetDevCapsA(UINT,LPWAVEINCAPSA,UINT); +MMRESULT WINAPI waveInGetNumDevs(void); +MMRESULT WINAPI waveInOpen(HWAVEIN*,UINT,WAVEFORMATEX*,DWORD*,DWORD*,DWORD); +MMRESULT WINAPI waveInPrepareHeader(HWAVEIN,LPWAVEHDR,UINT); +MMRESULT WINAPI waveInReset(HWAVEIN); +MMRESULT WINAPI waveInStart(HWAVEIN); +MMRESULT WINAPI waveOutClose(HWAVEOUT); +MMRESULT WINAPI waveOutGetDevCapsA(UINT,LPWAVEOUTCAPSA,UINT); +MMRESULT WINAPI waveOutGetNumDevs(void); +MMRESULT WINAPI waveOutOpen(HWAVEOUT*,UINT,WAVEFORMATEX*,DWORD*,DWORD*,DWORD); +MMRESULT WINAPI waveOutPrepareHeader(HWAVEOUT,LPWAVEHDR,UINT); +MMRESULT WINAPI waveOutReset(HWAVEOUT); +MMRESULT WINAPI waveOutWrite(HWAVEOUT,LPWAVEHDR,UINT); + +typedef struct { + WAVEFORMATEX Format; + union { + WORD wValidBitsPerSample; + WORD wSamplesPerBlock; + WORD wReserved; + } Samples; + DWORD dwChannelMask; + GUID SubFormat; +} WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE; diff --git a/app/src/main/cpp/sox/bit-rot/sndio.h b/app/src/main/cpp/sox/bit-rot/sndio.h new file mode 100644 index 0000000..ac6ec5a --- /dev/null +++ b/app/src/main/cpp/sox/bit-rot/sndio.h @@ -0,0 +1,160 @@ +#ifndef HAVE_SNDIO +/* + * SoX bit-rot detection file, obtained from: + * http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libsndio/sndio.h + */ +#if defined __GNUC__ + #pragma GCC system_header +#endif + +/* $OpenBSD: sndio.h,v 1.7 2009/02/03 19:44:58 ratchov Exp $ */ +/* + * Copyright (c) 2008 Alexandre Ratchov + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef SNDIO_H +#define SNDIO_H + +#include + +/* + * private ``handle'' structure + */ +struct sio_hdl; + +/* + * parameters of a full-duplex stream + */ +struct sio_par { + unsigned bits; /* bits per sample */ + unsigned bps; /* bytes per sample */ + unsigned sig; /* 1 = signed, 0 = unsigned */ + unsigned le; /* 1 = LE, 0 = BE byte order */ + unsigned msb; /* 1 = MSB, 0 = LSB aligned */ + unsigned rchan; /* number channels for recording direction */ + unsigned pchan; /* number channels for playback direction */ + unsigned rate; /* frames per second */ + unsigned bufsz; /* end-to-end buffer size */ +#define SIO_IGNORE 0 /* pause during xrun */ +#define SIO_SYNC 1 /* resync after xrun */ +#define SIO_ERROR 2 /* terminate on xrun */ + unsigned xrun; /* what to do on overruns/underruns */ + unsigned round; /* optimal bufsz divisor */ + unsigned appbufsz; /* minimum buffer size */ + int __pad[3]; /* for future use */ + int __magic; /* for internal/debug purposes only */ +}; + +/* + * capabilities of a stream + */ +struct sio_cap { +#define SIO_NENC 8 +#define SIO_NCHAN 8 +#define SIO_NRATE 16 +#define SIO_NCONF 4 + struct sio_enc { /* allowed sample encodings */ + unsigned bits; + unsigned bps; + unsigned sig; + unsigned le; + unsigned msb; + } enc[SIO_NENC]; + unsigned rchan[SIO_NCHAN]; /* allowed values for rchan */ + unsigned pchan[SIO_NCHAN]; /* allowed values for pchan */ + unsigned rate[SIO_NRATE]; /* allowed rates */ + int __pad[7]; /* for future use */ + unsigned nconf; /* number of elements in confs[] */ + struct sio_conf { + unsigned enc; /* mask of enc[] indexes */ + unsigned rchan; /* mask of chan[] indexes (rec) */ + unsigned pchan; /* mask of chan[] indexes (play) */ + unsigned rate; /* mask of rate[] indexes */ + } confs[SIO_NCONF]; +}; + +#define SIO_XSTRINGS { "ignore", "sync", "error" } + +/* + * mode bitmap + */ +#define SIO_PLAY 1 +#define SIO_REC 2 + +/* + * maximum size of the encording string (the longest possible + * encoding is ``s24le3msb'') + */ +#define SIO_ENCMAX 10 + +/* + * default bytes per sample for the given bits per sample + */ +#define SIO_BPS(bits) (((bits) <= 8) ? 1 : (((bits) <= 16) ? 2 : 4)) + +/* + * default value of "sio_par->le" flag + */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define SIO_LE_NATIVE 1 +#else +#define SIO_LE_NATIVE 0 +#endif + +/* + * default device for the sun audio(4) back-end + */ +#define SIO_SUN_PATH "/dev/audio" + +/* + * default socket name for the aucat(1) back-end + */ +#define SIO_AUCAT_PATH "default" + +/* + * maximum value of volume, eg. for sio_setvol() + */ +#define SIO_MAXVOL 127 + +#ifdef __cplusplus +extern "C" { +#endif + +int sio_strtoenc(struct sio_par *, char *); +int sio_enctostr(struct sio_par *, char *); +void sio_initpar(struct sio_par *); + +struct sio_hdl *sio_open(char *, unsigned, int); +void sio_close(struct sio_hdl *); +int sio_setpar(struct sio_hdl *, struct sio_par *); +int sio_getpar(struct sio_hdl *, struct sio_par *); +int sio_getcap(struct sio_hdl *, struct sio_cap *); +void sio_onmove(struct sio_hdl *, void (*)(void *, int), void *); +size_t sio_write(struct sio_hdl *, void *, size_t); +size_t sio_read(struct sio_hdl *, void *, size_t); +int sio_start(struct sio_hdl *); +int sio_stop(struct sio_hdl *); +int sio_nfds(struct sio_hdl *); +int sio_pollfd(struct sio_hdl *, struct pollfd *, int); +int sio_revents(struct sio_hdl *, struct pollfd *); +int sio_eof(struct sio_hdl *); +int sio_setvol(struct sio_hdl *, unsigned); +void sio_onvol(struct sio_hdl *, void (*)(void *, unsigned), void *); + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(SNDIO_H) */ +#endif diff --git a/app/src/main/cpp/sox/bit-rot/sys/audioio.h b/app/src/main/cpp/sox/bit-rot/sys/audioio.h new file mode 100644 index 0000000..071d980 --- /dev/null +++ b/app/src/main/cpp/sox/bit-rot/sys/audioio.h @@ -0,0 +1,289 @@ +#ifndef HAVE_SUN_AUDIO +/* + * SoX bit-rot detection file, obtained from: Solaris 9 /usr/include/sys + */ +#if defined __GNUC__ + #pragma GCC system_header +#endif + +/* + * Copyright (c) 1995-2001 by Sun Microsystems, Inc. + * All rights reserved. + */ + +#ifndef _SYS_AUDIOIO_H +#define _SYS_AUDIOIO_H + +#pragma ident "@(#)audioio.h 1.30 01/01/10 SMI" + +#include +#if 0 +#include +#include +#include +#else +#define ushort_t unsigned short +#define uint_t unsigned int +#define uchar_t unsigned char +struct timeval32 +{ + unsigned tv_sec; + unsigned tv_usec; +}; +#endif + +/* + * These are the ioctl calls for all Solaris audio devices, including + * the x86 and SPARCstation audio devices. + * + * You are encouraged to design your code in a modular fashion so that + * future changes to the interface can be incorporated with little + * trouble. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure contains state information for audio device IO streams. + */ +struct audio_prinfo { + /* + * The following values describe the audio data encoding. + */ + uint_t sample_rate; /* samples per second */ + uint_t channels; /* number of interleaved channels */ + uint_t precision; /* bit-width of each sample */ + uint_t encoding; /* data encoding method */ + + /* + * The following values control audio device configuration + */ + uint_t gain; /* gain level: 0 - 255 */ + uint_t port; /* selected I/O port (see below) */ + uint_t avail_ports; /* available I/O ports (see below) */ + uint_t mod_ports; /* I/O ports that are modifiable (see below) */ + uint_t _xxx; /* Reserved for future use */ + + uint_t buffer_size; /* I/O buffer size */ + + /* + * The following values describe driver state + */ + uint_t samples; /* number of samples converted */ + uint_t eof; /* End Of File counter (play only) */ + + uchar_t pause; /* non-zero for pause, zero to resume */ + uchar_t error; /* non-zero if overflow/underflow */ + uchar_t waiting; /* non-zero if a process wants access */ + uchar_t balance; /* stereo channel balance */ + + ushort_t minordev; + + /* + * The following values are read-only state flags + */ + uchar_t open; /* non-zero if open access permitted */ + uchar_t active; /* non-zero if I/O is active */ +}; +typedef struct audio_prinfo audio_prinfo_t; + + +/* + * This structure describes the current state of the audio device. + */ +struct audio_info { + /* + * Per-stream information + */ + audio_prinfo_t play; /* output status information */ + audio_prinfo_t record; /* input status information */ + + /* + * Per-unit/channel information + */ + uint_t monitor_gain; /* input to output mix: 0 - 255 */ + uchar_t output_muted; /* non-zero if output is muted */ + uchar_t ref_cnt; /* driver reference count, read only */ + uchar_t _xxx[2]; /* Reserved for future use */ + uint_t hw_features; /* hardware features this driver supports */ + uint_t sw_features; /* supported SW features */ + uint_t sw_features_enabled; /* supported SW feat. enabled */ +}; +typedef struct audio_info audio_info_t; + + +/* + * Audio encoding types + */ +#define AUDIO_ENCODING_NONE (0) /* no encoding assigned */ +#define AUDIO_ENCODING_ULAW (1) /* u-law encoding */ +#define AUDIO_ENCODING_ALAW (2) /* A-law encoding */ +#define AUDIO_ENCODING_LINEAR (3) /* Signed Linear PCM encoding */ +#define AUDIO_ENCODING_DVI (104) /* DVI ADPCM */ +#define AUDIO_ENCODING_LINEAR8 (105) /* 8 bit UNSIGNED */ + +/* + * These ranges apply to record, play, and monitor gain values + */ +#define AUDIO_MIN_GAIN (0) /* minimum gain value */ +#define AUDIO_MAX_GAIN (255) /* maximum gain value */ +#define AUDIO_MID_GAIN (AUDIO_MAX_GAIN / 2) + +/* + * These values apply to the balance field to adjust channel gain values + */ +#define AUDIO_LEFT_BALANCE (0) /* left channel only */ +#define AUDIO_MID_BALANCE (32) /* equal left/right channel */ +#define AUDIO_RIGHT_BALANCE (64) /* right channel only */ +#define AUDIO_BALANCE_SHIFT (3) + +/* + * Generic minimum/maximum limits for number of channels, both modes + */ +#define AUDIO_CHANNELS_MONO (1) +#define AUDIO_CHANNELS_STEREO (2) +#define AUDIO_MIN_PLAY_CHANNELS (AUDIO_CHANNELS_MONO) +#define AUDIO_MAX_PLAY_CHANNELS (AUDIO_CHANNELS_STEREO) +#define AUDIO_MIN_REC_CHANNELS (AUDIO_CHANNELS_MONO) +#define AUDIO_MAX_REC_CHANNELS (AUDIO_CHANNELS_STEREO) + +/* + * Generic minimum/maximum limits for sample precision + */ +#define AUDIO_PRECISION_8 (8) +#define AUDIO_PRECISION_16 (16) + +#define AUDIO_MIN_PLAY_PRECISION (8) +#define AUDIO_MAX_PLAY_PRECISION (32) +#define AUDIO_MIN_REC_PRECISION (8) +#define AUDIO_MAX_REC_PRECISION (32) + +/* + * Define some convenient names for typical audio ports + */ +#define AUDIO_NONE 0x00 /* all ports off */ +/* + * output ports (several may be enabled simultaneously) + */ +#define AUDIO_SPEAKER 0x01 /* output to built-in speaker */ +#define AUDIO_HEADPHONE 0x02 /* output to headphone jack */ +#define AUDIO_LINE_OUT 0x04 /* output to line out */ +#define AUDIO_SPDIF_OUT 0x08 /* output to SPDIF port */ +#define AUDIO_AUX1_OUT 0x10 /* output to aux1 out */ +#define AUDIO_AUX2_OUT 0x20 /* output to aux2 out */ + +/* + * input ports (usually only one at a time) + */ +#define AUDIO_MICROPHONE 0x01 /* input from microphone */ +#define AUDIO_LINE_IN 0x02 /* input from line in */ +#define AUDIO_CD 0x04 /* input from on-board CD inputs */ +#define AUDIO_INTERNAL_CD_IN AUDIO_CD /* input from internal CDROM */ +#define AUDIO_SPDIF_IN 0x08 /* input from SPDIF port */ +#define AUDIO_AUX1_IN 0x10 /* input from aux1 in */ +#define AUDIO_AUX2_IN 0x20 /* input from aux2 in */ +#define AUDIO_CODEC_LOOPB_IN 0x40 /* input from Codec internal loopback */ +#define AUDIO_SUNVTS 0x80 /* SunVTS input setting-internal LB */ + +/* + * Define the hw_features + */ +#define AUDIO_HWFEATURE_DUPLEX 0x00000001u /* simult. play & rec support */ +#define AUDIO_HWFEATURE_MSCODEC 0x00000002u /* multi-stream Codec */ +#define AUDIO_HWFEATURE_IN2OUT 0x00000004u /* input to output loopback */ +#define AUDIO_HWFEATURE_PLAY 0x00000008u /* device supports play */ +#define AUDIO_HWFEATURE_RECORD 0x00000010u /* device supports record */ + +/* + * Define the sw_features + */ +#define AUDIO_SWFEATURE_MIXER 0x00000001u /* audio mixer audio pers mod */ + +/* + * This macro initializes an audio_info structure to 'harmless' values. + * Note that (~0) might not be a harmless value for a flag that was + * a signed int. + */ +#define AUDIO_INITINFO(i) { \ + uint_t *__x__; \ + for (__x__ = (uint_t *)(i); \ + (char *)__x__ < (((char *)(i)) + sizeof (audio_info_t)); \ + *__x__++ = ~0); \ +} + + +/* + * Parameter for the AUDIO_GETDEV ioctl to determine current + * audio devices. + */ +#define MAX_AUDIO_DEV_LEN (16) +struct audio_device { + char name[MAX_AUDIO_DEV_LEN]; + char version[MAX_AUDIO_DEV_LEN]; + char config[MAX_AUDIO_DEV_LEN]; +}; +typedef struct audio_device audio_device_t; + + +/* + * Ioctl calls for the audio device. + */ + +/* + * AUDIO_GETINFO retrieves the current state of the audio device. + * + * AUDIO_SETINFO copies all fields of the audio_info structure whose + * values are not set to the initialized value (-1) to the device state. + * It performs an implicit AUDIO_GETINFO to return the new state of the + * device. Note that the record.samples and play.samples fields are set + * to the last value before the AUDIO_SETINFO took effect. This allows + * an application to reset the counters while atomically retrieving the + * last value. + * + * AUDIO_DRAIN suspends the calling process until the write buffers are + * empty. + * + * AUDIO_GETDEV returns a structure of type audio_device_t which contains + * three strings. The string "name" is a short identifying string (for + * example, the SBus Fcode name string), the string "version" identifies + * the current version of the device, and the "config" string identifies + * the specific configuration of the audio stream. All fields are + * device-dependent -- see the device specific manual pages for details. + */ +#define AUDIO_GETINFO _IOR('A', 1, audio_info_t) +#define AUDIO_SETINFO _IOWR('A', 2, audio_info_t) +#define AUDIO_DRAIN _IO('A', 3) +#define AUDIO_GETDEV _IOR('A', 4, audio_device_t) + +/* + * The following ioctl sets the audio device into an internal loopback mode, + * if the hardware supports this. The argument is TRUE to set loopback, + * FALSE to reset to normal operation. If the hardware does not support + * internal loopback, the ioctl should fail with EINVAL. + */ +#define AUDIO_DIAG_LOOPBACK _IOW('A', 101, int) + + +/* + * Structure sent up as a M_PROTO message on trace streams + */ +struct audtrace_hdr { + uint_t seq; /* Sequence number (per-aud_stream) */ + int type; /* device-dependent */ +#if defined(_LP64) || defined(_I32LPx) + struct timeval32 timestamp; +#else + struct timeval timestamp; +#endif + char _f[8]; /* filler */ +}; +typedef struct audtrace_hdr audtrace_hdr_t; + +#ifdef __cplusplus +} +#endif + +#endif /* _SYS_AUDIOIO_H */ +#endif diff --git a/app/src/main/cpp/sox/bit-rot/windows.h b/app/src/main/cpp/sox/bit-rot/windows.h new file mode 100644 index 0000000..e7488ee --- /dev/null +++ b/app/src/main/cpp/sox/bit-rot/windows.h @@ -0,0 +1,34 @@ +/* + * SoX bit-rot detection file; cobbled together + */ + +#define BYTE uint8_t +#define CHAR char +#define DWORD_PTR DWORD * +#define DWORD uint32_t +#define HANDLE void * +#define LPCSTR char * +#define LPCVOID void * +#define LPDWORD DWORD * +#define LPSTR char const * +#define UINT DWORD +#define WCHAR int16_t +#define WINAPI +#define WIN_BOOL int +#define WORD uint16_t +typedef char GUID[16]; + +enum { + FALSE, + TRUE, + FORMAT_MESSAGE_FROM_SYSTEM, + FORMAT_MESSAGE_IGNORE_INSERTS, + INFINITE, + CALLBACK_EVENT +}; + +DWORD CloseHandle(HANDLE); +DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR, DWORD,LPDWORD); +DWORD GetLastError(void); +DWORD WaitForSingleObject(HANDLE, DWORD); +HANDLE CreateEventA(LPCVOID,WIN_BOOL,WIN_BOOL,LPCSTR); diff --git a/app/src/main/cpp/sox/caf.c b/app/src/main/cpp/sox/caf.c new file mode 100644 index 0000000..8df3daf --- /dev/null +++ b/app/src/main/cpp/sox/caf.c @@ -0,0 +1,35 @@ +/* libSoX file format: CAF Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(caf) +{ + static char const * const names[] = {"caf", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 24, 32, 8, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_ULAW, 8, 0, + 0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = "Apples's Core Audio Format"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/cdr.c b/app/src/main/cpp/sox/cdr.c new file mode 100644 index 0000000..0b6b061 --- /dev/null +++ b/app/src/main/cpp/sox/cdr.c @@ -0,0 +1,49 @@ +/* libSoX file format: cdda (c) 2006-8 SoX contributors + * Based on an original idea by David Elliott + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +static int start(sox_format_t * ft) +{ + return lsx_check_read_params(ft, 2, 44100., SOX_ENCODING_SIGN2, 16, (uint64_t)0, sox_true); +} + +static int stopwrite(sox_format_t * ft) +{ + unsigned const sector_num_samples = 588 * ft->signal.channels; + unsigned i = ft->olength % sector_num_samples; + + if (i) while (i++ < sector_num_samples) /* Pad with silence to multiple */ + lsx_writew(ft, 0); /* of 1/75th of a second. */ + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(cdr) +{ + static char const * const names[] = {"cdda", "cdr", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0}; + static sox_rate_t const write_rates[] = {44100, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Red Book Compact Disc Digital Audio", + names, SOX_FILE_BIG_END|SOX_FILE_STEREO, + start, lsx_rawread, NULL, + NULL, lsx_rawwrite, stopwrite, + lsx_rawseek, write_encodings, write_rates, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/chorus.c b/app/src/main/cpp/sox/chorus.c new file mode 100644 index 0000000..96ca9df --- /dev/null +++ b/app/src/main/cpp/sox/chorus.c @@ -0,0 +1,351 @@ +/* August 24, 1998 + * Copyright (C) 1998 Juergen Mueller And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Juergen Mueller And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +/* + * Chorus effect. + * + * Flow diagram scheme for n delays ( 1 <= n <= MAX_CHORUS ): + * + * * gain-in ___ + * ibuff -----+--------------------------------------------->| | + * | _________ | | + * | | | * decay 1 | | + * +---->| delay 1 |----------------------------->| | + * | |_________| | | + * | /|\ | | + * : | | | + * : +-----------------+ +--------------+ | + | + * : | Delay control 1 |<--| mod. speed 1 | | | + * : +-----------------+ +--------------+ | | + * | _________ | | + * | | | * decay n | | + * +---->| delay n |----------------------------->| | + * |_________| | | + * /|\ |___| + * | | + * +-----------------+ +--------------+ | * gain-out + * | Delay control n |<--| mod. speed n | | + * +-----------------+ +--------------+ +----->obuff + * + * + * The delay i is controled by a sine or triangle modulation i ( 1 <= i <= n). + * + * Usage: + * chorus gain-in gain-out delay-1 decay-1 speed-1 depth-1 -s1|t1 [ + * delay-2 decay-2 speed-2 depth-2 -s2|-t2 ... ] + * + * Where: + * gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume + * gain-out : 0.0 ... volume + * delay-1 ... delay-n : 20.0 ... 100.0 msec + * speed-1 ... speed-n : 0.1 ... 5.0 Hz modulation 1 ... n + * depth-1 ... depth-n : 0.0 ... 10.0 msec modulated delay 1 ... n + * -s1 ... -sn : modulation by sine 1 ... n + * -t1 ... -tn : modulation by triangle 1 ... n + * + * Note: + * when decay is close to 1.0, the samples can begin clipping and the output + * can saturate! + * + * Hint: + * 1 / out-gain < gain-in ( 1 + decay-1 + ... + decay-n ) + * +*/ + +/* + * libSoX chorus effect file. + */ + +#include "sox_i.h" + +#include /* Harmless, and prototypes atof() etc. --dgc */ +#include + +#define MOD_SINE 0 +#define MOD_TRIANGLE 1 +#define MAX_CHORUS 7 + +typedef struct { + int num_chorus; + int modulation[MAX_CHORUS]; + int counter; + long phase[MAX_CHORUS]; + float *chorusbuf; + float in_gain, out_gain; + float delay[MAX_CHORUS], decay[MAX_CHORUS]; + float speed[MAX_CHORUS], depth[MAX_CHORUS]; + long length[MAX_CHORUS]; + int *lookup_tab[MAX_CHORUS]; + int depth_samples[MAX_CHORUS], samples[MAX_CHORUS]; + int maxsamples; + unsigned int fade_out; +} priv_t; + +/* + * Process options + */ +static int sox_chorus_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * chorus = (priv_t *) effp->priv; + int i; + --argc, ++argv; + + chorus->num_chorus = 0; + i = 0; + + if ( ( argc < 7 ) || (( argc - 2 ) % 5 ) ) + return lsx_usage(effp); + + sscanf(argv[i++], "%f", &chorus->in_gain); + sscanf(argv[i++], "%f", &chorus->out_gain); + while ( i < argc ) { + if ( chorus->num_chorus > MAX_CHORUS ) + { + lsx_fail("chorus: to many delays, use less than %i delays", MAX_CHORUS); + return (SOX_EOF); + } + sscanf(argv[i++], "%f", &chorus->delay[chorus->num_chorus]); + sscanf(argv[i++], "%f", &chorus->decay[chorus->num_chorus]); + sscanf(argv[i++], "%f", &chorus->speed[chorus->num_chorus]); + sscanf(argv[i++], "%f", &chorus->depth[chorus->num_chorus]); + if ( !strcmp(argv[i], "-s")) + chorus->modulation[chorus->num_chorus] = MOD_SINE; + else if ( ! strcmp(argv[i], "-t")) + chorus->modulation[chorus->num_chorus] = MOD_TRIANGLE; + else + return lsx_usage(effp); + i++; + chorus->num_chorus++; + } + return (SOX_SUCCESS); +} + +/* + * Prepare for processing. + */ +static int sox_chorus_start(sox_effect_t * effp) +{ + priv_t * chorus = (priv_t *) effp->priv; + int i; + float sum_in_volume; + + chorus->maxsamples = 0; + + if ( chorus->in_gain < 0.0 ) + { + lsx_fail("chorus: gain-in must be positive!"); + return (SOX_EOF); + } + if ( chorus->in_gain > 1.0 ) + { + lsx_fail("chorus: gain-in must be less than 1.0!"); + return (SOX_EOF); + } + if ( chorus->out_gain < 0.0 ) + { + lsx_fail("chorus: gain-out must be positive!"); + return (SOX_EOF); + } + for ( i = 0; i < chorus->num_chorus; i++ ) { + chorus->samples[i] = (int) ( ( chorus->delay[i] + + chorus->depth[i] ) * effp->in_signal.rate / 1000.0); + chorus->depth_samples[i] = (int) (chorus->depth[i] * + effp->in_signal.rate / 1000.0); + + if ( chorus->delay[i] < 20.0 ) + { + lsx_fail("chorus: delay must be more than 20.0 msec!"); + return (SOX_EOF); + } + if ( chorus->delay[i] > 100.0 ) + { + lsx_fail("chorus: delay must be less than 100.0 msec!"); + return (SOX_EOF); + } + if ( chorus->speed[i] < 0.1 ) + { + lsx_fail("chorus: speed must be more than 0.1 Hz!"); + return (SOX_EOF); + } + if ( chorus->speed[i] > 5.0 ) + { + lsx_fail("chorus: speed must be less than 5.0 Hz!"); + return (SOX_EOF); + } + if ( chorus->depth[i] < 0.0 ) + { + lsx_fail("chorus: delay must be more positive!"); + return (SOX_EOF); + } + if ( chorus->depth[i] > 10.0 ) + { + lsx_fail("chorus: delay must be less than 10.0 msec!"); + return (SOX_EOF); + } + if ( chorus->decay[i] < 0.0 ) + { + lsx_fail("chorus: decay must be positive!" ); + return (SOX_EOF); + } + if ( chorus->decay[i] > 1.0 ) + { + lsx_fail("chorus: decay must be less that 1.0!" ); + return (SOX_EOF); + } + chorus->length[i] = effp->in_signal.rate / chorus->speed[i]; + chorus->lookup_tab[i] = lsx_malloc(sizeof (int) * chorus->length[i]); + + if (chorus->modulation[i] == MOD_SINE) + lsx_generate_wave_table(SOX_WAVE_SINE, SOX_INT, chorus->lookup_tab[i], + (size_t)chorus->length[i], 0., (double)chorus->depth_samples[i], 0.); + else + lsx_generate_wave_table(SOX_WAVE_TRIANGLE, SOX_INT, chorus->lookup_tab[i], + (size_t)chorus->length[i], + (double)(chorus->samples[i] - 1 - 2 * chorus->depth_samples[i]), + (double)(chorus->samples[i] - 1), 3 * M_PI_2); + chorus->phase[i] = 0; + + if ( chorus->samples[i] > chorus->maxsamples ) + chorus->maxsamples = chorus->samples[i]; + } + + /* Be nice and check the hint with warning, if... */ + sum_in_volume = 1.0; + for ( i = 0; i < chorus->num_chorus; i++ ) + sum_in_volume += chorus->decay[i]; + if ( chorus->in_gain * ( sum_in_volume ) > 1.0 / chorus->out_gain ) + lsx_warn("chorus: warning >>> gain-out can cause saturation or clipping of output <<<"); + + + chorus->chorusbuf = lsx_malloc(sizeof (float) * chorus->maxsamples); + for ( i = 0; i < chorus->maxsamples; i++ ) + chorus->chorusbuf[i] = 0.0; + + chorus->counter = 0; + chorus->fade_out = chorus->maxsamples; + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ + + return (SOX_SUCCESS); +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +static int sox_chorus_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * chorus = (priv_t *) effp->priv; + int i; + float d_in, d_out; + sox_sample_t out; + size_t len = min(*isamp, *osamp); + *isamp = *osamp = len; + + while (len--) { + /* Store delays as 24-bit signed longs */ + d_in = (float) *ibuf++ / 256; + /* Compute output first */ + d_out = d_in * chorus->in_gain; + for ( i = 0; i < chorus->num_chorus; i++ ) + d_out += chorus->chorusbuf[(chorus->maxsamples + + chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) % + chorus->maxsamples] * chorus->decay[i]; + /* Adjust the output volume and size to 24 bit */ + d_out = d_out * chorus->out_gain; + out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); + *obuf++ = out * 256; + /* Mix decay of delay and input */ + chorus->chorusbuf[chorus->counter] = d_in; + chorus->counter = + ( chorus->counter + 1 ) % chorus->maxsamples; + for ( i = 0; i < chorus->num_chorus; i++ ) + chorus->phase[i] = + ( chorus->phase[i] + 1 ) % chorus->length[i]; + } + /* processed all samples */ + return (SOX_SUCCESS); +} + +/* + * Drain out reverb lines. + */ +static int sox_chorus_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * chorus = (priv_t *) effp->priv; + size_t done; + int i; + + float d_in, d_out; + sox_sample_t out; + + done = 0; + while ( ( done < *osamp ) && ( done < chorus->fade_out ) ) { + d_in = 0; + d_out = 0; + /* Compute output first */ + for ( i = 0; i < chorus->num_chorus; i++ ) + d_out += chorus->chorusbuf[(chorus->maxsamples + + chorus->counter - chorus->lookup_tab[i][chorus->phase[i]]) % + chorus->maxsamples] * chorus->decay[i]; + /* Adjust the output volume and size to 24 bit */ + d_out = d_out * chorus->out_gain; + out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); + *obuf++ = out * 256; + /* Mix decay of delay and input */ + chorus->chorusbuf[chorus->counter] = d_in; + chorus->counter = + ( chorus->counter + 1 ) % chorus->maxsamples; + for ( i = 0; i < chorus->num_chorus; i++ ) + chorus->phase[i] = + ( chorus->phase[i] + 1 ) % chorus->length[i]; + done++; + chorus->fade_out--; + } + /* samples played, it remains */ + *osamp = done; + if (chorus->fade_out == 0) + return SOX_EOF; + else + return SOX_SUCCESS; +} + +/* + * Clean up chorus effect. + */ +static int sox_chorus_stop(sox_effect_t * effp) +{ + priv_t * chorus = (priv_t *) effp->priv; + int i; + + free(chorus->chorusbuf); + chorus->chorusbuf = NULL; + for ( i = 0; i < chorus->num_chorus; i++ ) { + free(chorus->lookup_tab[i]); + chorus->lookup_tab[i] = NULL; + } + return (SOX_SUCCESS); +} + +static sox_effect_handler_t sox_chorus_effect = { + "chorus", + "gain-in gain-out delay decay speed depth [ -s | -t ]", + SOX_EFF_LENGTH | SOX_EFF_GAIN, + sox_chorus_getopts, + sox_chorus_start, + sox_chorus_flow, + sox_chorus_drain, + sox_chorus_stop, + NULL, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_chorus_effect_fn(void) +{ + return &sox_chorus_effect; +} diff --git a/app/src/main/cpp/sox/compand.c b/app/src/main/cpp/sox/compand.c new file mode 100644 index 0000000..4c3df5c --- /dev/null +++ b/app/src/main/cpp/sox/compand.c @@ -0,0 +1,293 @@ +/* libSoX compander effect + * + * Written by Nick Bailey (nick@bailey-family.org.uk or + * n.bailey@elec.gla.ac.uk) + * + * Copyright 1999 Chris Bagwell And Nick Bailey + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Chris Bagwell And Nick Bailey are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" + +#include +#include +#include "compandt.h" + +/* + * Compressor/expander effect for libSoX. + * + * Flow diagram for one channel: + * + * ------------ --------------- + * | | | | --- + * ibuff ---+---| integrator |--->| transfer func |--->| | + * | | | | | | | + * | ------------ --------------- | | * gain + * | | * |----------->obuff + * | ------- | | + * | | | | | + * +----->| delay |-------------------------->| | + * | | --- + * ------- + */ +#define compand_usage \ + "attack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" \ + "\twhere {} means optional and repeatable and [] means optional.\n" \ + "\tdB values are floating point or -inf'; times are in seconds." +/* + * Note: clipping can occur if the transfer function pushes things too + * close to 0 dB. In that case, use a negative gain, or reduce the + * output level of the transfer function. + */ + +typedef struct { + sox_compandt_t transfer_fn; + + struct { + double attack_times[2]; /* 0:attack_time, 1:decay_time */ + double volume; /* Current "volume" of each channel */ + } * channels; + unsigned expectedChannels;/* Also flags that channels aren't to be treated + individually when = 1 and input not mono */ + double delay; /* Delay to apply before companding */ + sox_sample_t *delay_buf; /* Old samples, used for delay processing */ + ptrdiff_t delay_buf_size;/* Size of delay_buf in samples */ + ptrdiff_t delay_buf_index; /* Index into delay_buf */ + ptrdiff_t delay_buf_cnt; /* No. of active entries in delay_buf */ + int delay_buf_full; /* Shows buffer situation (important for drain) */ + + char *arg0; /* copies of arguments, so that they may be modified */ + char *arg1; + char *arg2; +} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * l = (priv_t *) effp->priv; + char * s; + char dummy; /* To check for extraneous chars. */ + unsigned pairs, i, j, commas; + + --argc, ++argv; + if (argc < 2 || argc > 5) + return lsx_usage(effp); + + l->arg0 = lsx_strdup(argv[0]); + l->arg1 = lsx_strdup(argv[1]); + l->arg2 = argc > 2 ? lsx_strdup(argv[2]) : NULL; + + /* Start by checking the attack and decay rates */ + for (s = l->arg0, commas = 0; *s; ++s) if (*s == ',') ++commas; + if ((commas % 2) == 0) { + lsx_fail("there must be an even number of attack/decay parameters"); + return SOX_EOF; + } + pairs = 1 + commas/2; + l->channels = lsx_calloc(pairs, sizeof(*l->channels)); + l->expectedChannels = pairs; + + /* Now tokenise the rates string and set up these arrays. Keep + them in seconds at the moment: we don't know the sample rate yet. */ + for (i = 0, s = strtok(l->arg0, ","); s != NULL; ++i) { + for (j = 0; j < 2; ++j) { + if (sscanf(s, "%lf %c", &l->channels[i].attack_times[j], &dummy) != 1) { + lsx_fail("syntax error trying to read attack/decay time"); + return SOX_EOF; + } else if (l->channels[i].attack_times[j] < 0) { + lsx_fail("attack & decay times can't be less than 0 seconds"); + return SOX_EOF; + } + s = strtok(NULL, ","); + } + } + + if (!lsx_compandt_parse(&l->transfer_fn, l->arg1, l->arg2)) + return SOX_EOF; + + /* Set the initial "volume" to be attibuted to the input channels. + Unless specified, choose 0dB otherwise clipping will + result if the user has seleced a long attack time */ + for (i = 0; i < l->expectedChannels; ++i) { + double init_vol_dB = 0; + if (argc > 3 && sscanf(argv[3], "%lf %c", &init_vol_dB, &dummy) != 1) { + lsx_fail("syntax error trying to read initial volume"); + return SOX_EOF; + } else if (init_vol_dB > 0) { + lsx_fail("initial volume is relative to maximum volume so can't exceed 0dB"); + return SOX_EOF; + } + l->channels[i].volume = pow(10., init_vol_dB / 20); + } + + /* If there is a delay, store it. */ + if (argc > 4 && sscanf(argv[4], "%lf %c", &l->delay, &dummy) != 1) { + lsx_fail("syntax error trying to read delay value"); + return SOX_EOF; + } else if (l->delay < 0) { + lsx_fail("delay can't be less than 0 seconds"); + return SOX_EOF; + } + + return SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * l = (priv_t *) effp->priv; + unsigned i, j; + + lsx_debug("%i input channel(s) expected: actually %i", + l->expectedChannels, effp->out_signal.channels); + for (i = 0; i < l->expectedChannels; ++i) + lsx_debug("Channel %i: attack = %g decay = %g", i, + l->channels[i].attack_times[0], l->channels[i].attack_times[1]); + if (!lsx_compandt_show(&l->transfer_fn, effp->global_info->plot)) + return SOX_EOF; + + /* Convert attack and decay rates using number of samples */ + for (i = 0; i < l->expectedChannels; ++i) + for (j = 0; j < 2; ++j) + if (l->channels[i].attack_times[j] > 1.0/effp->out_signal.rate) + l->channels[i].attack_times[j] = 1.0 - + exp(-1.0/(effp->out_signal.rate * l->channels[i].attack_times[j])); + else + l->channels[i].attack_times[j] = 1.0; + + /* Allocate the delay buffer */ + l->delay_buf_size = l->delay * effp->out_signal.rate * effp->out_signal.channels; + if (l->delay_buf_size > 0) + l->delay_buf = lsx_calloc((size_t)l->delay_buf_size, sizeof(*l->delay_buf)); + l->delay_buf_index = 0; + l->delay_buf_cnt = 0; + l->delay_buf_full= 0; + + return SOX_SUCCESS; +} + +/* + * Update a volume value using the given sample + * value, the attack rate and decay rate + */ +static void doVolume(double *v, double samp, priv_t * l, int chan) +{ + double s = -samp / SOX_SAMPLE_MIN; + double delta = s - *v; + + if (delta > 0.0) /* increase volume according to attack rate */ + *v += delta * l->channels[chan].attack_times[0]; + else /* reduce volume according to decay rate */ + *v += delta * l->channels[chan].attack_times[1]; +} + +static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * l = (priv_t *) effp->priv; + int len = (*isamp > *osamp) ? *osamp : *isamp; + int filechans = effp->out_signal.channels; + int idone,odone; + + for (idone = 0,odone = 0; idone < len; ibuf += filechans) { + int chan; + + /* Maintain the volume fields by simulating a leaky pump circuit */ + for (chan = 0; chan < filechans; ++chan) { + if (l->expectedChannels == 1 && filechans > 1) { + /* User is expecting same compander for all channels */ + int i; + double maxsamp = 0.0; + for (i = 0; i < filechans; ++i) { + double rect = fabs((double)ibuf[i]); + if (rect > maxsamp) maxsamp = rect; + } + doVolume(&l->channels[0].volume, maxsamp, l, 0); + break; + } else + doVolume(&l->channels[chan].volume, fabs((double)ibuf[chan]), l, chan); + } + + /* Volume memory is updated: perform compand */ + for (chan = 0; chan < filechans; ++chan) { + int ch = l->expectedChannels > 1 ? chan : 0; + double level_in_lin = l->channels[ch].volume; + double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin); + double checkbuf; + + if (l->delay_buf_size <= 0) { + checkbuf = ibuf[chan] * level_out_lin; + SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); + obuf[odone++] = checkbuf; + idone++; + } else { + if (l->delay_buf_cnt >= l->delay_buf_size) { + l->delay_buf_full=1; /* delay buffer is now definitely full */ + checkbuf = l->delay_buf[l->delay_buf_index] * level_out_lin; + SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); + obuf[odone] = checkbuf; + odone++; + idone++; + } else { + l->delay_buf_cnt++; + idone++; /* no "odone++" because we did not fill obuf[...] */ + } + l->delay_buf[l->delay_buf_index++] = ibuf[chan]; + l->delay_buf_index %= l->delay_buf_size; + } + } + } + + *isamp = idone; *osamp = odone; + return (SOX_SUCCESS); +} + +static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * l = (priv_t *) effp->priv; + size_t chan, done = 0; + + if (l->delay_buf_full == 0) + l->delay_buf_index = 0; + while (done+effp->out_signal.channels <= *osamp && l->delay_buf_cnt > 0) + for (chan = 0; chan < effp->out_signal.channels; ++chan) { + int c = l->expectedChannels > 1 ? chan : 0; + double level_in_lin = l->channels[c].volume; + double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin); + obuf[done++] = l->delay_buf[l->delay_buf_index++] * level_out_lin; + l->delay_buf_index %= l->delay_buf_size; + l->delay_buf_cnt--; + } + *osamp = done; + return l->delay_buf_cnt > 0 ? SOX_SUCCESS : SOX_EOF; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * l = (priv_t *) effp->priv; + + free(l->delay_buf); + return SOX_SUCCESS; +} + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * l = (priv_t *) effp->priv; + + lsx_compandt_kill(&l->transfer_fn); + free(l->channels); + free(l->arg0); + free(l->arg1); + free(l->arg2); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_compand_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "compand", compand_usage, SOX_EFF_MCHAN | SOX_EFF_GAIN, + getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/compandt.c b/app/src/main/cpp/sox/compandt.c new file mode 100644 index 0000000..19e6bc9 --- /dev/null +++ b/app/src/main/cpp/sox/compandt.c @@ -0,0 +1,229 @@ +/* libSoX Compander Transfer Function: (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include "compandt.h" +#include + +#define LOG_TO_LOG10(x) ((x) * 20 / M_LN10) + +sox_bool lsx_compandt_show(sox_compandt_t * t, sox_plot_t plot) +{ + int i; + + for (i = 1; t->segments[i-1].x; ++i) + lsx_debug("TF: %g %g %g %g", + LOG_TO_LOG10(t->segments[i].x), + LOG_TO_LOG10(t->segments[i].y), + LOG_TO_LOG10(t->segments[i].a), + LOG_TO_LOG10(t->segments[i].b)); + + if (plot == sox_plot_octave) { + printf( + "%% GNU Octave file (may also work with MATLAB(R) )\n" + "in=linspace(-99.5,0,200);\n" + "out=["); + for (i = -199; i <= 0; ++i) { + double in = i/2.; + double in_lin = pow(10., in/20); + printf("%g ", in + 20 * log10(lsx_compandt(t, in_lin))); + } + printf( + "];\n" + "plot(in,out)\n" + "title('SoX effect: compand')\n" + "xlabel('Input level (dB)')\n" + "ylabel('Output level (dB)')\n" + "grid on\n" + "disp('Hit return to continue')\n" + "pause\n"); + return sox_false; + } + if (plot == sox_plot_gnuplot) { + printf( + "# gnuplot file\n" + "set title 'SoX effect: compand'\n" + "set xlabel 'Input level (dB)'\n" + "set ylabel 'Output level (dB)'\n" + "set grid xtics ytics\n" + "set key off\n" + "plot '-' with lines\n"); + for (i = -199; i <= 0; ++i) { + double in = i/2.; + double in_lin = pow(10., in/20); + printf("%g %g\n", in, in + 20 * log10(lsx_compandt(t, in_lin))); + } + printf( + "e\n" + "pause -1 'Hit return to continue'\n"); + return sox_false; + } + return sox_true; +} + +static void prepare_transfer_fn(sox_compandt_t * t) +{ + int i; + double radius = t->curve_dB * M_LN10 / 20; + + for (i = 0; !i || t->segments[i-2].x; i += 2) { + t->segments[i].y += t->outgain_dB; + t->segments[i].x *= M_LN10 / 20; /* Convert to natural logs */ + t->segments[i].y *= M_LN10 / 20; + } + +#define line1 t->segments[i - 4] +#define curve t->segments[i - 3] +#define line2 t->segments[i - 2] +#define line3 t->segments[i - 0] + for (i = 4; t->segments[i - 2].x; i += 2) { + double x, y, cx, cy, in1, in2, out1, out2, theta, len, r; + + line1.a = 0; + line1.b = (line2.y - line1.y) / (line2.x - line1.x); + + line2.a = 0; + line2.b = (line3.y - line2.y) / (line3.x - line2.x); + + theta = atan2(line2.y - line1.y, line2.x - line1.x); + len = sqrt(pow(line2.x - line1.x, 2.) + pow(line2.y - line1.y, 2.)); + r = min(radius, len); + curve.x = line2.x - r * cos(theta); + curve.y = line2.y - r * sin(theta); + + theta = atan2(line3.y - line2.y, line3.x - line2.x); + len = sqrt(pow(line3.x - line2.x, 2.) + pow(line3.y - line2.y, 2.)); + r = min(radius, len / 2); + x = line2.x + r * cos(theta); + y = line2.y + r * sin(theta); + + cx = (curve.x + line2.x + x) / 3; + cy = (curve.y + line2.y + y) / 3; + + line2.x = x; + line2.y = y; + + in1 = cx - curve.x; + out1 = cy - curve.y; + in2 = line2.x - curve.x; + out2 = line2.y - curve.y; + curve.a = (out2/in2 - out1/in1) / (in2-in1); + curve.b = out1/in1 - curve.a*in1; + } +#undef line1 +#undef curve +#undef line2 +#undef line3 + t->segments[i - 3].x = 0; + t->segments[i - 3].y = t->segments[i - 2].y; + + t->in_min_lin = exp(t->segments[1].x); + t->out_min_lin= exp(t->segments[1].y); +} + +static sox_bool parse_transfer_value(char const * text, double * value) +{ + char dummy; /* To check for extraneous chars. */ + + if (!text) { + lsx_fail("syntax error trying to read transfer function value"); + return sox_false; + } + if (!strcmp(text, "-inf")) + *value = -20 * log10(-(double)SOX_SAMPLE_MIN); + else if (sscanf(text, "%lf %c", value, &dummy) != 1) { + lsx_fail("syntax error trying to read transfer function value"); + return sox_false; + } + else if (*value > 0) { + lsx_fail("transfer function values are relative to maximum volume so can't exceed 0dB"); + return sox_false; + } + return sox_true; +} + +sox_bool lsx_compandt_parse(sox_compandt_t * t, char * points, char * gain) +{ + char const * text = points; + unsigned i, j, num, pairs, commas = 0; + char dummy; /* To check for extraneous chars. */ + + if (sscanf(points, "%lf %c", &t->curve_dB, &dummy) == 2 && dummy == ':') + points = strchr(points, ':') + 1; + else t->curve_dB = 0; + t->curve_dB = max(t->curve_dB, .01); + + while (*text) commas += *text++ == ','; + pairs = 1 + commas / 2; + ++pairs; /* allow room for extra pair at the beginning */ + pairs *= 2; /* allow room for the auto-curves */ + ++pairs; /* allow room for 0,0 at end */ + t->segments = lsx_calloc(pairs, sizeof(*t->segments)); + +#define s(n) t->segments[2*((n)+1)] + for (i = 0, text = strtok(points, ","); text != NULL; ++i) { + if (!parse_transfer_value(text, &s(i).x)) + return sox_false; + if (i && s(i-1).x > s(i).x) { + lsx_fail("transfer function input values must be strictly increasing"); + return sox_false; + } + if (i || (commas & 1)) { + text = strtok(NULL, ","); + if (!parse_transfer_value(text, &s(i).y)) + return sox_false; + s(i).y -= s(i).x; + } + text = strtok(NULL, ","); + } + num = i; + + if (num == 0 || s(num-1).x) /* Add 0,0 if necessary */ + ++num; +#undef s + + if (gain && sscanf(gain, "%lf %c", &t->outgain_dB, &dummy) != 1) { + lsx_fail("syntax error trying to read post-processing gain value"); + return sox_false; + } + +#define s(n) t->segments[2*(n)] + s(0).x = s(1).x - 2 * t->curve_dB; /* Add a tail off segment at the start */ + s(0).y = s(1).y; + ++num; + + for (i = 2; i < num; ++i) { /* Join adjacent colinear segments */ + double g1 = (s(i-1).y - s(i-2).y) * (s(i-0).x - s(i-1).x); + double g2 = (s(i-0).y - s(i-1).y) * (s(i-1).x - s(i-2).x); + if (fabs(g1 - g2)) /* fabs stops epsilon problems */ + continue; + --num; + for (j = --i; j < num; ++j) + s(j) = s(j+1); + } +#undef s + + prepare_transfer_fn(t); + return sox_true; +} + +void lsx_compandt_kill(sox_compandt_t * p) +{ + free(p->segments); +} + diff --git a/app/src/main/cpp/sox/compandt.h b/app/src/main/cpp/sox/compandt.h new file mode 100644 index 0000000..75e0349 --- /dev/null +++ b/app/src/main/cpp/sox/compandt.h @@ -0,0 +1,52 @@ +/* libSoX Compander Transfer Function (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +typedef struct { + struct sox_compandt_segment { + double x, y; /* 1st point in segment */ + double a, b; /* Quadratic coeffecients for rest of segment */ + } * segments; + double in_min_lin; + double out_min_lin; + double outgain_dB; /* Post processor gain */ + double curve_dB; +} sox_compandt_t; + +sox_bool lsx_compandt_parse(sox_compandt_t * t, char * points, char * gain); +sox_bool lsx_compandt_show(sox_compandt_t * t, sox_plot_t plot); +void lsx_compandt_kill(sox_compandt_t * p); + +/* Place in header to allow in-lining */ +static double lsx_compandt(sox_compandt_t * t, double in_lin) +{ + struct sox_compandt_segment * s; + double in_log, out_log; + + if (in_lin <= t->in_min_lin) + return t->out_min_lin; + + in_log = log(in_lin); + + for (s = t->segments + 1; in_log > s[1].x; ++s); + + in_log -= s->x; + out_log = s->y + in_log * (s->a * in_log + s->b); + + return exp(out_log); +} diff --git a/app/src/main/cpp/sox/contrast.c b/app/src/main/cpp/sox/contrast.c new file mode 100644 index 0000000..adbb925 --- /dev/null +++ b/app/src/main/cpp/sox/contrast.c @@ -0,0 +1,49 @@ +/* libSoX effect: Contrast Enhancement (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct {double contrast;} priv_t; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + p->contrast = 75; + --argc, ++argv; + do {NUMERIC_PARAMETER(contrast, 0, 100)} while (0); + p->contrast /= 750; /* shift range to 0 to 0.1333, default 0.1 */ + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len = *isamp = *osamp = min(*isamp, *osamp); + while (len--) { + double d = *ibuf++ * (-M_PI_2 / SOX_SAMPLE_MIN); + *obuf++ = sin(d + p->contrast * sin(d * 4)) * SOX_SAMPLE_MAX; + } + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_contrast_effect_fn(void) +{ + static sox_effect_handler_t handler = {"contrast", "[enhancement (75)]", + 0, create, NULL, flow, NULL, NULL, NULL, sizeof(priv_t)}; + return &handler; +} diff --git a/app/src/main/cpp/sox/coreaudio.c b/app/src/main/cpp/sox/coreaudio.c new file mode 100644 index 0000000..f6f20c1 --- /dev/null +++ b/app/src/main/cpp/sox/coreaudio.c @@ -0,0 +1,418 @@ +/* AudioCore sound handler + * + * Copyright 2008 Chris Bagwell And Sundry Contributors + */ + +#include "sox_i.h" + +#include +#include + +#define Buffactor 4 + +typedef struct { + AudioDeviceID adid; + pthread_mutex_t mutex; + pthread_cond_t cond; + int device_started; + size_t bufsize; + size_t bufrd; + size_t bufwr; + size_t bufrdavail; + float *buf; +} priv_t; + +static OSStatus PlaybackIOProc(AudioDeviceID inDevice UNUSED, + const AudioTimeStamp *inNow UNUSED, + const AudioBufferList *inInputData UNUSED, + const AudioTimeStamp *inInputTime UNUSED, + AudioBufferList *outOutputData, + const AudioTimeStamp *inOutputTime UNUSED, + void *inClientData) +{ + priv_t *ac = (priv_t*)((sox_format_t*)inClientData)->priv; + AudioBuffer *buf; + size_t copylen, avail; + + pthread_mutex_lock(&ac->mutex); + + for(buf = outOutputData->mBuffers; + buf != outOutputData->mBuffers + outOutputData->mNumberBuffers; + buf++){ + + copylen = buf->mDataByteSize / sizeof(float); + if(copylen > ac->bufrdavail) + copylen = ac->bufrdavail; + + avail = ac->bufsize - ac->bufrd; + if(buf->mData == NULL){ + /*do nothing-hardware can't play audio*/ + }else if(copylen > avail){ + memcpy(buf->mData, ac->buf + ac->bufrd, avail * sizeof(float)); + memcpy((float*)buf->mData + avail, ac->buf, (copylen - avail) * sizeof(float)); + }else{ + memcpy(buf->mData, ac->buf + ac->bufrd, copylen * sizeof(float)); + } + + buf->mDataByteSize = copylen * sizeof(float); + ac->bufrd += copylen; + if(ac->bufrd >= ac->bufsize) + ac->bufrd -= ac->bufsize; + ac->bufrdavail -= copylen; + } + + pthread_cond_signal(&ac->cond); + pthread_mutex_unlock(&ac->mutex); + + return kAudioHardwareNoError; +} + +static OSStatus RecIOProc(AudioDeviceID inDevice UNUSED, + const AudioTimeStamp *inNow UNUSED, + const AudioBufferList *inInputData, + const AudioTimeStamp *inInputTime UNUSED, + AudioBufferList *outOutputData UNUSED, + const AudioTimeStamp *inOutputTime UNUSED, + void *inClientData) +{ + priv_t *ac = (priv_t *)((sox_format_t*)inClientData)->priv; + AudioBuffer const *buf; + size_t nfree, copylen, avail; + + pthread_mutex_lock(&ac->mutex); + + for(buf = inInputData->mBuffers; + buf != inInputData->mBuffers + inInputData->mNumberBuffers; + buf++){ + + if(buf->mData == NULL) + continue; + + copylen = buf->mDataByteSize / sizeof(float); + nfree = ac->bufsize - ac->bufrdavail - 1; + if(nfree == 0) + lsx_warn("coreaudio: unhandled buffer overrun. Data discarded."); + + if(copylen > nfree) + copylen = nfree; + + avail = ac->bufsize - ac->bufwr; + if(copylen > avail){ + memcpy(ac->buf + ac->bufwr, buf->mData, avail * sizeof(float)); + memcpy(ac->buf, (float*)buf->mData + avail, (copylen - avail) * sizeof(float)); + }else{ + memcpy(ac->buf + ac->bufwr, buf->mData, copylen * sizeof(float)); + } + + ac->bufwr += copylen; + if(ac->bufwr >= ac->bufsize) + ac->bufwr -= ac->bufsize; + ac->bufrdavail += copylen; + } + + pthread_cond_signal(&ac->cond); + pthread_mutex_unlock(&ac->mutex); + + return kAudioHardwareNoError; +} + +static int setup(sox_format_t *ft, int is_input) +{ + priv_t *ac = (priv_t *)ft->priv; + OSStatus status; + UInt32 property_size; + struct AudioStreamBasicDescription stream_desc; + int32_t buf_size; + int rc; + + if (strncmp(ft->filename, "default", (size_t)7) == 0) + { + property_size = sizeof(ac->adid); + if (is_input) + status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &property_size, &ac->adid); + else + status = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &property_size, &ac->adid); + } + else + { + Boolean is_writable; + status = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &property_size, &is_writable); + + if (status == noErr) + { + int device_count = property_size/sizeof(AudioDeviceID); + AudioDeviceID *devices; + + devices = malloc(property_size); + status = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &property_size, devices); + + if (status == noErr) + { + int i; + for (i = 0; i < device_count; i++) + { + char name[256]; + status = AudioDeviceGetProperty(devices[i],0,false,kAudioDevicePropertyDeviceName,&property_size,&name); + + lsx_report("Found Audio Device \"%s\"\n",name); + + /* String returned from OS is truncated so only compare + * as much as returned. + */ + if (strncmp(name,ft->filename,strlen(name)) == 0) + { + ac->adid = devices[i]; + break; + } + } + } + free(devices); + } + } + + if (status || ac->adid == kAudioDeviceUnknown) + { + lsx_fail_errno(ft, SOX_EPERM, "can not open audio device"); + return SOX_EOF; + } + + /* Query device to get initial values */ + property_size = sizeof(struct AudioStreamBasicDescription); + status = AudioDeviceGetProperty(ac->adid, 0, is_input, + kAudioDevicePropertyStreamFormat, + &property_size, &stream_desc); + if (status) + { + lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties"); + return SOX_EOF; + } + + if (!(stream_desc.mFormatFlags & kLinearPCMFormatFlagIsFloat)) + { + lsx_fail_errno(ft, SOX_EPERM, "audio device does not accept floats"); + return SOX_EOF; + } + + /* OS X effectively only supports these values. */ + ft->signal.channels = 2; + ft->signal.rate = 44100; + ft->encoding.bits_per_sample = 32; + + /* TODO: My limited experience with hardware can only get floats working + * withh a fixed sample rate and stereo. I know that is a limitiation of + * audio device I have so this may not be standard operating orders. + * If some hardware supports setting sample rates and channel counts + * then should do that over resampling and mixing. + */ +#if 0 + stream_desc.mSampleRate = ft->signal.rate; + stream_desc.mChannelsPerFrame = ft->signal.channels; + + /* Write them back */ + property_size = sizeof(struct AudioStreamBasicDescription); + status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input, + kAudioDevicePropertyStreamFormat, + property_size, &stream_desc); + if (status) + { + lsx_fail_errno(ft, SOX_EPERM, "can not set audio device properties"); + return SOX_EOF; + } + + /* Query device to see if it worked */ + property_size = sizeof(struct AudioStreamBasicDescription); + status = AudioDeviceGetProperty(ac->adid, 0, is_input, + kAudioDevicePropertyStreamFormat, + &property_size, &stream_desc); + + if (status) + { + lsx_fail_errno(ft, SOX_EPERM, "can not get audio device properties"); + return SOX_EOF; + } +#endif + + if (stream_desc.mChannelsPerFrame != ft->signal.channels) + { + lsx_debug("audio device did not accept %d channels. Use %d channels instead.", (int)ft->signal.channels, + (int)stream_desc.mChannelsPerFrame); + ft->signal.channels = stream_desc.mChannelsPerFrame; + } + + if (stream_desc.mSampleRate != ft->signal.rate) + { + lsx_debug("audio device did not accept %d sample rate. Use %d instead.", (int)ft->signal.rate, + (int)stream_desc.mSampleRate); + ft->signal.rate = stream_desc.mSampleRate; + } + + ac->bufsize = sox_globals.bufsiz / sizeof(sox_sample_t) * Buffactor; + ac->bufrd = 0; + ac->bufwr = 0; + ac->bufrdavail = 0; + ac->buf = lsx_malloc(ac->bufsize * sizeof(float)); + + buf_size = sox_globals.bufsiz / sizeof(sox_sample_t) * sizeof(float); + property_size = sizeof(buf_size); + status = AudioDeviceSetProperty(ac->adid, NULL, 0, is_input, + kAudioDevicePropertyBufferSize, + property_size, &buf_size); + + rc = pthread_mutex_init(&ac->mutex, NULL); + if (rc) + { + lsx_fail_errno(ft, SOX_EPERM, "failed initializing mutex"); + return SOX_EOF; + } + + rc = pthread_cond_init(&ac->cond, NULL); + if (rc) + { + lsx_fail_errno(ft, SOX_EPERM, "failed initializing condition"); + return SOX_EOF; + } + + ac->device_started = 0; + + /* Registers callback with the device without activating it. */ + if (is_input) + status = AudioDeviceAddIOProc(ac->adid, RecIOProc, (void *)ft); + else + status = AudioDeviceAddIOProc(ac->adid, PlaybackIOProc, (void *)ft); + + return SOX_SUCCESS; +} + +static int startread(sox_format_t *ft) +{ + return setup(ft, 1); +} + +static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp) +{ + priv_t *ac = (priv_t *)ft->priv; + size_t len; + SOX_SAMPLE_LOCALS; + + if (!ac->device_started) { + AudioDeviceStart(ac->adid, RecIOProc); + ac->device_started = 1; + } + + pthread_mutex_lock(&ac->mutex); + + /* Wait until input buffer has been filled by device driver */ + while (ac->bufrdavail == 0) + pthread_cond_wait(&ac->cond, &ac->mutex); + + len = 0; + while(len < nsamp && ac->bufrdavail > 0){ + buf[len] = SOX_FLOAT_32BIT_TO_SAMPLE(ac->buf[ac->bufrd], ft->clips); + len++; + ac->bufrd++; + if(ac->bufrd == ac->bufsize) + ac->bufrd = 0; + ac->bufrdavail--; + } + + pthread_mutex_unlock(&ac->mutex); + + return len; +} + +static int stopread(sox_format_t * ft) +{ + priv_t *ac = (priv_t *)ft->priv; + + AudioDeviceStop(ac->adid, RecIOProc); + AudioDeviceRemoveIOProc(ac->adid, RecIOProc); + pthread_cond_destroy(&ac->cond); + pthread_mutex_destroy(&ac->mutex); + free(ac->buf); + + return SOX_SUCCESS; +} + +static int startwrite(sox_format_t * ft) +{ + return setup(ft, 0); +} + +static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp) +{ + priv_t *ac = (priv_t *)ft->priv; + size_t i; + + SOX_SAMPLE_LOCALS; + + pthread_mutex_lock(&ac->mutex); + + /* Wait to start until mutex is locked to help prevent callback + * getting zero samples. + */ + if(!ac->device_started){ + if(AudioDeviceStart(ac->adid, PlaybackIOProc)){ + pthread_mutex_unlock(&ac->mutex); + return SOX_EOF; + } + ac->device_started = 1; + } + + /* globals.bufsize is in samples + * buf_offset is in bytes + * buf_size is in bytes + */ + for(i = 0; i < nsamp; i++){ + while(ac->bufrdavail == ac->bufsize - 1) + pthread_cond_wait(&ac->cond, &ac->mutex); + + ac->buf[ac->bufwr] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[i], ft->clips); + ac->bufwr++; + if(ac->bufwr == ac->bufsize) + ac->bufwr = 0; + ac->bufrdavail++; + } + + pthread_mutex_unlock(&ac->mutex); + return nsamp; +} + + +static int stopwrite(sox_format_t * ft) +{ + priv_t *ac = (priv_t *)ft->priv; + + if(ac->device_started){ + pthread_mutex_lock(&ac->mutex); + + while (ac->bufrdavail > 0) + pthread_cond_wait(&ac->cond, &ac->mutex); + + pthread_mutex_unlock(&ac->mutex); + + AudioDeviceStop(ac->adid, PlaybackIOProc); + } + + AudioDeviceRemoveIOProc(ac->adid, PlaybackIOProc); + pthread_cond_destroy(&ac->cond); + pthread_mutex_destroy(&ac->mutex); + free(ac->buf); + + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(coreaudio) +{ + static char const *const names[] = { "coreaudio", NULL }; + static unsigned const write_encodings[] = { + SOX_ENCODING_FLOAT, 32, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Mac AudioCore device driver", + names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/cvsd-fmt.c b/app/src/main/cpp/sox/cvsd-fmt.c new file mode 100644 index 0000000..4d42aa7 --- /dev/null +++ b/app/src/main/cpp/sox/cvsd-fmt.c @@ -0,0 +1,114 @@ +/* libSoX file format: CVSD (see cvsd.c) (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "cvsd.h" + +LSX_FORMAT_HANDLER(cvsd) +{ + static char const * const names[] = {"cvsd", "cvs", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Headerless MIL Std 188 113 Continuously Variable Slope Delta modulation", + names, SOX_FILE_MONO, + lsx_cvsdstartread, lsx_cvsdread, lsx_cvsdstopread, + lsx_cvsdstartwrite, lsx_cvsdwrite, lsx_cvsdstopwrite, + lsx_rawseek, write_encodings, NULL, sizeof(cvsd_priv_t) + }; + return &handler; +} + +/* libSoX file format: CVU (c) 2008 robs@users.sourceforge.net + * Unfiltered, therefore, on decode, use with either filter -4k or rate 8k */ + +typedef struct { + double sample, step, step_mult, step_add; + unsigned last_n_bits; + unsigned char byte; + off_t bit_count; +} priv_t; + +static int start(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + + ft->signal.channels = 1; + lsx_rawstart(ft, sox_true, sox_false, sox_true, SOX_ENCODING_CVSD, 1); + p->last_n_bits = 5; /* 101 */ + p->step_mult = exp((-1 / .005 / ft->signal.rate)); + p->step_add = (1 - p->step_mult) * (.1 * SOX_SAMPLE_MAX); + lsx_debug("step_mult=%g step_add=%f", p->step_mult, p->step_add); + return SOX_SUCCESS; +} + +static void decode(priv_t * p, int bit) +{ + p->last_n_bits = ((p->last_n_bits << 1) | bit) & 7; + + p->step *= p->step_mult; + if (p->last_n_bits == 0 || p->last_n_bits == 7) + p->step += p->step_add; + + if (p->last_n_bits & 1) + p->sample = min(p->step_mult * p->sample + p->step, SOX_SAMPLE_MAX); + else + p->sample = max(p->step_mult * p->sample - p->step, SOX_SAMPLE_MIN); +} + +static size_t cvsdread(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + priv_t *p = (priv_t *) ft->priv; + size_t i; + + for (i = 0; i < len; ++i) { + if (!(p->bit_count & 7)) + if (lsx_read_b_buf(ft, &p->byte, (size_t)1) != 1) + break; + ++p->bit_count; + decode(p, p->byte & 1); + p->byte >>= 1; + *buf++ = floor(p->sample + .5); + } + return i; +} + +static size_t cvsdwrite(sox_format_t * ft, sox_sample_t const * buf, size_t len) +{ + priv_t *p = (priv_t *) ft->priv; + size_t i; + + for (i = 0; i < len; ++i) { + decode(p, *buf++ > p->sample); + p->byte >>= 1; + p->byte |= p->last_n_bits << 7; + if (!(++p->bit_count & 7)) + if (lsx_writeb(ft, p->byte) != SOX_SUCCESS) + break; + } + return len; +} + +LSX_FORMAT_HANDLER(cvu) +{ + static char const * const names[] = {"cvu", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Headerless Continuously Variable Slope Delta modulation (unfiltered)", + names, SOX_FILE_MONO, start, cvsdread, NULL, start, cvsdwrite, NULL, + lsx_rawseek, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/cvsd.c b/app/src/main/cpp/sox/cvsd.c new file mode 100644 index 0000000..9e2bbde --- /dev/null +++ b/app/src/main/cpp/sox/cvsd.c @@ -0,0 +1,680 @@ +/* libSoX CVSD (Continuously Variable Slope Delta modulation) + * conversion routines + * + * The CVSD format is described in the MIL Std 188 113, which is + * available from http://bbs.itsi.disa.mil:5580/T3564 + * + * Copyright (C) 1996 + * Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA) + * Swiss Federal Institute of Technology, Electronics Lab + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Change History: + * + * June 1, 1998 - Chris Bagwell (cbagwell@sprynet.com) + * Fixed compile warnings reported by Kjetil Torgrim Homme + * + * + * June 20, 2006 - Kimberly Rockwell (pyxis13317 (at) yahoo.com) + * Speed optimization: Unrolled float_conv() loop in seperate + * functions for encoding and decoding. 15% speed up decoding. + * + * Aug. 24, 2009 - P. Chaintreuil (sox-cvsd-peep (at) parallaxshift.com) + * Speed optimization: Replaced calls to memmove() with a + * mirrored circular buffer. This doubles the size of the + * dec.output_filter (48 -> 96 floats) and enc.input_filter + * (16 -> 32 floats), but keeps the memory from having to + * be copied so many times. 56% speed increase decoding; + * less than 5% encoding speed increase. + */ + +#include "sox_i.h" +#include "cvsd.h" +#include "cvsdfilt.h" + +#include +#include + +/* ---------------------------------------------------------------------- */ +/* + * private data structures + */ + +typedef cvsd_priv_t priv_t; + +static int debug_count = 0; + +/* ---------------------------------------------------------------------- */ + +/* This float_conv() function is not used as more specialized/optimized + * versions exist below. However, those new versions are tied to + * very percise filters defined in cvsdfilt.h. If those are modified + * or different filters are found to be required, this function may + * be needed. Thus I leave it here for possible future use, but commented + * out to avoid compiler warnings about it not being used. +static float float_conv(float const *fp1, float const *fp2,int n) +{ + float res = 0; + for(; n > 0; n--) + res += (*fp1++) * (*fp2++); + return res; +} +*/ + +static float float_conv_enc(float const *fp1, float const *fp2) +{ + /* This is a specialzed version of float_conv() for encoding + * which simply assumes a CVSD_ENC_FILTERLEN (16) length of + * the two arrays and unrolls that loop. + * + * fp1 should be the enc.input_filter array and must be + * CVSD_ENC_FILTERLEN (16) long. + * + * fp2 should be one of the enc_filter_xx_y() tables listed + * in cvsdfilt.h. At minimum, fp2 must be CVSD_ENC_FILTERLEN + * (16) entries long. + */ + float res = 0; + + /* unrolling loop */ + res += fp1[0] * fp2[0]; + res += fp1[1] * fp2[1]; + res += fp1[2] * fp2[2]; + res += fp1[3] * fp2[3]; + res += fp1[4] * fp2[4]; + res += fp1[5] * fp2[5]; + res += fp1[6] * fp2[6]; + res += fp1[7] * fp2[7]; + res += fp1[8] * fp2[8]; + res += fp1[9] * fp2[9]; + res += fp1[10] * fp2[10]; + res += fp1[11] * fp2[11]; + res += fp1[12] * fp2[12]; + res += fp1[13] * fp2[13]; + res += fp1[14] * fp2[14]; + res += fp1[15] * fp2[15]; + + return res; +} + +static float float_conv_dec(float const *fp1, float const *fp2) +{ + /* This is a specialzed version of float_conv() for decoding + * which assumes a specific length and structure to the data + * in fp2. + * + * fp1 should be the dec.output_filter array and must be + * CVSD_DEC_FILTERLEN (48) long. + * + * fp2 should be one of the dec_filter_xx() tables listed + * in cvsdfilt.h. fp2 is assumed to be CVSD_DEC_FILTERLEN + * (48) entries long, is assumed to have 0.0 in the last + * entry, and is a symmetrical mirror around fp2[23] (ie, + * fp2[22] == fp2[24], fp2[0] == fp2[47], etc). + */ + float res = 0; + + /* unrolling loop, also taking advantage of the symmetry + * of the sampling rate array*/ + res += (fp1[0] + fp1[46]) * fp2[0]; + res += (fp1[1] + fp1[45]) * fp2[1]; + res += (fp1[2] + fp1[44]) * fp2[2]; + res += (fp1[3] + fp1[43]) * fp2[3]; + res += (fp1[4] + fp1[42]) * fp2[4]; + res += (fp1[5] + fp1[41]) * fp2[5]; + res += (fp1[6] + fp1[40]) * fp2[6]; + res += (fp1[7] + fp1[39]) * fp2[7]; + res += (fp1[8] + fp1[38]) * fp2[8]; + res += (fp1[9] + fp1[37]) * fp2[9]; + res += (fp1[10] + fp1[36]) * fp2[10]; + res += (fp1[11] + fp1[35]) * fp2[11]; + res += (fp1[12] + fp1[34]) * fp2[12]; + res += (fp1[13] + fp1[33]) * fp2[13]; + res += (fp1[14] + fp1[32]) * fp2[14]; + res += (fp1[15] + fp1[31]) * fp2[15]; + res += (fp1[16] + fp1[30]) * fp2[16]; + res += (fp1[17] + fp1[29]) * fp2[17]; + res += (fp1[18] + fp1[28]) * fp2[18]; + res += (fp1[19] + fp1[27]) * fp2[19]; + res += (fp1[20] + fp1[26]) * fp2[20]; + res += (fp1[21] + fp1[25]) * fp2[21]; + res += (fp1[22] + fp1[24]) * fp2[22]; + res += (fp1[23]) * fp2[23]; + + return res; +} + +/* ---------------------------------------------------------------------- */ +/* + * some remarks about the implementation of the CVSD decoder + * the principal integrator is integrated into the output filter + * to achieve this, the coefficients of the output filter are multiplied + * with (1/(1-1/z)) in the initialisation code. + * the output filter must have a sharp zero at f=0 (i.e. the sum of the + * filter parameters must be zero). This prevents an accumulation of + * DC voltage at the principal integration. + */ +/* ---------------------------------------------------------------------- */ + +static void cvsdstartcommon(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + + p->cvsd_rate = (ft->signal.rate <= 24000) ? 16000 : 32000; + ft->signal.rate = 8000; + ft->signal.channels = 1; + lsx_rawstart(ft, sox_true, sox_false, sox_true, SOX_ENCODING_CVSD, 1); + /* + * initialize the decoder + */ + p->com.overload = 0x5; + p->com.mla_int = 0; + /* + * timeconst = (1/e)^(200 / SR) = exp(-200/SR) + * SR is the sampling rate + */ + p->com.mla_tc0 = exp((-200.0)/((float)(p->cvsd_rate))); + /* + * phase_inc = 32000 / SR + */ + p->com.phase_inc = 32000 / p->cvsd_rate; + /* + * initialize bit shift register + */ + p->bit.shreg = p->bit.cnt = 0; + p->bit.mask = 1; + /* + * count the bytes written + */ + p->bytes_written = 0; + p->com.v_min = 1; + p->com.v_max = -1; + lsx_report("cvsd: bit rate %dbit/s, bits from %s", p->cvsd_rate, + ft->encoding.reverse_bits ? "msb to lsb" : "lsb to msb"); +} + +/* ---------------------------------------------------------------------- */ + +int lsx_cvsdstartread(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + float *fp1; + int i; + + cvsdstartcommon(ft); + + p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0); + p->com.phase = 0; + /* + * initialize the output filter coeffs (i.e. multiply + * the coeffs with (1/(1-1/z)) to achieve integration + * this is now done in the filter parameter generation utility + */ + /* + * zero the filter + */ + for(fp1 = p->c.dec.output_filter, i = CVSD_DEC_FILTERLEN*2; i > 0; i--) + *fp1++ = 0; + /* initialize mirror circular buffer offset to anything sane. */ + p->c.dec.offset = CVSD_DEC_FILTERLEN - 1; + + return (SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +int lsx_cvsdstartwrite(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + float *fp1; + int i; + + cvsdstartcommon(ft); + + p->com.mla_tc1 = 0.1 * (1 - p->com.mla_tc0); + p->com.phase = 4; + /* + * zero the filter + */ + for(fp1 = p->c.enc.input_filter, i = CVSD_ENC_FILTERLEN*2; i > 0; i--) + *fp1++ = 0; + p->c.enc.recon_int = 0; + /* initialize mirror circular buffer offset to anything sane. */ + p->c.enc.offset = CVSD_ENC_FILTERLEN - 1; + + return(SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +int lsx_cvsdstopwrite(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + + if (p->bit.cnt) { + lsx_writeb(ft, p->bit.shreg); + p->bytes_written++; + } + lsx_debug("cvsd: min slope %f, max slope %f", + p->com.v_min, p->com.v_max); + + return (SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +int lsx_cvsdstopread(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + + lsx_debug("cvsd: min value %f, max value %f", + p->com.v_min, p->com.v_max); + + return(SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +size_t lsx_cvsdread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp) +{ + priv_t *p = (priv_t *) ft->priv; + size_t done = 0; + float oval; + + while (done < nsamp) { + if (!p->bit.cnt) { + if (lsx_read_b_buf(ft, &(p->bit.shreg), (size_t) 1) != 1) + return done; + p->bit.cnt = 8; + p->bit.mask = 1; + } + /* + * handle one bit + */ + p->bit.cnt--; + p->com.overload = ((p->com.overload << 1) | + (!!(p->bit.shreg & p->bit.mask))) & 7; + p->bit.mask <<= 1; + p->com.mla_int *= p->com.mla_tc0; + if ((p->com.overload == 0) || (p->com.overload == 7)) + p->com.mla_int += p->com.mla_tc1; + + /* shift output filter window in mirror cirular buffer. */ + if (p->c.dec.offset != 0) + --p->c.dec.offset; + else p->c.dec.offset = CVSD_DEC_FILTERLEN - 1; + /* write into both halves of the mirror circular buffer */ + if (p->com.overload & 1) + { + p->c.dec.output_filter[p->c.dec.offset] = p->com.mla_int; + p->c.dec.output_filter[p->c.dec.offset + CVSD_DEC_FILTERLEN] = p->com.mla_int; + } + else + { + p->c.dec.output_filter[p->c.dec.offset] = -p->com.mla_int; + p->c.dec.output_filter[p->c.dec.offset + CVSD_DEC_FILTERLEN] = -p->com.mla_int; + } + + /* + * check if the next output is due + */ + p->com.phase += p->com.phase_inc; + if (p->com.phase >= 4) { + oval = float_conv_dec( + p->c.dec.output_filter + p->c.dec.offset, + (p->cvsd_rate < 24000) ? + dec_filter_16 : dec_filter_32); + lsx_debug_more("input %d %f\n", debug_count, p->com.mla_int); + lsx_debug_more("recon %d %f\n", debug_count, oval); + debug_count++; + + if (oval > p->com.v_max) + p->com.v_max = oval; + if (oval < p->com.v_min) + p->com.v_min = oval; + *buf++ = (oval * ((float)SOX_SAMPLE_MAX)); + done++; + } + p->com.phase &= 3; + } + return done; +} + +/* ---------------------------------------------------------------------- */ + +size_t lsx_cvsdwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp) +{ + priv_t *p = (priv_t *) ft->priv; + size_t done = 0; + float inval; + + for(;;) { + /* + * check if the next input is due + */ + if (p->com.phase >= 4) { + if (done >= nsamp) + return done; + + /* shift input filter window in mirror cirular buffer. */ + if (p->c.enc.offset != 0) + --p->c.enc.offset; + else p->c.enc.offset = CVSD_ENC_FILTERLEN - 1; + + /* write into both halves of the mirror circular buffer */ + p->c.enc.input_filter[p->c.enc.offset] = + p->c.enc.input_filter[p->c.enc.offset + + CVSD_ENC_FILTERLEN] = + (*buf++) / + ((float)SOX_SAMPLE_MAX); + done++; + } + p->com.phase &= 3; + /* insert input filter here! */ + inval = float_conv_enc( + p->c.enc.input_filter + p->c.enc.offset, + (p->cvsd_rate < 24000) ? + (enc_filter_16[(p->com.phase >= 2)]) : + (enc_filter_32[p->com.phase])); + /* + * encode one bit + */ + p->com.overload = (((p->com.overload << 1) | + (inval > p->c.enc.recon_int)) & 7); + p->com.mla_int *= p->com.mla_tc0; + if ((p->com.overload == 0) || (p->com.overload == 7)) + p->com.mla_int += p->com.mla_tc1; + if (p->com.mla_int > p->com.v_max) + p->com.v_max = p->com.mla_int; + if (p->com.mla_int < p->com.v_min) + p->com.v_min = p->com.mla_int; + if (p->com.overload & 1) { + p->c.enc.recon_int += p->com.mla_int; + p->bit.shreg |= p->bit.mask; + } else + p->c.enc.recon_int -= p->com.mla_int; + if ((++(p->bit.cnt)) >= 8) { + lsx_writeb(ft, p->bit.shreg); + p->bytes_written++; + p->bit.shreg = p->bit.cnt = 0; + p->bit.mask = 1; + } else + p->bit.mask <<= 1; + p->com.phase += p->com.phase_inc; + lsx_debug_more("input %d %f\n", debug_count, inval); + lsx_debug_more("recon %d %f\n", debug_count, p->c.enc.recon_int); + debug_count++; + } +} + +/* ---------------------------------------------------------------------- */ +/* + * DVMS file header + */ + +/* FIXME: eliminate these 4 functions */ + +static uint32_t get32_le(unsigned char **p) +{ + uint32_t val = (((*p)[3]) << 24) | (((*p)[2]) << 16) | + (((*p)[1]) << 8) | (**p); + (*p) += 4; + return val; +} + +static uint16_t get16_le(unsigned char **p) +{ + unsigned val = (((*p)[1]) << 8) | (**p); + (*p) += 2; + return val; +} + +static void put32_le(unsigned char **p, uint32_t val) +{ + *(*p)++ = val & 0xff; + *(*p)++ = (val >> 8) & 0xff; + *(*p)++ = (val >> 16) & 0xff; + *(*p)++ = (val >> 24) & 0xff; +} + +static void put16_le(unsigned char **p, unsigned val) +{ + *(*p)++ = val & 0xff; + *(*p)++ = (val >> 8) & 0xff; +} + +struct dvms_header { + char Filename[14]; + unsigned Id; + unsigned State; + time_t Unixtime; + unsigned Usender; + unsigned Ureceiver; + size_t Length; + unsigned Srate; + unsigned Days; + unsigned Custom1; + unsigned Custom2; + char Info[16]; + char extend[64]; + unsigned Crc; +}; + +#define DVMS_HEADER_LEN 120 + +/* ---------------------------------------------------------------------- */ + +static int dvms_read_header(sox_format_t * ft, struct dvms_header *hdr) +{ + unsigned char hdrbuf[DVMS_HEADER_LEN]; + unsigned char *pch = hdrbuf; + int i; + unsigned sum; + + if (lsx_readbuf(ft, hdrbuf, sizeof(hdrbuf)) != sizeof(hdrbuf)) + { + return (SOX_EOF); + } + for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */ + sum += *pch++; + pch = hdrbuf; + memcpy(hdr->Filename, pch, sizeof(hdr->Filename)); + pch += sizeof(hdr->Filename); + hdr->Id = get16_le(&pch); + hdr->State = get16_le(&pch); + hdr->Unixtime = get32_le(&pch); + hdr->Usender = get16_le(&pch); + hdr->Ureceiver = get16_le(&pch); + hdr->Length = get32_le(&pch); + hdr->Srate = get16_le(&pch); + hdr->Days = get16_le(&pch); + hdr->Custom1 = get16_le(&pch); + hdr->Custom2 = get16_le(&pch); + memcpy(hdr->Info, pch, sizeof(hdr->Info)); + pch += sizeof(hdr->Info); + memcpy(hdr->extend, pch, sizeof(hdr->extend)); + pch += sizeof(hdr->extend); + hdr->Crc = get16_le(&pch); + if (sum != hdr->Crc) + { + lsx_report("DVMS header checksum error, read %u, calculated %u", + hdr->Crc, sum); + return (SOX_EOF); + } + return (SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +/* + * note! file must be seekable + */ +static int dvms_write_header(sox_format_t * ft, struct dvms_header *hdr) +{ + unsigned char hdrbuf[DVMS_HEADER_LEN]; + unsigned char *pch = hdrbuf; + unsigned char *pchs = hdrbuf; + int i; + unsigned sum; + + memcpy(pch, hdr->Filename, sizeof(hdr->Filename)); + pch += sizeof(hdr->Filename); + put16_le(&pch, hdr->Id); + put16_le(&pch, hdr->State); + put32_le(&pch, (unsigned)hdr->Unixtime); + put16_le(&pch, hdr->Usender); + put16_le(&pch, hdr->Ureceiver); + put32_le(&pch, (unsigned) hdr->Length); + put16_le(&pch, hdr->Srate); + put16_le(&pch, hdr->Days); + put16_le(&pch, hdr->Custom1); + put16_le(&pch, hdr->Custom2); + memcpy(pch, hdr->Info, sizeof(hdr->Info)); + pch += sizeof(hdr->Info); + memcpy(pch, hdr->extend, sizeof(hdr->extend)); + pch += sizeof(hdr->extend); + for(i = sizeof(hdrbuf), sum = 0; i > /*2*/3; i--) /* Deti bug */ + sum += *pchs++; + hdr->Crc = sum; + put16_le(&pch, hdr->Crc); + if (lsx_seeki(ft, (off_t)0, SEEK_SET) < 0) + { + lsx_report("seek failed\n: %s",strerror(errno)); + return (SOX_EOF); + } + if (lsx_writebuf(ft, hdrbuf, sizeof(hdrbuf)) != sizeof(hdrbuf)) + { + lsx_report("%s",strerror(errno)); + return (SOX_EOF); + } + return (SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +static void make_dvms_hdr(sox_format_t * ft, struct dvms_header *hdr) +{ + priv_t *p = (priv_t *) ft->priv; + size_t len; + char * comment = lsx_cat_comments(ft->oob.comments); + + memset(hdr->Filename, 0, sizeof(hdr->Filename)); + len = strlen(ft->filename); + if (len >= sizeof(hdr->Filename)) + len = sizeof(hdr->Filename)-1; + memcpy(hdr->Filename, ft->filename, len); + hdr->Id = hdr->State = 0; + hdr->Unixtime = sox_globals.repeatable? 0 : time(NULL); + hdr->Usender = hdr->Ureceiver = 0; + hdr->Length = p->bytes_written; + hdr->Srate = p->cvsd_rate/100; + hdr->Days = hdr->Custom1 = hdr->Custom2 = 0; + memset(hdr->Info, 0, sizeof(hdr->Info)); + len = strlen(comment); + if (len >= sizeof(hdr->Info)) + len = sizeof(hdr->Info)-1; + memcpy(hdr->Info, comment, len); + memset(hdr->extend, 0, sizeof(hdr->extend)); + free(comment); +} + +/* ---------------------------------------------------------------------- */ + +int lsx_dvmsstartread(sox_format_t * ft) +{ + struct dvms_header hdr; + int rc; + + rc = dvms_read_header(ft, &hdr); + if (rc){ + lsx_fail_errno(ft,SOX_EHDR,"unable to read DVMS header"); + return rc; + } + + lsx_debug("DVMS header of source file \"%s\":", ft->filename); + lsx_debug(" filename \"%.14s\"", hdr.Filename); + lsx_debug(" id 0x%x", hdr.Id); + lsx_debug(" state 0x%x", hdr.State); + lsx_debug(" time %s", ctime(&hdr.Unixtime)); /* ctime generates lf */ + lsx_debug(" usender %u", hdr.Usender); + lsx_debug(" ureceiver %u", hdr.Ureceiver); + lsx_debug(" length %" PRIuPTR, hdr.Length); + lsx_debug(" srate %u", hdr.Srate); + lsx_debug(" days %u", hdr.Days); + lsx_debug(" custom1 %u", hdr.Custom1); + lsx_debug(" custom2 %u", hdr.Custom2); + lsx_debug(" info \"%.16s\"", hdr.Info); + ft->signal.rate = (hdr.Srate < 240) ? 16000 : 32000; + lsx_debug("DVMS rate %dbit/s using %gbit/s deviation %g%%", + hdr.Srate*100, ft->signal.rate, + ((ft->signal.rate - hdr.Srate*100) * 100) / ft->signal.rate); + rc = lsx_cvsdstartread(ft); + if (rc) + return rc; + + return(SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +int lsx_dvmsstartwrite(sox_format_t * ft) +{ + struct dvms_header hdr; + int rc; + + rc = lsx_cvsdstartwrite(ft); + if (rc) + return rc; + + make_dvms_hdr(ft, &hdr); + rc = dvms_write_header(ft, &hdr); + if (rc){ + lsx_fail_errno(ft,rc,"cannot write DVMS header"); + return rc; + } + + if (!ft->seekable) + lsx_warn("Length in output .DVMS header will wrong since can't seek to fix it"); + + return(SOX_SUCCESS); +} + +/* ---------------------------------------------------------------------- */ + +int lsx_dvmsstopwrite(sox_format_t * ft) +{ + struct dvms_header hdr; + int rc; + + lsx_cvsdstopwrite(ft); + if (!ft->seekable) + { + lsx_warn("File not seekable"); + return (SOX_EOF); + } + if (lsx_seeki(ft, (off_t)0, 0) != 0) + { + lsx_fail_errno(ft,errno,"Can't rewind output file to rewrite DVMS header."); + return(SOX_EOF); + } + make_dvms_hdr(ft, &hdr); + rc = dvms_write_header(ft, &hdr); + if(rc){ + lsx_fail_errno(ft,rc,"cannot write DVMS header"); + return rc; + } + return rc; +} diff --git a/app/src/main/cpp/sox/cvsd.h b/app/src/main/cpp/sox/cvsd.h new file mode 100644 index 0000000..a4bb39a --- /dev/null +++ b/app/src/main/cpp/sox/cvsd.h @@ -0,0 +1,68 @@ +/* libSoX DVMS format module (implementation in cvsd.c) + * + * Copyright (C) 1996-2007 Thomas Sailer and SoX Contributors + * Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA) + * Swiss Federal Institute of Technology, Electronics Lab + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#include "sox_i.h" + +#define CVSD_ENC_FILTERLEN 16 /* PCM sampling rate */ +#define CVSD_DEC_FILTERLEN 48 /* CVSD sampling rate */ + +typedef struct { + struct { + unsigned overload; + float mla_int; + float mla_tc0; + float mla_tc1; + unsigned phase; + unsigned phase_inc; + float v_min, v_max; + } com; + union { + struct { + /* mirror circular buffer */ + float output_filter[CVSD_DEC_FILTERLEN*2]; + unsigned offset; /* into output_filter; always in first half */ + } dec; + struct { + float recon_int; + /* mirror circular buffer */ + float input_filter[CVSD_ENC_FILTERLEN*2]; + unsigned offset; /* into input_filter; always in first half */ + } enc; + } c; + struct { + unsigned char shreg; + unsigned mask; + unsigned cnt; + } bit; + unsigned bytes_written; + unsigned cvsd_rate; +} cvsd_priv_t; + +int lsx_cvsdstartread(sox_format_t * ft); +int lsx_cvsdstartwrite(sox_format_t * ft); +size_t lsx_cvsdread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp); +size_t lsx_cvsdwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp); +int lsx_cvsdstopread(sox_format_t * ft); +int lsx_cvsdstopwrite(sox_format_t * ft); + +int lsx_dvmsstartread(sox_format_t * ft); +int lsx_dvmsstartwrite(sox_format_t * ft); +int lsx_dvmsstopwrite(sox_format_t * ft); diff --git a/app/src/main/cpp/sox/cvsdfilt.h b/app/src/main/cpp/sox/cvsdfilt.h new file mode 100644 index 0000000..c03f841 --- /dev/null +++ b/app/src/main/cpp/sox/cvsdfilt.h @@ -0,0 +1,112 @@ +/* libSoX CVSD (Continuously Variable Slope Delta modulation) + * conversion routines + * + * The CVSD format is described in the MIL Std 188 113, which is + * available from http://bbs.itsi.disa.mil:5580/T3564 + * + * Copyright (C) 1996 + * Thomas Sailer (sailer@ife.ee.ethz.ch) (HB9JNX/AE4WA) + * Swiss Federal Institute of Technology, Electronics Lab + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static const float dec_filter_16[48] = { + 0.001102, 0.001159, 0.000187, -0.000175, + 0.002097, 0.006543, 0.009384, 0.008004, + 0.006562, 0.013569, 0.030745, 0.047053, + 0.050491, 0.047388, 0.062171, 0.109115, + 0.167120, 0.197144, 0.195471, 0.222098, + 0.354745, 0.599184, 0.849632, 0.956536, + 0.849632, 0.599184, 0.354745, 0.222098, + 0.195471, 0.197144, 0.167120, 0.109115, + 0.062171, 0.047388, 0.050491, 0.047053, + 0.030745, 0.013569, 0.006562, 0.008004, + 0.009384, 0.006543, 0.002097, -0.000175, + 0.000187, 0.001159, 0.001102, 0.000000 +}; + +/* ---------------------------------------------------------------------- */ + +static const float dec_filter_32[48] = { + 0.001950, 0.004180, 0.006331, 0.007907, + 0.008510, 0.008342, 0.008678, 0.011827, + 0.020282, 0.035231, 0.055200, 0.075849, + 0.091585, 0.098745, 0.099031, 0.101287, + 0.120058, 0.170672, 0.262333, 0.392047, + 0.542347, 0.684488, 0.786557, 0.823702, + 0.786557, 0.684488, 0.542347, 0.392047, + 0.262333, 0.170672, 0.120058, 0.101287, + 0.099031, 0.098745, 0.091585, 0.075849, + 0.055200, 0.035231, 0.020282, 0.011827, + 0.008678, 0.008342, 0.008510, 0.007907, + 0.006331, 0.004180, 0.001950, -0.000000 +}; + +/* ---------------------------------------------------------------------- */ + +static const float enc_filter_16_0[16] = { + -0.000362, 0.004648, 0.001381, 0.008312, + 0.041490, -0.001410, 0.124061, 0.247446, + -0.106761, -0.236326, -0.023798, -0.023506, + -0.030097, 0.001493, -0.005363, -0.001672 +}; + +static const float enc_filter_16_1[16] = { + 0.001672, 0.005363, -0.001493, 0.030097, + 0.023506, 0.023798, 0.236326, 0.106761, + -0.247446, -0.124061, 0.001410, -0.041490, + -0.008312, -0.001381, -0.004648, 0.000362 +}; + +static const float *enc_filter_16[2] = { + enc_filter_16_0, enc_filter_16_1 +}; + +/* ---------------------------------------------------------------------- */ + +static const float enc_filter_32_0[16] = { + -0.000289, 0.002112, 0.001421, 0.002235, + 0.021003, 0.001237, 0.047132, 0.129636, + -0.027328, -0.126462, -0.021456, -0.008069, + -0.017959, 0.000301, -0.002538, -0.001278 +}; + +static const float enc_filter_32_1[16] = { + -0.000010, 0.002787, 0.000055, 0.006813, + 0.020249, -0.000995, 0.077912, 0.112870, + -0.076980, -0.106971, -0.005096, -0.015449, + -0.012591, 0.000813, -0.003003, -0.000527 +}; + +static const float enc_filter_32_2[16] = { + 0.000527, 0.003003, -0.000813, 0.012591, + 0.015449, 0.005096, 0.106971, 0.076980, + -0.112870, -0.077912, 0.000995, -0.020249, + -0.006813, -0.000055, -0.002787, 0.000010 +}; + +static const float enc_filter_32_3[16] = { + 0.001278, 0.002538, -0.000301, 0.017959, + 0.008069, 0.021456, 0.126462, 0.027328, + -0.129636, -0.047132, -0.001237, -0.021003, + -0.002235, -0.001421, -0.002112, 0.000289 +}; + +static const float *enc_filter_32[4] = { + enc_filter_32_0, enc_filter_32_1, enc_filter_32_2, enc_filter_32_3 +}; + +/* ---------------------------------------------------------------------- */ diff --git a/app/src/main/cpp/sox/dat.c b/app/src/main/cpp/sox/dat.c new file mode 100644 index 0000000..b014f23 --- /dev/null +++ b/app/src/main/cpp/sox/dat.c @@ -0,0 +1,162 @@ +/* libSoX text format file. Tom Littlejohn, March 93. + * + * Reads/writes sound files as text. + * + * Copyright 1998-2006 Chris Bagwell and SoX Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" +#include + +#define LINEWIDTH (size_t)256 + +/* Private data for dat file */ +typedef struct { + double timevalue, deltat; + int buffered; + char prevline[LINEWIDTH]; +} priv_t; + +static int sox_datstartread(sox_format_t * ft) +{ + char inpstr[LINEWIDTH]; + long rate; + int chan; + int status; + char sc; + + /* Read lines until EOF or first non-comment line */ + while ((status = lsx_reads(ft, inpstr, LINEWIDTH-1)) != SOX_EOF) { + inpstr[LINEWIDTH-1] = 0; + if ((sscanf(inpstr," %c", &sc) != 0) && (sc != ';')) break; + if (sscanf(inpstr," ; Sample Rate %ld", &rate)) { + ft->signal.rate=rate; + } else if (sscanf(inpstr," ; Channels %d", &chan)) { + ft->signal.channels=chan; + } + } + /* Hold a copy of the last line we read (first non-comment) */ + if (status != SOX_EOF) { + strncpy(((priv_t *)ft->priv)->prevline, inpstr, (size_t)LINEWIDTH); + ((priv_t *)ft->priv)->buffered = 1; + } else { + ((priv_t *)ft->priv)->buffered = 0; + } + + /* Default channels to 1 if not found */ + if (ft->signal.channels == 0) + ft->signal.channels = 1; + + ft->encoding.encoding = SOX_ENCODING_FLOAT_TEXT; + + return (SOX_SUCCESS); +} + +static int sox_datstartwrite(sox_format_t * ft) +{ + priv_t * dat = (priv_t *) ft->priv; + char s[LINEWIDTH]; + + dat->timevalue = 0.0; + dat->deltat = 1.0 / (double)ft->signal.rate; + /* Write format comments to start of file */ + sprintf(s,"; Sample Rate %ld\015\n", (long)ft->signal.rate); + lsx_writes(ft, s); + sprintf(s,"; Channels %d\015\n", (int)ft->signal.channels); + lsx_writes(ft, s); + + return (SOX_SUCCESS); +} + +static size_t sox_datread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp) +{ + char inpstr[LINEWIDTH]; + int inpPtr = 0; + int inpPtrInc = 0; + double sampval = 0.0; + int retc = 0; + char sc = 0; + size_t done = 0; + size_t i=0; + + /* Always read a complete set of channels */ + nsamp -= (nsamp % ft->signal.channels); + + while (done < nsamp) { + + /* Read a line or grab the buffered first line */ + if (((priv_t *)ft->priv)->buffered) { + strncpy(inpstr, ((priv_t *)ft->priv)->prevline, (size_t)LINEWIDTH); + inpstr[LINEWIDTH-1] = 0; + ((priv_t *)ft->priv)->buffered=0; + } else { + lsx_reads(ft, inpstr, LINEWIDTH-1); + inpstr[LINEWIDTH-1] = 0; + if (lsx_eof(ft)) return (done); + } + + /* Skip over comments - ie. 0 or more whitespace, then ';' */ + if ((sscanf(inpstr," %c", &sc) != 0) && (sc==';')) continue; + + /* Read a complete set of channels */ + sscanf(inpstr," %*s%n", &inpPtr); + for (i=0; isignal.channels; i++) { + SOX_SAMPLE_LOCALS; + retc = sscanf(&inpstr[inpPtr]," %lg%n", &sampval, &inpPtrInc); + inpPtr += inpPtrInc; + if (retc != 1) { + lsx_fail_errno(ft,SOX_EOF,"Unable to read sample."); + return 0; + } + *buf++ = SOX_FLOAT_64BIT_TO_SAMPLE(sampval, ft->clips); + done++; + } + } + + return (done); +} + +static size_t sox_datwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp) +{ + priv_t * dat = (priv_t *) ft->priv; + size_t done = 0; + double sampval=0.0; + char s[LINEWIDTH]; + size_t i=0; + + /* Always write a complete set of channels */ + nsamp -= (nsamp % ft->signal.channels); + + /* Write time, then sample values, then CRLF newline */ + while(done < nsamp) { + sprintf(s," %15.8g ",dat->timevalue); + lsx_writes(ft, s); + for (i=0; isignal.channels; i++) { + sampval = SOX_SAMPLE_TO_FLOAT_64BIT(*buf++, ft->clips); + sprintf(s," %15.11g", sampval); + lsx_writes(ft, s); + done++; + } + sprintf(s," \r\n"); + lsx_writes(ft, s); + dat->timevalue += dat->deltat; + } + return done; +} + +LSX_FORMAT_HANDLER(dat) +{ + static char const * const names[] = {"dat", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_FLOAT_TEXT, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Textual representation of the sampled audio", names, 0, + sox_datstartread, sox_datread, NULL, + sox_datstartwrite, sox_datwrite, NULL, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/dcshift.c b/app/src/main/cpp/sox/dcshift.c new file mode 100644 index 0000000..07d881d --- /dev/null +++ b/app/src/main/cpp/sox/dcshift.c @@ -0,0 +1,165 @@ +/* libSoX dcshift.c + * (c) 2000.04.15 Chris Ausbrooks + * + * based on vol.c which is + * (c) 20/03/2000 Fabien COELHO for sox. + * + * DC shift a sound file, with basic linear amplitude formula. + * Beware of saturations! clipping is checked and reported. + * Cannot handle different number of channels. + * Cannot handle rate change. + */ + +#include "sox_i.h" + +typedef struct { + double dcshift; /* DC shift. */ + int uselimiter; /* boolean: are we using the limiter? */ + double limiterthreshhold; + double limitergain; /* limiter gain. */ + uint64_t limited; /* number of limited values to report. */ + uint64_t totalprocessed; +} priv_t; + +/* + * Process options: dcshift (double) type (amplitude, power, dB) + */ +static int sox_dcshift_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * dcs = (priv_t *) effp->priv; + dcs->dcshift = 1.0; /* default is no change */ + dcs->uselimiter = 0; /* default is no limiter */ + + --argc, ++argv; + if (argc < 1) + return lsx_usage(effp); + + if (argc && (!sscanf(argv[0], "%lf", &dcs->dcshift))) + return lsx_usage(effp); + + if (argc>1) + { + if (!sscanf(argv[1], "%lf", &dcs->limitergain)) + return lsx_usage(effp); + + dcs->uselimiter = 1; /* ok, we'll use it */ + /* The following equation is derived so that there is no + * discontinuity in output amplitudes */ + /* and a SOX_SAMPLE_MAX input always maps to a SOX_SAMPLE_MAX output + * when the limiter is activated. */ + /* (NOTE: There **WILL** be a discontinuity in the slope of the + * output amplitudes when using the limiter.) */ + dcs->limiterthreshhold = SOX_SAMPLE_MAX * (1.0 - (fabs(dcs->dcshift) - dcs->limitergain)); + } + + return SOX_SUCCESS; +} + +/* + * Start processing + */ +static int sox_dcshift_start(sox_effect_t * effp) +{ + priv_t * dcs = (priv_t *) effp->priv; + + if (dcs->dcshift == 0) + return SOX_EFF_NULL; + + dcs->limited = 0; + dcs->totalprocessed = 0; + + return SOX_SUCCESS; +} + +/* + * Process data. + */ +static int sox_dcshift_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * dcs = (priv_t *) effp->priv; + double dcshift = dcs->dcshift; + double limitergain = dcs->limitergain; + double limiterthreshhold = dcs->limiterthreshhold; + double sample; + size_t len; + + len = min(*osamp, *isamp); + + /* report back dealt with amount. */ + *isamp = len; *osamp = len; + + if (dcs->uselimiter) + { + dcs->totalprocessed += len; + + for (;len>0; len--) + { + sample = *ibuf++; + + if (sample > limiterthreshhold && dcshift > 0) + { + sample = (sample - limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) + limiterthreshhold + dcshift; + dcs->limited++; + } + else if (sample < -limiterthreshhold && dcshift < 0) + { + /* Note this should really be SOX_SAMPLE_MIN but + * the clip() below will take care of the overflow. + */ + sample = (sample + limiterthreshhold) * limitergain / (SOX_SAMPLE_MAX - limiterthreshhold) - limiterthreshhold + dcshift; + dcs->limited++; + } + else + { + /* Note this should consider SOX_SAMPLE_MIN but + * the clip() below will take care of the overflow. + */ + sample = dcshift * SOX_SAMPLE_MAX + sample; + } + + SOX_SAMPLE_CLIP_COUNT(sample, effp->clips); + *obuf++ = sample; + } + } + else for (; len > 0; --len) { /* quite basic, with clipping */ + double d = dcshift * (SOX_SAMPLE_MAX + 1.) + *ibuf++; + *obuf++ = SOX_ROUND_CLIP_COUNT(d, effp->clips); + } + return SOX_SUCCESS; +} + +/* + * Do anything required when you stop reading samples. + * Don't close input file! + */ +static int sox_dcshift_stop(sox_effect_t * effp) +{ + priv_t * dcs = (priv_t *) effp->priv; + + if (dcs->limited) + { + lsx_warn("DCSHIFT limited %" PRIu64 " values (%d percent).", + dcs->limited, (int) (dcs->limited * 100.0 / dcs->totalprocessed)); + } + return SOX_SUCCESS; +} + +static sox_effect_handler_t sox_dcshift_effect = { + "dcshift", + "shift [ limitergain ]\n" + "\tThe peak limiter has a gain much less than 1.0 (ie 0.05 or 0.02) which\n" + "\tis only used on peaks to prevent clipping. (default is no limiter)", + SOX_EFF_MCHAN | SOX_EFF_GAIN, + sox_dcshift_getopts, + sox_dcshift_start, + sox_dcshift_flow, + NULL, + sox_dcshift_stop, + NULL, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_dcshift_effect_fn(void) +{ + return &sox_dcshift_effect; +} diff --git a/app/src/main/cpp/sox/deemph.plt b/app/src/main/cpp/sox/deemph.plt new file mode 100644 index 0000000..0dc9cd9 --- /dev/null +++ b/app/src/main/cpp/sox/deemph.plt @@ -0,0 +1,118 @@ +# 15/50us EIAJ de-emphasis filter for CD/DAT +# +# 09/02/98 (c) Heiko Eissfeldt +# +# 18/03/07 robs@users.sourceforge.net: changed to biquad for slightly +# better accuracy. +# +# License: LGPL (Lesser Gnu Public License) +# +# This implements the inverse filter of the optional pre-emphasis stage +# as defined by IEC 60908 (describing the audio cd format). +# +# Background: In the early days of audio cds, there were recording +# problems with noise (for example in classical recordings). The high +# dynamics of audio cds exposed these recording errors a lot. +# +# The commonly used solution at that time was to 'pre-emphasize' the +# trebles to have a better signal-noise-ratio. That is trebles were +# amplified before recording, so that they would give a stronger signal +# compared to the underlying (tape) noise. +# +# For that purpose the audio signal was prefiltered with the following +# frequency response (simple first order filter): +# +# V (in dB) +# ^ +# | +# |~10dB _________________ +# | / +# | / | +# | 20dB / decade ->/ | +# | / | +# |____________________/_ _ |_ _ _ _ _ _ _ _ _ Frequency +# |0 dB | | +# | | | +# | | | +# 3.1kHz ~10kHz +# +# So the recorded audio signal has amplified trebles compared to the +# original. HiFi cd players do correct this by applying an inverse +# filter automatically, the cd-rom drives or cd burners used by digital +# sampling programs (like cdda2wav) however do not. +# +# So, this is what this effect does. +# +# This is the gnuplot file for the frequency response of the deemphasis. +# +# The absolute error is <=0.04dB up to ~12kHz, and <=0.06dB up to 20kHz. + +# First define the ideal filter: + +# Filter parameters +T = 1. / 441000. # we use the tenfold sampling frequency +OmegaU = 1. / 15e-6 +OmegaL = 15. / 50. * OmegaU + +# Calculate filter coefficients +V0 = OmegaL / OmegaU +H0 = V0 - 1. +B = V0 * tan(OmegaU * T / 2.) +A1 = (B - 1.) / (B + 1.) +B0 = (1. + (1. - A1) * H0 / 2.) +B1 = (A1 + (A1 - 1.) * H0 / 2.) + +# helper variables +D = B1 / B0 +O = 2 * pi * T + +# Ideal transfer function +Hi(f) = B0*sqrt((1 + 2*cos(f*O)*D + D*D)/(1 + 2*cos(f*O)*A1 + A1*A1)) + +# Now use a biquad (RBJ high shelf) with sampling frequency of 44100Hz +# to approximate the ideal curve: + +# Filter parameters +t = 1. / 44100. +gain = -9.477 +slope = .4845 +f0 = 5283 + +# Calculate filter coefficients +A = exp(gain / 40. * log(10.)) +w0 = 2. * pi * f0 * t +alpha = sin(w0) / 2. * sqrt((A + 1. / A) * (1. / slope - 1.) + 2.) +b0 = A * ((A + 1.) + (A - 1.) * cos(w0) + 2. * sqrt(A) * alpha) +b1 = -2. * A * ((A - 1.) + (A + 1.) * cos(w0)) +b2 = A * ((A + 1.) + (A - 1.) * cos(w0) - 2. * sqrt(A) * alpha) +a0 = (A + 1.) - (A - 1.) * cos(w0) + 2. * sqrt(A) * alpha +a1 = 2. * ((A - 1.) - (A + 1.) * cos(w0)) +a2 = (A + 1.) - (A - 1.) * cos(w0) - 2. * sqrt(A) * alpha +b2 = b2 / a0 +b1 = b1 / a0 +b0 = b0 / a0 +a2 = a2 / a0 +a1 = a1 / a0 + +# helper variables +o = 2 * pi * t + +# Best fit transfer function +Hb(f) = sqrt((b0*b0 + b1*b1 + b2*b2 +\ + 2.*(b0*b1 + b1*b2)*cos(f*o) + 2.*(b0*b2)* cos(2.*f*o)) /\ + (1. + a1*a1 + a2*a2 + 2.*(a1 + a1*a2)*cos(f*o) + 2.*a2*cos(2.*f*o))) + +# plot real, best, ideal, level with halved attenuation, +# level at full attentuation, 10fold magnified error +set logscale x +set grid xtics ytics mxtics mytics +set key left bottom +plot [f=1000:20000] [-12:2] \ +20 * log10(Hi(f)),\ +20 * log10(Hb(f)),\ +20 * log10(OmegaL/(2 * pi * f)),\ +.5 * 20 * log10(V0),\ +20 * log10(V0),\ +200 * log10(Hb(f)/Hi(f)) + +pause -1 "Hit return to continue" diff --git a/app/src/main/cpp/sox/delay.c b/app/src/main/cpp/sox/delay.c new file mode 100644 index 0000000..14da6ac --- /dev/null +++ b/app/src/main/cpp/sox/delay.c @@ -0,0 +1,163 @@ +/* libSoX effect: Delay one or more channels (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +typedef struct { + size_t argc; + struct { char *str; uint64_t delay; } *args; + uint64_t *max_delay; + uint64_t delay, pre_pad, pad; + size_t buffer_size, buffer_index; + sox_sample_t * buffer; + sox_bool drain_started; +} priv_t; + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + + for (i = 0; i < p->argc; ++i) + free(p->args[i].str); + free(p->args); + free(p->max_delay); + return SOX_SUCCESS; +} + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + + --argc, ++argv; + p->argc = argc; + p->args = lsx_calloc(p->argc, sizeof(*p->args)); + p->max_delay = lsx_malloc(sizeof(*p->max_delay)); + for (i = 0; i < p->argc; ++i) { + char const * next = lsx_parseposition(0., p->args[i].str = lsx_strdup(argv[i]), NULL, (uint64_t)0, (uint64_t)0, '='); + if (!next || *next) { + lsx_kill(effp); + return lsx_usage(effp); + } + } + return SOX_SUCCESS; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + free(p->buffer); + return SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + uint64_t max_delay = 0, last_seen = 0, delay; + uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN; + + if (effp->flow == 0) { + unsigned i; + if (p->argc > effp->in_signal.channels) { + lsx_fail("too few input channels"); + return SOX_EOF; + } + for (i = 0; i < p->argc; ++i) { + if (!lsx_parseposition(effp->in_signal.rate, p->args[i].str, &delay, last_seen, in_length, '=') || delay == SOX_UNKNOWN_LEN) { + lsx_fail("Position relative to end of audio specified, but audio length is unknown"); + return SOX_EOF; + } + p->args[i].delay = last_seen = delay; + if (delay > max_delay) { + max_delay = delay; + } + } + *p->max_delay = max_delay; + if (max_delay == 0) + return SOX_EFF_NULL; + effp->out_signal.length = effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length + max_delay * effp->in_signal.channels : + SOX_UNKNOWN_LEN; + lsx_debug("extending audio by %" PRIu64 " samples", max_delay); + } + + max_delay = *p->max_delay; + if (effp->flow < p->argc) + p->buffer_size = p->args[effp->flow].delay; + p->buffer_index = p->delay = p->pre_pad = 0; + p->pad = max_delay - p->buffer_size; + p->buffer = lsx_malloc(p->buffer_size * sizeof(*p->buffer)); + p->drain_started = sox_false; + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len = *isamp = *osamp = min(*isamp, *osamp); + + if (!p->buffer_size) + memcpy(obuf, ibuf, len * sizeof(*obuf)); + else for (; len; --len) { + if (p->delay < p->buffer_size) { + p->buffer[p->delay++] = *ibuf++; + *obuf++ = 0; + } else { + *obuf++ = p->buffer[p->buffer_index]; + p->buffer[p->buffer_index++] = *ibuf++; + p->buffer_index %= p->buffer_size; + } + } + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len; + if (! p->drain_started) { + p->drain_started = sox_true; + p->pre_pad = p->buffer_size - p->delay; + /* If the input was too short to fill the buffer completely, + flow() has not yet output enough silence to reach the + desired delay. */ + } + len = *osamp = min(p->pre_pad + p->delay + p->pad, *osamp); + + for (; p->pre_pad && len; --p->pre_pad, --len) + *obuf++ = 0; + for (; p->delay && len; --p->delay, --len) { + *obuf++ = p->buffer[p->buffer_index++]; + p->buffer_index %= p->buffer_size; + } + for (; p->pad && len; --p->pad, --len) + *obuf++ = 0; + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_delay_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "delay", "{position}", SOX_EFF_LENGTH | SOX_EFF_MODIFY, + create, start, flow, drain, stop, lsx_kill, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/dft_filter.c b/app/src/main/cpp/sox/dft_filter.c new file mode 100644 index 0000000..8a72363 --- /dev/null +++ b/app/src/main/cpp/sox/dft_filter.c @@ -0,0 +1,137 @@ +/* Abstract effect: dft filter Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "fft4g.h" +#include "dft_filter.h" +#include + +typedef dft_filter_t filter_t; +typedef dft_filter_priv_t priv_t; + +void lsx_set_dft_filter(dft_filter_t *f, double *h, int n, int post_peak) +{ + int i; + f->num_taps = n; + f->post_peak = post_peak; + f->dft_length = lsx_set_dft_length(f->num_taps); + f->coefs = lsx_calloc(f->dft_length, sizeof(*f->coefs)); + for (i = 0; i < f->num_taps; ++i) + f->coefs[(i + f->dft_length - f->num_taps + 1) & (f->dft_length - 1)] = h[i] / f->dft_length * 2; + lsx_safe_rdft(f->dft_length, 1, f->coefs); + free(h); +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + + fifo_create(&p->input_fifo, (int)sizeof(double)); + memset(fifo_reserve(&p->input_fifo, + p->filter_ptr->post_peak), 0, sizeof(double) * p->filter_ptr->post_peak); + fifo_create(&p->output_fifo, (int)sizeof(double)); + return SOX_SUCCESS; +} + +static void filter(priv_t * p) +{ + int i, num_in = max(0, fifo_occupancy(&p->input_fifo)); + filter_t const * f = p->filter_ptr; + int const overlap = f->num_taps - 1; + double * output; + + while (num_in >= f->dft_length) { + double const * input = fifo_read_ptr(&p->input_fifo); + fifo_read(&p->input_fifo, f->dft_length - overlap, NULL); + num_in -= f->dft_length - overlap; + + output = fifo_reserve(&p->output_fifo, f->dft_length); + fifo_trim_by(&p->output_fifo, overlap); + memcpy(output, input, f->dft_length * sizeof(*output)); + + lsx_safe_rdft(f->dft_length, 1, output); + output[0] *= f->coefs[0]; + output[1] *= f->coefs[1]; + for (i = 2; i < f->dft_length; i += 2) { + double tmp = output[i]; + output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1]; + output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1]; + } + lsx_safe_rdft(f->dft_length, -1, output); + } +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t odone = min(*osamp, (size_t)fifo_occupancy(&p->output_fifo)); + + double const * s = fifo_read(&p->output_fifo, (int)odone, NULL); + lsx_save_samples(obuf, s, odone, &effp->clips); + p->samples_out += odone; + + if (*isamp && odone < *osamp) { + double * t = fifo_write(&p->input_fifo, (int)*isamp, NULL); + p->samples_in += *isamp; + lsx_load_samples(t, ibuf, *isamp); + filter(p); + } + else *isamp = 0; + *osamp = odone; + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + static size_t isamp = 0; + size_t remaining = p->samples_in > p->samples_out ? + (size_t)(p->samples_in - p->samples_out) : 0; + double * buff = lsx_calloc(1024, sizeof(*buff)); + + if (remaining > 0) { + while ((size_t)fifo_occupancy(&p->output_fifo) < remaining) { + fifo_write(&p->input_fifo, 1024, buff); + p->samples_in += 1024; + filter(p); + } + fifo_trim_to(&p->output_fifo, (int)remaining); + p->samples_in = 0; + } + free(buff); + return flow(effp, 0, obuf, &isamp, osamp); +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + + fifo_delete(&p->input_fifo); + fifo_delete(&p->output_fifo); + free(p->filter_ptr->coefs); + memset(p->filter_ptr, 0, sizeof(*p->filter_ptr)); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_dft_filter_effect_fn(void) +{ + static sox_effect_handler_t handler = { + NULL, NULL, SOX_EFF_GAIN, NULL, start, flow, drain, stop, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/dft_filter.h b/app/src/main/cpp/sox/dft_filter.h new file mode 100644 index 0000000..b8b2599 --- /dev/null +++ b/app/src/main/cpp/sox/dft_filter.h @@ -0,0 +1,16 @@ +#include "fft4g.h" +#define FIFO_SIZE_T int +#include "fifo.h" + +typedef struct { + int dft_length, num_taps, post_peak; + double * coefs; +} dft_filter_t; + +typedef struct { + uint64_t samples_in, samples_out; + fifo_t input_fifo, output_fifo; + dft_filter_t filter, * filter_ptr; +} dft_filter_priv_t; + +void lsx_set_dft_filter(dft_filter_t * f, double * h, int n, int post_peak); diff --git a/app/src/main/cpp/sox/dither.c b/app/src/main/cpp/sox/dither.c new file mode 100644 index 0000000..3351615 --- /dev/null +++ b/app/src/main/cpp/sox/dither.c @@ -0,0 +1,436 @@ +/* Effect: dither/noise-shape Copyright (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef NDEBUG /* Enable assert always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox_i.h" +#include + +#undef RANQD1 +#define RANQD1 ranqd1(p->ranqd1) + +typedef enum { /* Collection of various filters from the net */ + Shape_none, Shape_lipshitz, Shape_f_weighted, Shape_modified_e_weighted, + Shape_improved_e_weighted, Shape_gesemann, Shape_shibata, Shape_low_shibata, Shape_high_shibata +} filter_name_t; +static lsx_enum_item const filter_names[] = { + LSX_ENUM_ITEM(Shape_,none) + LSX_ENUM_ITEM(Shape_,lipshitz) + {"f-weighted", Shape_f_weighted}, + {"modified-e-weighted", Shape_modified_e_weighted}, + {"improved-e-weighted", Shape_improved_e_weighted}, + LSX_ENUM_ITEM(Shape_,gesemann) + LSX_ENUM_ITEM(Shape_,shibata) + {"low-shibata", Shape_low_shibata}, + {"high-shibata", Shape_high_shibata}, + {0, 0}}; + +typedef struct { + sox_rate_t rate; + enum {fir, iir} type; + size_t len; + int gain_cB; /* Chosen so clips are few if any, but not guaranteed none. */ + double const * coefs; + filter_name_t name; +} filter_t; + +static double const lip44[] = {2.033, -2.165, 1.959, -1.590, .6149}; +static double const fwe44[] = { + 2.412, -3.370, 3.937, -4.174, 3.353, -2.205, 1.281, -.569, .0847}; +static double const mew44[] = { + 1.662, -1.263, .4827, -.2913, .1268, -.1124, .03252, -.01265, -.03524}; +static double const iew44[] = { + 2.847, -4.685, 6.214, -7.184, 6.639, -5.032, 3.263, -1.632, .4191}; +static double const ges44[] = { + 2.2061, -.4706, -.2534, -.6214, 1.0587, .0676, -.6054, -.2738}; +static double const ges48[] = { + 2.2374, -.7339, -.1251, -.6033, .903, .0116, -.5853, -.2571}; + +static double const shi48[] = { + 2.8720729351043701172, -5.0413231849670410156, 6.2442994117736816406, + -5.8483986854553222656, 3.7067542076110839844, -1.0495119094848632812, + -1.1830236911773681641, 2.1126792430877685547, -1.9094531536102294922, + 0.99913084506988525391, -0.17090806365013122559, -0.32615602016448974609, + 0.39127644896507263184, -0.26876461505889892578, 0.097676105797290802002, + -0.023473845794796943665, +}; +static double const shi44[] = { + 2.6773197650909423828, -4.8308925628662109375, 6.570110321044921875, + -7.4572014808654785156, 6.7263274192810058594, -4.8481650352478027344, + 2.0412089824676513672, 0.7006359100341796875, -2.9537565708160400391, + 4.0800385475158691406, -4.1845216751098632812, 3.3311812877655029297, + -2.1179926395416259766, 0.879302978515625, -0.031759146600961685181, + -0.42382788658142089844, 0.47882103919982910156, -0.35490813851356506348, + 0.17496839165687561035, -0.060908168554306030273, +}; +static double const shi38[] = { + 1.6335992813110351562, -2.2615492343902587891, 2.4077029228210449219, + -2.6341717243194580078, 2.1440362930297851562, -1.8153258562088012695, + 1.0816224813461303711, -0.70302653312683105469, 0.15991993248462677002, + 0.041549518704414367676, -0.29416576027870178223, 0.2518316805362701416, + -0.27766478061676025391, 0.15785403549671173096, -0.10165894031524658203, + 0.016833892092108726501, +}; +static double const shi32[] = +{ /* dmaker 32000: bestmax=4.99659 (inverted) */ +0.82118552923202515, +-1.0063692331314087, +0.62341964244842529, +-1.0447187423706055, +0.64532512426376343, +-0.87615132331848145, +0.52219754457473755, +-0.67434263229370117, +0.44954317808151245, +-0.52557498216629028, +0.34567299485206604, +-0.39618203043937683, +0.26791760325431824, +-0.28936097025871277, +0.1883765310049057, +-0.19097308814525604, +0.10431359708309174, +-0.10633844882249832, +0.046832218766212463, +-0.039653312414884567, +}; +static double const shi22[] = +{ /* dmaker 22050: bestmax=5.77762 (inverted) */ +0.056581053882837296, +-0.56956905126571655, +-0.40727734565734863, +-0.33870288729667664, +-0.29810553789138794, +-0.19039161503314972, +-0.16510021686553955, +-0.13468159735202789, +-0.096633769571781158, +-0.081049129366874695, +-0.064953058958053589, +-0.054459091275930405, +-0.043378707021474838, +-0.03660014271736145, +-0.026256965473294258, +-0.018786206841468811, +-0.013387725688517094, +-0.0090983230620622635, +-0.0026585909072309732, +-0.00042083300650119781, +}; +static double const shi16[] = +{ /* dmaker 16000: bestmax=5.97128 (inverted) */ +-0.37251132726669312, +-0.81423574686050415, +-0.55010956525802612, +-0.47405767440795898, +-0.32624706625938416, +-0.3161766529083252, +-0.2286367267370224, +-0.22916607558727264, +-0.19565616548061371, +-0.18160104751586914, +-0.15423151850700378, +-0.14104481041431427, +-0.11844276636838913, +-0.097583092749118805, +-0.076493598520755768, +-0.068106919527053833, +-0.041881654411554337, +-0.036922425031661987, +-0.019364040344953537, +-0.014994367957115173, +}; +static double const shi11[] = +{ /* dmaker 11025: bestmax=5.9406 (inverted) */ +-0.9264228343963623, +-0.98695987462997437, +-0.631156325340271, +-0.51966935396194458, +-0.39738872647285461, +-0.35679301619529724, +-0.29720726609230042, +-0.26310476660728455, +-0.21719355881214142, +-0.18561814725399017, +-0.15404847264289856, +-0.12687471508979797, +-0.10339745879173279, +-0.083688631653785706, +-0.05875682458281517, +-0.046893671154975891, +-0.027950936928391457, +-0.020740609616041183, +-0.009366452693939209, +-0.0060260160826146603, +}; +static double const shi08[] = +{ /* dmaker 8000: bestmax=5.56234 (inverted) */ +-1.202863335609436, +-0.94103097915649414, +-0.67878556251525879, +-0.57650017738342285, +-0.50004476308822632, +-0.44349345564842224, +-0.37833768129348755, +-0.34028723835945129, +-0.29413089156150818, +-0.24994957447052002, +-0.21715600788593292, +-0.18792112171649933, +-0.15268312394618988, +-0.12135542929172516, +-0.099610626697540283, +-0.075273610651493073, +-0.048787496984004974, +-0.042586319148540497, +-0.028991291299462318, +-0.011869125068187714, +}; +static double const shl48[] = { + 2.3925774097442626953, -3.4350297451019287109, 3.1853709220886230469, + -1.8117271661758422852, -0.20124770700931549072, 1.4759907722473144531, + -1.7210904359817504883, 0.97746700048446655273, -0.13790138065814971924, + -0.38185903429985046387, 0.27421241998672485352, 0.066584214568138122559, + -0.35223302245140075684, 0.37672343850135803223, -0.23964276909828186035, + 0.068674825131893157959, +}; +static double const shl44[] = { + 2.0833916664123535156, -3.0418450832366943359, 3.2047898769378662109, + -2.7571926116943359375, 1.4978630542755126953, -0.3427594602108001709, + -0.71733748912811279297, 1.0737057924270629883, -1.0225815773010253906, + 0.56649994850158691406, -0.20968692004680633545, -0.065378531813621520996, + 0.10322438180446624756, -0.067442022264003753662, -0.00495197344571352005, +}; +static double const shh44[] = { + 3.0259189605712890625, -6.0268716812133789062, 9.195003509521484375, + -11.824929237365722656, 12.767142295837402344, -11.917946815490722656, + 9.1739168167114257812, -5.3712320327758789062, 1.1393624544143676758, + 2.4484779834747314453, -4.9719839096069335938, 6.0392003059387207031, + -5.9359521865844726562, 4.903278350830078125, -3.5527443885803222656, + 2.1909697055816650391, -1.1672389507293701172, 0.4903914332389831543, + -0.16519790887832641602, 0.023217858746647834778, +}; + +static const filter_t filters[] = { + {44100, fir, 5, 210, lip44, Shape_lipshitz}, + {46000, fir, 9, 276, fwe44, Shape_f_weighted}, + {46000, fir, 9, 160, mew44, Shape_modified_e_weighted}, + {46000, fir, 9, 321, iew44, Shape_improved_e_weighted}, + {48000, iir, 4, 220, ges48, Shape_gesemann}, + {44100, iir, 4, 230, ges44, Shape_gesemann}, + {48000, fir, 16, 301, shi48, Shape_shibata}, + {44100, fir, 20, 333, shi44, Shape_shibata}, + {37800, fir, 16, 240, shi38, Shape_shibata}, + {32000, fir, 20, 240/*TBD*/, shi32, Shape_shibata}, + {22050, fir, 20, 240/*TBD*/, shi22, Shape_shibata}, + {16000, fir, 20, 240/*TBD*/, shi16, Shape_shibata}, + {11025, fir, 20, 240/*TBD*/, shi11, Shape_shibata}, + { 8000, fir, 20, 240/*TBD*/, shi08, Shape_shibata}, + {48000, fir, 16, 250, shl48, Shape_low_shibata}, + {44100, fir, 15, 250, shl44, Shape_low_shibata}, + {44100, fir, 20, 383, shh44, Shape_high_shibata}, + { 0, fir, 0, 0, NULL, Shape_none}, +}; + +#define MAX_N 20 + +typedef struct { + filter_name_t filter_name; + sox_bool auto_detect, alt_tpdf; + double dummy; + + double previous_errors[MAX_N * 2]; + double previous_outputs[MAX_N * 2]; + size_t pos, prec; + uint64_t num_output; + int32_t history, ranqd1, r; + double const * coefs; + sox_bool dither_off; + sox_effect_handler_flow flow; +} priv_t; + +#define CONVOLVE _ _ _ _ +#define NAME flow_iir_4 +#define IIR +#define N 4 +#include "dither.h" +#undef IIR +#define CONVOLVE _ _ _ _ _ +#define NAME flow_fir_5 +#define N 5 +#include "dither.h" +#define CONVOLVE _ _ _ _ _ _ _ _ _ +#define NAME flow_fir_9 +#define N 9 +#include "dither.h" +#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +#define NAME flow_fir_15 +#define N 15 +#include "dither.h" +#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +#define NAME flow_fir_16 +#define N 16 +#include "dither.h" +#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +#define NAME flow_fir_20 +#define N 20 +#include "dither.h" + +static int flow_no_shape(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len = *isamp = *osamp = min(*isamp, *osamp); + + while (len--) { + if (p->auto_detect) { + p->history = (p->history << 1) + + !!(*ibuf & (((unsigned)-1) >> p->prec)); + if (p->history && p->dither_off) { + p->dither_off = sox_false; + lsx_debug("flow %" PRIuPTR ": on @ %" PRIu64, effp->flow, p->num_output); + } else if (!p->history && !p->dither_off) { + p->dither_off = sox_true; + lsx_debug("flow %" PRIuPTR ": off @ %" PRIu64, effp->flow, p->num_output); + } + } + + if (!p->dither_off) { + int32_t r = RANQD1 >> p->prec; + double d = ((double)*ibuf++ + r + (p->alt_tpdf? -p->r : (RANQD1 >> p->prec))) / (1 << (32 - p->prec)); + int i = d < 0? d - .5 : d + .5; + p->r = r; + if (i <= (-1 << (p->prec-1))) + ++effp->clips, *obuf = SOX_SAMPLE_MIN; + else if (i > (int)SOX_INT_MAX(p->prec)) + ++effp->clips, *obuf = SOX_INT_MAX(p->prec) << (32 - p->prec); + else *obuf = i << (32 - p->prec); + ++obuf; + } + else + *obuf++ = *ibuf++; + ++p->num_output; + } + return SOX_SUCCESS; +} + +static int getopts(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + int c; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, "+aSsf:p:", NULL, lsx_getopt_flag_none, 1, &optstate); + + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + case 'a': p->auto_detect = sox_true; break; + case 'S': p->alt_tpdf = sox_true; break; + case 's': p->filter_name = Shape_shibata; break; + case 'f': + p->filter_name = lsx_enum_option(c, optstate.arg, filter_names); + if (p->filter_name == INT_MAX) + return SOX_EOF; + break; + GETOPT_NUMERIC(optstate, 'p', prec, 1, 24) + default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); + } + argc -= optstate.ind, argv += optstate.ind; + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + double mult = 1; /* Amount the noise shaping multiplies up the TPDF (+/-1) */ + + if (p->prec == 0) + p->prec = effp->out_signal.precision; + + if (effp->in_signal.precision <= p->prec || p->prec > 24) + return SOX_EFF_NULL; /* Dithering not needed at this resolution */ + + if (p->prec == 1) { + /* The general dither routines don't work in this case, so notify + user and leave it at that for now. + TODO: Some special-case treatment of 1-bit noise shaping will be + needed for meaningful DSD write support. */ + lsx_warn("Dithering/noise-shaping to 1 bit is currently not supported."); + return SOX_EFF_NULL; + } + + effp->out_signal.precision = p->prec; + + p->flow = flow_no_shape; + if (p->filter_name) { + filter_t const * f; + + for (f = filters; f->len && (f->name != p->filter_name || fabs(effp->in_signal.rate - f->rate) / f->rate > .05); ++f); /* 5% leeway on frequency */ + if (!f->len) { + p->alt_tpdf |= effp->in_signal.rate >= 22050; + if (!effp->flow) + lsx_warn("no `%s' filter is available for rate %g; using %s TPDF", + lsx_find_enum_value(p->filter_name, filter_names)->text, + effp->in_signal.rate, p->alt_tpdf? "sloped" : "plain"); + } + else { + assert(f->len <= MAX_N); + if (f->type == fir) switch(f->len) { + case 5: p->flow = flow_fir_5 ; break; + case 9: p->flow = flow_fir_9 ; break; + case 15: p->flow = flow_fir_15; break; + case 16: p->flow = flow_fir_16; break; + case 20: p->flow = flow_fir_20; break; + default: assert(sox_false); + } else switch(f->len) { + case 4: p->flow = flow_iir_4 ; break; + default: assert(sox_false); + } + p->coefs = f->coefs; + mult = dB_to_linear(f->gain_cB * 0.1); + } + } + p->ranqd1 = ranqd1(sox_globals.ranqd1) + effp->flow; + if (effp->in_signal.mult) /* (Takes account of ostart mult (sox.c). */ + *effp->in_signal.mult *= (SOX_SAMPLE_MAX - (1 << (31 - p->prec)) * + (2 * mult + 1)) / (SOX_SAMPLE_MAX - (1 << (31 - p->prec))); + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + return p->flow(effp, ibuf, obuf, isamp, osamp); +} + +sox_effect_handler_t const * lsx_dither_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "dither", "[-S|-s|-f filter] [-a] [-p precision]" + "\n (none) Use TPDF" + "\n -S Use sloped TPDF (without noise shaping)" + "\n -s Shape noise (with shibata filter)" + "\n -f name Set shaping filter to one of: lipshitz, f-weighted," + "\n modified-e-weighted, improved-e-weighted, gesemann," + "\n shibata, low-shibata, high-shibata." + "\n -a Automatically turn on & off dithering as needed (use with caution!)" + "\n -p bits Override the target sample precision", + SOX_EFF_PREC, getopts, start, flow, 0, 0, 0, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/dither.h b/app/src/main/cpp/sox/dither.h new file mode 100644 index 0000000..c34b6c3 --- /dev/null +++ b/app/src/main/cpp/sox/dither.h @@ -0,0 +1,63 @@ +#ifdef IIR +#define _ output += p->coefs[j] * p->previous_errors[p->pos + j] \ + - p->coefs[N + j] * p->previous_outputs[p->pos + j], ++j; +#else +#define _ d -= p->coefs[j] * p->previous_errors[p->pos + j], ++j; +#endif +static int NAME(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len = *isamp = *osamp = min(*isamp, *osamp); + + while (len--) { + if (p->auto_detect) { + p->history = (p->history << 1) + + !!(*ibuf & (((unsigned)-1) >> p->prec)); + if (p->history && p->dither_off) { + p->dither_off = sox_false; + lsx_debug("flow %" PRIuPTR ": on @ %" PRIu64, effp->flow, p->num_output); + } else if (!p->history && !p->dither_off) { + p->dither_off = sox_true; + memset(p->previous_errors, 0, sizeof(p->previous_errors)); + memset(p->previous_outputs, 0, sizeof(p->previous_outputs)); + lsx_debug("flow %" PRIuPTR ": off @ %" PRIu64, effp->flow, p->num_output); + } + } + + if (!p->dither_off) { + int32_t r1 = RANQD1 >> p->prec, r2 = RANQD1 >> p->prec; /* Defer add! */ +#ifdef IIR + double d1, d, output = 0; +#else + double d1, d = *ibuf++; +#endif + int i, j = 0; + CONVOLVE + assert(j == N); + p->pos = p->pos? p->pos - 1 : p->pos - 1 + N; +#ifdef IIR + d = *ibuf++ - output; + p->previous_outputs[p->pos + N] = p->previous_outputs[p->pos] = output; +#endif + d1 = (d + r1 + r2) / (1 << (32 - p->prec)); + i = d1 < 0? d1 - .5 : d1 + .5; + p->previous_errors[p->pos + N] = p->previous_errors[p->pos] = + (double)i * (1 << (32 - p->prec)) - d; + if (i < (-1 << (p->prec-1))) + ++effp->clips, *obuf = SOX_SAMPLE_MIN; + else if (i > (int)SOX_INT_MAX(p->prec)) + ++effp->clips, *obuf = SOX_INT_MAX(p->prec) << (32 - p->prec); + else *obuf = i << (32 - p->prec); + ++obuf; + } + else + *obuf++ = *ibuf++; + ++p->num_output; + } + return SOX_SUCCESS; +} +#undef CONVOLVE +#undef _ +#undef NAME +#undef N diff --git a/app/src/main/cpp/sox/divide.c b/app/src/main/cpp/sox/divide.c new file mode 100644 index 0000000..f718098 --- /dev/null +++ b/app/src/main/cpp/sox/divide.c @@ -0,0 +1,73 @@ +/* libSoX effect: divide Copyright (c) 2009 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This is W.I.P. hence marked SOX_EFF_ALPHA for now. + * Needs better handling of when the divisor approaches or is zero; some + * sort of interpolation of the output values perhaps. + */ + +#include "sox_i.h" +#include + +typedef struct { + sox_sample_t * last; +} priv_t; + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + p->last = lsx_calloc(effp->in_signal.channels, sizeof(*p->last)); + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i, len = min(*isamp, *osamp) / effp->in_signal.channels; + *osamp = *isamp = len * effp->in_signal.channels; + + while (len--) { + double divisor = *obuf++ = *ibuf++; + if (divisor) { + double out, mult = 1. / SOX_SAMPLE_TO_FLOAT_64BIT(divisor,); + for (i = 1; i < effp->in_signal.channels; ++i) { + out = *ibuf++ * mult; + p->last[i] = *obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips); + } + } + else for (i = 1; i < effp->in_signal.channels; ++i, ++ibuf) + *obuf++ = p->last[i]; + } + return SOX_SUCCESS; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + free(p->last); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_divide_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "divide", NULL, SOX_EFF_MCHAN | SOX_EFF_GAIN | SOX_EFF_ALPHA, + NULL, start, flow, NULL, stop, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/downsample.c b/app/src/main/cpp/sox/downsample.c new file mode 100644 index 0000000..36de6af --- /dev/null +++ b/app/src/main/cpp/sox/downsample.c @@ -0,0 +1,85 @@ +/* libSoX effect: Downsample + * + * First version of this effect written 11/2011 by Ulrich Klauer. + * + * Copyright 2011 Chris Bagwell and SoX Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct { + unsigned int factor; + unsigned int carry; /* number of samples still to be discarded, + carried over from last block */ +} priv_t; + +static int create(sox_effect_t *effp, int argc, char **argv) +{ + priv_t *p = (priv_t*)effp->priv; + p->factor = 2; + --argc, ++argv; + do { /* break-able block */ + NUMERIC_PARAMETER(factor, 1, 16384) + } while (0); + return argc ? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t *effp) +{ + priv_t *p = (priv_t*) effp->priv; + effp->out_signal.rate = effp->in_signal.rate / p->factor; + return p->factor == 1 ? SOX_EFF_NULL : SOX_SUCCESS; +} + +static int flow(sox_effect_t *effp, const sox_sample_t *ibuf, + sox_sample_t *obuf, size_t *isamp, size_t *osamp) +{ + priv_t *p = (priv_t*)effp->priv; + size_t ilen = *isamp, olen = *osamp; + size_t t; + + t = min(p->carry, ilen); + p->carry -= t; + ibuf += t; ilen -= t; + + /* NB: either p->carry (usually) or ilen is now zero; hence, a + non-zero value of ilen implies p->carry == 0, and there is no + need to test for this in the following while and if. */ + + while (ilen >= p->factor && olen) { + *obuf++ = *ibuf; + ibuf += p->factor; + olen--; ilen -= p->factor; + } + + if (ilen && olen) { + *obuf++ = *ibuf; + p->carry = p->factor - ilen; + olen--; ilen = 0; + } + + *isamp -= ilen, *osamp -= olen; + return SOX_SUCCESS; +} + +sox_effect_handler_t const *lsx_downsample_effect_fn(void) +{ + static sox_effect_handler_t handler = {"downsample", "[factor (2)]", + SOX_EFF_RATE | SOX_EFF_MODIFY, + create, start, flow, NULL, NULL, NULL, sizeof(priv_t)}; + return &handler; +} diff --git a/app/src/main/cpp/sox/dvms-fmt.c b/app/src/main/cpp/sox/dvms-fmt.c new file mode 100644 index 0000000..20209f1 --- /dev/null +++ b/app/src/main/cpp/sox/dvms-fmt.c @@ -0,0 +1,32 @@ +/* libSoX file format: DVMS (see cvsd.c) (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "cvsd.h" + +LSX_FORMAT_HANDLER(dvms) +{ + static char const * const names[] = {"dvms", "vms", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_CVSD, 1, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "MIL Std 188 113 Continuously Variable Slope Delta modulation with header", + names, SOX_FILE_MONO, + lsx_dvmsstartread, lsx_cvsdread, lsx_cvsdstopread, + lsx_dvmsstartwrite, lsx_cvsdwrite, lsx_dvmsstopwrite, + NULL, write_encodings, NULL, sizeof(cvsd_priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/earwax.c b/app/src/main/cpp/sox/earwax.c new file mode 100644 index 0000000..0f72418 --- /dev/null +++ b/app/src/main/cpp/sox/earwax.c @@ -0,0 +1,97 @@ +/* libSoX earwax - makes listening to headphones easier November 9, 2000 + * + * Copyright (c) 2000 Edward Beingessner And Sundry Contributors. + * This source code is freely redistributable and may be used for any purpose. + * This copyright notice must be maintained. Edward Beingessner And Sundry + * Contributors are not responsible for the consequences of using this + * software. + * + * This effect takes a 44.1kHz stereo (CD format) signal that is meant to be + * listened to on headphones, and adds audio cues to move the soundstage from + * inside your head (standard for headphones) to outside and in front of the + * listener (standard for speakers). This makes the sound much easier to listen + * to on headphones. + */ + +#include "sox_i.h" +#include + +static const sox_sample_t filt[32 * 2] = { +/* 30° 330° */ + 4, -6, /* 32 tap stereo FIR filter. */ + 4, -11, /* One side filters as if the */ + -1, -5, /* signal was from 30 degrees */ + 3, 3, /* from the ear, the other as */ + -2, 5, /* if 330 degrees. */ + -5, 0, + 9, 1, + 6, 3, /* Input */ + -4, -1, /* Left Right */ + -5, -3, /* __________ __________ */ + -2, -5, /* | | | | */ + -7, 1, /* .---| Hh,0(f) | | Hh,0(f) |---. */ + 6, -7, /* / |__________| |__________| \ */ + 30, -29, /* / \ / \ */ + 12, -3, /* / X \ */ + -11, 4, /* / / \ \ */ + -3, 7, /* ____V_____ __________V V__________ _____V____ */ + -20, 23, /* | | | | | | | | */ + 2, 0, /* | Hh,30(f) | | Hh,330(f)| | Hh,330(f)| | Hh,30(f) | */ + 1, -6, /* |__________| |__________| |__________| |__________| */ + -14, -5, /* \ ___ / \ ___ / */ + 15, -18, /* \ / \ / _____ \ / \ / */ + 6, 7, /* `->| + |<--' / \ `-->| + |<-' */ + 15, -10, /* \___/ _/ \_ \___/ */ + -14, 22, /* \ / \ / \ / */ + -7, -2, /* `--->| | | |<---' */ + -4, 9, /* \_/ \_/ */ + 6, -12, /* */ + 6, -6, /* Headphones */ + 0, -11, + 0, -5, + 4, 0}; + +#define NUMTAPS array_length(filt) +typedef struct {sox_sample_t tap[NUMTAPS];} priv_t; /* FIR filter z^-1 delays */ + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + if (effp->in_signal.rate != 44100 || effp->in_signal.channels != 2) { + lsx_fail("works only with stereo audio sampled at 44100Hz (i.e. CDDA)"); + return SOX_EOF; + } + memset(p->tap, 0, NUMTAPS * sizeof(*p->tap)); /* zero tap memory */ + if (effp->in_signal.mult) + *effp->in_signal.mult *= dB_to_linear(-4.4); + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i, len = *isamp = *osamp = min(*isamp, *osamp); + + while (len--) { /* update taps and calculate output */ + double output = 0; + + for (i = NUMTAPS - 1; i; --i) { + p->tap[i] = p->tap[i - 1]; + output += p->tap[i] * filt[i]; + } + p->tap[0] = *ibuf++ / 64; /* scale output */ + output += p->tap[0] * filt[0]; + *obuf++ = SOX_ROUND_CLIP_COUNT(output, effp->clips); + } + return SOX_SUCCESS; +} + +/* No drain: preserve audio file length; it's only 32 samples anyway. */ + +sox_effect_handler_t const *lsx_earwax_effect_fn(void) +{ + static sox_effect_handler_t handler = {"earwax", NULL, SOX_EFF_MCHAN, + NULL, start, flow, NULL, NULL, NULL, sizeof(priv_t)}; + return &handler; +} diff --git a/app/src/main/cpp/sox/echo.c b/app/src/main/cpp/sox/echo.c new file mode 100644 index 0000000..503ebd5 --- /dev/null +++ b/app/src/main/cpp/sox/echo.c @@ -0,0 +1,266 @@ +/* libSoX Echo effect August 24, 1998 + * + * Copyright (C) 1998 Juergen Mueller And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Juergen Mueller And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * + * Flow diagram scheme for n delays ( 1 <= n <= MAX_ECHOS ): + * + * * gain-in ___ + * ibuff -----------+------------------------------------------>| | + * | _________ | | + * | | | * decay 1 | | + * +----->| delay 1 |------------------------->| | + * | |_________| | | + * | _________ | + | + * | | | * decay 2 | | + * +---------->| delay 2 |-------------------->| | + * | |_________| | | + * : _________ | | + * | | | * decay n | | + * +--------------->| delay n |--------------->|___| + * |_________| | + * | * gain-out + * | + * +----->obuff + * Usage: + * echo gain-in gain-out delay-1 decay-1 [delay-2 decay-2 ... delay-n decay-n] + * + * Where: + * gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume + * gain-out : 0.0 ... volume + * delay-1 ... delay-n : > 0.0 msec + * + * Note: + * when decay is close to 1.0, the samples can begin clipping and the output + * can saturate! + * + * Hint: + * 1 / out-gain > gain-in ( 1 + decay-1 + ... + decay-n ) + */ + +#include "sox_i.h" + +#include /* Harmless, and prototypes atof() etc. --dgc */ + +#define DELAY_BUFSIZ ( 50 * 50U * 1024 ) +#define MAX_ECHOS 7 /* 24 bit x ( 1 + MAX_ECHOS ) = */ + /* 24 bit x 8 = 32 bit !!! */ + +/* Private data for SKEL file */ +typedef struct { + int counter; + int num_delays; + double *delay_buf; + float in_gain, out_gain; + float delay[MAX_ECHOS], decay[MAX_ECHOS]; + ptrdiff_t samples[MAX_ECHOS], maxsamples; + size_t fade_out; +} priv_t; + +/* Private data for SKEL file */ + + +/* + * Process options + */ +static int sox_echo_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * echo = (priv_t *) effp->priv; + int i; + + --argc, ++argv; + echo->num_delays = 0; + + if ((argc < 4) || (argc % 2)) + return lsx_usage(effp); + + i = 0; + sscanf(argv[i++], "%f", &echo->in_gain); + sscanf(argv[i++], "%f", &echo->out_gain); + while (i < argc) { + if ( echo->num_delays >= MAX_ECHOS ) + lsx_fail("echo: to many delays, use less than %i delays", + MAX_ECHOS); + /* Linux bug and it's cleaner. */ + sscanf(argv[i++], "%f", &echo->delay[echo->num_delays]); + sscanf(argv[i++], "%f", &echo->decay[echo->num_delays]); + echo->num_delays++; + } + return (SOX_SUCCESS); +} + +/* + * Prepare for processing. + */ +static int sox_echo_start(sox_effect_t * effp) +{ + priv_t * echo = (priv_t *) effp->priv; + int i; + float sum_in_volume; + long j; + + echo->maxsamples = 0; + if ( echo->in_gain < 0.0 ) + { + lsx_fail("echo: gain-in must be positive!"); + return (SOX_EOF); + } + if ( echo->in_gain > 1.0 ) + { + lsx_fail("echo: gain-in must be less than 1.0!"); + return (SOX_EOF); + } + if ( echo->out_gain < 0.0 ) + { + lsx_fail("echo: gain-in must be positive!"); + return (SOX_EOF); + } + for ( i = 0; i < echo->num_delays; i++ ) { + echo->samples[i] = echo->delay[i] * effp->in_signal.rate / 1000.0; + if ( echo->samples[i] < 1 ) + { + lsx_fail("echo: delay must be positive!"); + return (SOX_EOF); + } + if ( echo->samples[i] > (ptrdiff_t)DELAY_BUFSIZ ) + { + lsx_fail("echo: delay must be less than %g seconds!", + DELAY_BUFSIZ / effp->in_signal.rate ); + return (SOX_EOF); + } + if ( echo->decay[i] < 0.0 ) + { + lsx_fail("echo: decay must be positive!" ); + return (SOX_EOF); + } + if ( echo->decay[i] > 1.0 ) + { + lsx_fail("echo: decay must be less than 1.0!" ); + return (SOX_EOF); + } + if ( echo->samples[i] > echo->maxsamples ) + echo->maxsamples = echo->samples[i]; + } + echo->delay_buf = lsx_malloc(sizeof (double) * echo->maxsamples); + for ( j = 0; j < echo->maxsamples; ++j ) + echo->delay_buf[j] = 0.0; + /* Be nice and check the hint with warning, if... */ + sum_in_volume = 1.0; + for ( i = 0; i < echo->num_delays; i++ ) + sum_in_volume += echo->decay[i]; + if ( sum_in_volume * echo->in_gain > 1.0 / echo->out_gain ) + lsx_warn("echo: warning >>> gain-out can cause saturation of output <<<"); + echo->counter = 0; + echo->fade_out = echo->maxsamples; + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ + + return (SOX_SUCCESS); +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +static int sox_echo_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * echo = (priv_t *) effp->priv; + int j; + double d_in, d_out; + sox_sample_t out; + size_t len = min(*isamp, *osamp); + *isamp = *osamp = len; + + while (len--) { + /* Store delays as 24-bit signed longs */ + d_in = (double) *ibuf++ / 256; + /* Compute output first */ + d_out = d_in * echo->in_gain; + for ( j = 0; j < echo->num_delays; j++ ) { + d_out += echo->delay_buf[ +(echo->counter + echo->maxsamples - echo->samples[j]) % echo->maxsamples] + * echo->decay[j]; + } + /* Adjust the output volume and size to 24 bit */ + d_out = d_out * echo->out_gain; + out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); + *obuf++ = out * 256; + /* Store input in delay buffer */ + echo->delay_buf[echo->counter] = d_in; + /* Adjust the counter */ + echo->counter = ( echo->counter + 1 ) % echo->maxsamples; + } + /* processed all samples */ + return (SOX_SUCCESS); +} + +/* + * Drain out reverb lines. + */ +static int sox_echo_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * echo = (priv_t *) effp->priv; + double d_in, d_out; + sox_sample_t out; + int j; + size_t done; + + done = 0; + /* drain out delay samples */ + while ( ( done < *osamp ) && ( done < echo->fade_out ) ) { + d_in = 0; + d_out = 0; + for ( j = 0; j < echo->num_delays; j++ ) { + d_out += echo->delay_buf[ +(echo->counter + echo->maxsamples - echo->samples[j]) % echo->maxsamples] + * echo->decay[j]; + } + /* Adjust the output volume and size to 24 bit */ + d_out = d_out * echo->out_gain; + out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); + *obuf++ = out * 256; + /* Store input in delay buffer */ + echo->delay_buf[echo->counter] = d_in; + /* Adjust the counters */ + echo->counter = ( echo->counter + 1 ) % echo->maxsamples; + done++; + echo->fade_out--; + }; + /* samples played, it remains */ + *osamp = done; + if (echo->fade_out == 0) + return SOX_EOF; + else + return SOX_SUCCESS; +} + +static int sox_echo_stop(sox_effect_t * effp) +{ + priv_t * echo = (priv_t *) effp->priv; + + free(echo->delay_buf); + echo->delay_buf = NULL; + return (SOX_SUCCESS); +} + +static sox_effect_handler_t sox_echo_effect = { + "echo", + "gain-in gain-out delay decay [ delay decay ... ]", + SOX_EFF_LENGTH | SOX_EFF_GAIN, + sox_echo_getopts, + sox_echo_start, + sox_echo_flow, + sox_echo_drain, + sox_echo_stop, + NULL, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_echo_effect_fn(void) +{ + return &sox_echo_effect; +} diff --git a/app/src/main/cpp/sox/echos.c b/app/src/main/cpp/sox/echos.c new file mode 100644 index 0000000..4202cd7 --- /dev/null +++ b/app/src/main/cpp/sox/echos.c @@ -0,0 +1,278 @@ +/* libSoX Echo effect August 24, 1998 + * + * Copyright (C) 1998 Juergen Mueller And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Juergen Mueller And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * + * Flow diagram scheme for n delays ( 1 <= n <= MAX_ECHOS ): + * + * * gain-in ___ + * ibuff --+--------------------------------------------------->| | + * | * decay 1 | | + * | +----------------------------------->| | + * | | * decay 2 | + | + * | | +--------------------->| | + * | | | * decay n | | + * | _________ | _________ | _________ +--->|___| + * | | | | | | | | | | | + * +-->| delay 1 |-+-| delay 2 |-+...-| delay n |--+ | * gain-out + * |_________| |_________| |_________| | + * +----->obuff + * Usage: + * echos gain-in gain-out delay-1 decay-1 [delay-2 decay-2 ... delay-n decay-n] + * + * Where: + * gain-in, decay-1 ... decay-n : 0.0 ... 1.0 volume + * gain-out : 0.0 ... volume + * delay-1 ... delay-n : > 0.0 msec + * + * Note: + * when decay is close to 1.0, the samples can begin clipping and the output + * can saturate! + * + * Hint: + * 1 / out-gain > gain-in ( 1 + decay-1 + ... + decay-n ) + * + */ + +#include "sox_i.h" + +#include /* Harmless, and prototypes atof() etc. --dgc */ + +#define DELAY_BUFSIZ ( 50 * 50U * 1024 ) +#define MAX_ECHOS 7 /* 24 bit x ( 1 + MAX_ECHOS ) = */ + /* 24 bit x 8 = 32 bit !!! */ + +/* Private data for SKEL file */ +typedef struct { + int counter[MAX_ECHOS]; + int num_delays; + double *delay_buf; + float in_gain, out_gain; + float delay[MAX_ECHOS], decay[MAX_ECHOS]; + ptrdiff_t samples[MAX_ECHOS], pointer[MAX_ECHOS]; + size_t sumsamples; +} priv_t; + +/* Private data for SKEL file */ + +/* + * Process options + */ +static int sox_echos_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * echos = (priv_t *) effp->priv; + int i; + + echos->num_delays = 0; + + --argc, ++argv; + if ((argc < 4) || (argc % 2)) + return lsx_usage(effp); + + i = 0; + sscanf(argv[i++], "%f", &echos->in_gain); + sscanf(argv[i++], "%f", &echos->out_gain); + while (i < argc) { + /* Linux bug and it's cleaner. */ + sscanf(argv[i++], "%f", &echos->delay[echos->num_delays]); + sscanf(argv[i++], "%f", &echos->decay[echos->num_delays]); + echos->num_delays++; + if ( echos->num_delays > MAX_ECHOS ) + { + lsx_fail("echos: to many delays, use less than %i delays", + MAX_ECHOS); + return (SOX_EOF); + } + } + echos->sumsamples = 0; + return (SOX_SUCCESS); +} + +/* + * Prepare for processing. + */ +static int sox_echos_start(sox_effect_t * effp) +{ + priv_t * echos = (priv_t *) effp->priv; + int i; + float sum_in_volume; + unsigned long j; + + if ( echos->in_gain < 0.0 ) + { + lsx_fail("echos: gain-in must be positive!"); + return (SOX_EOF); + } + if ( echos->in_gain > 1.0 ) + { + lsx_fail("echos: gain-in must be less than 1.0!"); + return (SOX_EOF); + } + if ( echos->out_gain < 0.0 ) + { + lsx_fail("echos: gain-in must be positive!"); + return (SOX_EOF); + } + for ( i = 0; i < echos->num_delays; i++ ) { + echos->samples[i] = echos->delay[i] * effp->in_signal.rate / 1000.0; + if ( echos->samples[i] < 1 ) + { + lsx_fail("echos: delay must be positive!"); + return (SOX_EOF); + } + if ( echos->samples[i] > (ptrdiff_t)DELAY_BUFSIZ ) + { + lsx_fail("echos: delay must be less than %g seconds!", + DELAY_BUFSIZ / effp->in_signal.rate ); + return (SOX_EOF); + } + if ( echos->decay[i] < 0.0 ) + { + lsx_fail("echos: decay must be positive!" ); + return (SOX_EOF); + } + if ( echos->decay[i] > 1.0 ) + { + lsx_fail("echos: decay must be less than 1.0!" ); + return (SOX_EOF); + } + echos->counter[i] = 0; + echos->pointer[i] = echos->sumsamples; + echos->sumsamples += echos->samples[i]; + } + echos->delay_buf = lsx_malloc(sizeof (double) * echos->sumsamples); + for ( j = 0; j < echos->sumsamples; ++j ) + echos->delay_buf[j] = 0.0; + /* Be nice and check the hint with warning, if... */ + sum_in_volume = 1.0; + for ( i = 0; i < echos->num_delays; i++ ) + sum_in_volume += echos->decay[i]; + if ( sum_in_volume * echos->in_gain > 1.0 / echos->out_gain ) + lsx_warn("echos: warning >>> gain-out can cause saturation of output <<<"); + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ + + return (SOX_SUCCESS); +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +static int sox_echos_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * echos = (priv_t *) effp->priv; + int j; + double d_in, d_out; + sox_sample_t out; + size_t len = min(*isamp, *osamp); + *isamp = *osamp = len; + + while (len--) { + /* Store delays as 24-bit signed longs */ + d_in = (double) *ibuf++ / 256; + /* Compute output first */ + d_out = d_in * echos->in_gain; + for ( j = 0; j < echos->num_delays; j++ ) { + d_out += echos->delay_buf[echos->counter[j] + echos->pointer[j]] * echos->decay[j]; + } + /* Adjust the output volume and size to 24 bit */ + d_out = d_out * echos->out_gain; + out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); + *obuf++ = out * 256; + /* Mix decay of delays and input */ + for ( j = 0; j < echos->num_delays; j++ ) { + if ( j == 0 ) + echos->delay_buf[echos->counter[j] + echos->pointer[j]] = d_in; + else + echos->delay_buf[echos->counter[j] + echos->pointer[j]] = + echos->delay_buf[echos->counter[j-1] + echos->pointer[j-1]] + d_in; + } + /* Adjust the counters */ + for ( j = 0; j < echos->num_delays; j++ ) + echos->counter[j] = + ( echos->counter[j] + 1 ) % echos->samples[j]; + } + /* processed all samples */ + return (SOX_SUCCESS); +} + +/* + * Drain out reverb lines. + */ +static int sox_echos_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * echos = (priv_t *) effp->priv; + double d_in, d_out; + sox_sample_t out; + int j; + size_t done; + + done = 0; + /* drain out delay samples */ + while ( ( done < *osamp ) && ( done < echos->sumsamples ) ) { + d_in = 0; + d_out = 0; + for ( j = 0; j < echos->num_delays; j++ ) { + d_out += echos->delay_buf[echos->counter[j] + echos->pointer[j]] * echos->decay[j]; + } + /* Adjust the output volume and size to 24 bit */ + d_out = d_out * echos->out_gain; + out = SOX_24BIT_CLIP_COUNT((sox_sample_t) d_out, effp->clips); + *obuf++ = out * 256; + /* Mix decay of delays and input */ + for ( j = 0; j < echos->num_delays; j++ ) { + if ( j == 0 ) + echos->delay_buf[echos->counter[j] + echos->pointer[j]] = d_in; + else + echos->delay_buf[echos->counter[j] + echos->pointer[j]] = + echos->delay_buf[echos->counter[j-1] + echos->pointer[j-1]]; + } + /* Adjust the counters */ + for ( j = 0; j < echos->num_delays; j++ ) + echos->counter[j] = + ( echos->counter[j] + 1 ) % echos->samples[j]; + done++; + echos->sumsamples--; + }; + /* samples played, it remains */ + *osamp = done; + if (echos->sumsamples == 0) + return SOX_EOF; + else + return SOX_SUCCESS; +} + +/* + * Clean up echos effect. + */ +static int sox_echos_stop(sox_effect_t * effp) +{ + priv_t * echos = (priv_t *) effp->priv; + + free(echos->delay_buf); + echos->delay_buf = NULL; + return (SOX_SUCCESS); +} + +static sox_effect_handler_t sox_echos_effect = { + "echos", + "gain-in gain-out delay decay [ delay decay ... ]", + SOX_EFF_LENGTH | SOX_EFF_GAIN, + sox_echos_getopts, + sox_echos_start, + sox_echos_flow, + sox_echos_drain, + sox_echos_stop, + NULL, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_echos_effect_fn(void) +{ + return &sox_echos_effect; +} diff --git a/app/src/main/cpp/sox/effects.c b/app/src/main/cpp/sox/effects.c new file mode 100644 index 0000000..99bc862 --- /dev/null +++ b/app/src/main/cpp/sox/effects.c @@ -0,0 +1,669 @@ +/* SoX Effects chain (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define LSX_EFF_ALIAS +#include "sox_i.h" +#include +#include +#ifdef HAVE_STRINGS_H + #include +#endif + +#define DEBUG_EFFECTS_CHAIN 0 + +/* Default effect handler functions for do-nothing situations: */ + +static int default_function(sox_effect_t * effp UNUSED) +{ + return SOX_SUCCESS; +} + +/* Pass through samples verbatim */ +int lsx_flow_copy(sox_effect_t * effp UNUSED, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + *isamp = *osamp = min(*isamp, *osamp); + memcpy(obuf, ibuf, *isamp * sizeof(*obuf)); + return SOX_SUCCESS; +} + +/* Inform no more samples to drain */ +static int default_drain(sox_effect_t * effp UNUSED, sox_sample_t *obuf UNUSED, size_t *osamp) +{ + *osamp = 0; + return SOX_EOF; +} + +/* Check that no parameters have been given */ +static int default_getopts(sox_effect_t * effp, int argc, char **argv UNUSED) +{ + return --argc? lsx_usage(effp) : SOX_SUCCESS; +} + +/* Partially initialise the effect structure; signal info will come later */ +sox_effect_t * sox_create_effect(sox_effect_handler_t const * eh) +{ + sox_effect_t * effp = lsx_calloc(1, sizeof(*effp)); + effp->obuf = NULL; + + effp->global_info = sox_get_effects_globals(); + effp->handler = *eh; + if (!effp->handler.getopts) effp->handler.getopts = default_getopts; + if (!effp->handler.start ) effp->handler.start = default_function; + if (!effp->handler.flow ) effp->handler.flow = lsx_flow_copy; + if (!effp->handler.drain ) effp->handler.drain = default_drain; + if (!effp->handler.stop ) effp->handler.stop = default_function; + if (!effp->handler.kill ) effp->handler.kill = default_function; + + effp->priv = lsx_calloc(1, effp->handler.priv_size); + + return effp; +} /* sox_create_effect */ + +int sox_effect_options(sox_effect_t *effp, int argc, char * const argv[]) +{ + int result; + + char * * argv2 = lsx_malloc((argc + 1) * sizeof(*argv2)); + argv2[0] = (char *)effp->handler.name; + memcpy(argv2 + 1, argv, argc * sizeof(*argv2)); + result = effp->handler.getopts(effp, argc + 1, argv2); + free(argv2); + return result; +} /* sox_effect_options */ + +/* Effects chain: */ + +sox_effects_chain_t * sox_create_effects_chain( + sox_encodinginfo_t const * in_enc, sox_encodinginfo_t const * out_enc) +{ + sox_effects_chain_t * result = lsx_calloc(1, sizeof(sox_effects_chain_t)); + result->global_info = *sox_get_effects_globals(); + result->in_enc = in_enc; + result->out_enc = out_enc; + return result; +} /* sox_create_effects_chain */ + +void sox_delete_effects_chain(sox_effects_chain_t *ecp) +{ + if (ecp && ecp->length) + sox_delete_effects(ecp); + free(ecp->effects); + free(ecp); +} /* sox_delete_effects_chain */ + +/* Effect can call in start() or flow() to set minimum input size to flow() */ +int lsx_effect_set_imin(sox_effect_t * effp, size_t imin) +{ + if (imin > sox_globals.bufsiz / effp->flows) { + lsx_fail("sox_bufsiz not big enough"); + return SOX_EOF; + } + + effp->imin = imin; + return SOX_SUCCESS; +} + +/* Effects table to be extended in steps of EFF_TABLE_STEP */ +#define EFF_TABLE_STEP 8 + +/* Add an effect to the chain. *in is the input signal for this effect. *out is + * a suggestion as to what the output signal should be, but depending on its + * given options and *in, the effect can choose to do differently. Whatever + * output rate and channels the effect does produce are written back to *in, + * ready for the next effect in the chain. + */ +int sox_add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, sox_signalinfo_t * in, sox_signalinfo_t const * out) +{ + int ret, (*start)(sox_effect_t * effp) = effp->handler.start; + size_t f; + sox_effect_t eff0; /* Copy of effect for flow 0 before calling start */ + + effp->global_info = &chain->global_info; + effp->in_signal = *in; + effp->out_signal = *out; + effp->in_encoding = chain->in_enc; + effp->out_encoding = chain->out_enc; + if (!(effp->handler.flags & SOX_EFF_CHAN)) + effp->out_signal.channels = in->channels; + if (!(effp->handler.flags & SOX_EFF_RATE)) + effp->out_signal.rate = in->rate; + if (!(effp->handler.flags & SOX_EFF_PREC)) + effp->out_signal.precision = (effp->handler.flags & SOX_EFF_MODIFY)? + in->precision : SOX_SAMPLE_PRECISION; + if (!(effp->handler.flags & SOX_EFF_GAIN)) + effp->out_signal.mult = in->mult; + + effp->flows = + (effp->handler.flags & SOX_EFF_MCHAN)? 1 : effp->in_signal.channels; + effp->clips = 0; + effp->imin = 0; + eff0 = *effp, eff0.priv = lsx_memdup(eff0.priv, eff0.handler.priv_size); + eff0.in_signal.mult = NULL; /* Only used in channel 0 */ + ret = start(effp); + if (ret == SOX_EFF_NULL) { + lsx_report("has no effect in this configuration"); + free(eff0.priv); + effp->handler.kill(effp); + free(effp->priv); + effp->priv = NULL; + return SOX_SUCCESS; + } + if (ret != SOX_SUCCESS) { + free(eff0.priv); + return SOX_EOF; + } + if (in->mult) + lsx_debug("mult=%g", *in->mult); + + if (!(effp->handler.flags & SOX_EFF_LENGTH)) { + effp->out_signal.length = in->length; + if (effp->out_signal.length != SOX_UNKNOWN_LEN) { + if (effp->handler.flags & SOX_EFF_CHAN) + effp->out_signal.length = + effp->out_signal.length / in->channels * effp->out_signal.channels; + if (effp->handler.flags & SOX_EFF_RATE) + effp->out_signal.length = + effp->out_signal.length / in->rate * effp->out_signal.rate + .5; + } + } + + *in = effp->out_signal; + + if (chain->length == chain->table_size) { + chain->table_size += EFF_TABLE_STEP; + lsx_debug_more("sox_add_effect: extending effects table, " + "new size = %" PRIuPTR, chain->table_size); + lsx_revalloc(chain->effects, chain->table_size); + } + + chain->effects[chain->length] = + lsx_calloc(effp->flows, sizeof(chain->effects[chain->length][0])); + chain->effects[chain->length][0] = *effp; + + for (f = 1; f < effp->flows; ++f) { + chain->effects[chain->length][f] = eff0; + chain->effects[chain->length][f].flow = f; + chain->effects[chain->length][f].priv = lsx_memdup(eff0.priv, eff0.handler.priv_size); + if (start(&chain->effects[chain->length][f]) != SOX_SUCCESS) { + free(eff0.priv); + return SOX_EOF; + } + } + + ++chain->length; + free(eff0.priv); + return SOX_SUCCESS; +} + +/* An effect's output buffer (effp->obuf) generally has this layout: + * |. . . A1A2A3B1B2B3C1C2C3. . . . . . . . . . . . . . . . . . | + * ^0 ^obeg ^oend ^bufsiz + * (where A1 is the first sample of channel 1, A2 the first sample of + * channel 2, etc.), i.e. the channels are interleaved. + * However, while sox_flow_effects() is running, output buffers are + * adapted to how the following effect expects its input, to avoid + * back-and-forth conversions. If the following effect operates on + * each of several channels separately (flows > 1), the layout is + * changed to this uninterleaved form: + * |. A1B1C1. . . . . . . A2B2C2. . . . . . . A3B3C3. . . . . . | + * ^0 ^obeg ^oend ^bufsiz + * <--- channel 1 ----><--- channel 2 ----><--- channel 3 ----> + * The buffer is logically subdivided into channel buffers of size + * bufsiz/flows each, starting at offsets 0, bufsiz/flows, + * 2*(bufsiz/flows) etc. Within the channel buffers, the data starts + * at position obeg/flows and ends before oend/flows. In case bufsiz + * is not evenly divisible by flows, there will be an unused area at + * the very end of the output buffer. + * The interleave() and deinterleave() functions convert between these + * two representations. + */ +static void interleave(size_t flows, size_t length, sox_sample_t *from, + size_t bufsiz, size_t offset, sox_sample_t *to); +static void deinterleave(size_t flows, size_t length, sox_sample_t *from, + sox_sample_t *to, size_t bufsiz, size_t offset); + +static int flow_effect(sox_effects_chain_t * chain, size_t n) +{ + sox_effect_t *effp1 = chain->effects[n - 1]; + sox_effect_t *effp = chain->effects[n]; + int effstatus = SOX_SUCCESS; + size_t f = 0; + size_t idone = effp1->oend - effp1->obeg; + size_t obeg = sox_globals.bufsiz - effp->oend; + sox_bool il_change = (effp->flows == 1) != + (chain->length == n + 1 || chain->effects[n+1]->flows == 1); +#if DEBUG_EFFECTS_CHAIN + size_t pre_idone = idone; + size_t pre_odone = obeg; +#endif + + if (effp->flows == 1) { /* Run effect on all channels at once */ + idone -= idone % effp->in_signal.channels; + effstatus = effp->handler.flow(effp, effp1->obuf + effp1->obeg, + il_change ? chain->il_buf : effp->obuf + effp->oend, + &idone, &obeg); + if (obeg % effp->out_signal.channels != 0) { + lsx_fail("multi-channel effect flowed asymmetrically!"); + effstatus = SOX_EOF; + } + if (il_change) + deinterleave(chain->effects[n+1]->flows, obeg, chain->il_buf, + effp->obuf, sox_globals.bufsiz, effp->oend); + } else { /* Run effect on each channel individually */ + sox_sample_t *obuf = il_change ? chain->il_buf : effp->obuf; + size_t flow_offs = sox_globals.bufsiz/effp->flows; + size_t idone_min = SOX_SIZE_MAX, idone_max = 0; + size_t odone_min = SOX_SIZE_MAX, odone_max = 0; + +#ifdef HAVE_OPENMP_3_1 + #pragma omp parallel for \ + if(sox_globals.use_threads) \ + schedule(static) default(none) \ + shared(effp,effp1,idone,obeg,obuf,flow_offs,chain,n,effstatus) \ + reduction(min:idone_min,odone_min) reduction(max:idone_max,odone_max) +#elif defined HAVE_OPENMP + #pragma omp parallel for \ + if(sox_globals.use_threads) \ + schedule(static) default(none) \ + shared(effp,effp1,idone,obeg,obuf,flow_offs,chain,n,effstatus) \ + firstprivate(idone_min,odone_min,idone_max,odone_max) \ + lastprivate(idone_min,odone_min,idone_max,odone_max) +#endif + for (f = 0; f < effp->flows; ++f) { + size_t idonec = idone / effp->flows; + size_t odonec = obeg / effp->flows; + int eff_status_c = effp->handler.flow(&chain->effects[n][f], + effp1->obuf + f*flow_offs + effp1->obeg/effp->flows, + obuf + f*flow_offs + effp->oend/effp->flows, + &idonec, &odonec); + idone_min = min(idonec, idone_min); idone_max = max(idonec, idone_max); + odone_min = min(odonec, odone_min); odone_max = max(odonec, odone_max); + + if (eff_status_c != SOX_SUCCESS) + effstatus = SOX_EOF; + } + + if (idone_min != idone_max || odone_min != odone_max) { + lsx_fail("flowed asymmetrically!"); + effstatus = SOX_EOF; + } + idone = effp->flows * idone_max; + obeg = effp->flows * odone_max; + + if (il_change) + interleave(effp->flows, obeg, chain->il_buf, sox_globals.bufsiz, + effp->oend, effp->obuf + effp->oend); + } + effp1->obeg += idone; + if (effp1->obeg == effp1->oend) + effp1->obeg = effp1->oend = 0; + else if (effp1->oend - effp1->obeg < effp->imin) { /* Need to refill? */ + size_t flow_offs = sox_globals.bufsiz/effp->flows; + for (f = 0; f < effp->flows; ++f) + memcpy(effp1->obuf + f * flow_offs, + effp1->obuf + f * flow_offs + effp1->obeg/effp->flows, + (effp1->oend - effp1->obeg)/effp->flows * sizeof(*effp1->obuf)); + effp1->oend -= effp1->obeg; + effp1->obeg = 0; + } + + effp->oend += obeg; + +#if DEBUG_EFFECTS_CHAIN + lsx_report("\t" "flow: %2" PRIuPTR " (%1" PRIuPTR ") " + "%5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " " + "%5" PRIuPTR " [%" PRIuPTR "-%" PRIuPTR "]", + n, effp->flows, pre_idone, pre_odone, idone, obeg, + effp1->oend - effp1->obeg, effp1->obeg, effp1->oend); +#endif + + return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF; +} + +/* The same as flow_effect but with no input */ +static int drain_effect(sox_effects_chain_t * chain, size_t n) +{ + sox_effect_t *effp = chain->effects[n]; + int effstatus = SOX_SUCCESS; + size_t f = 0; + size_t obeg = sox_globals.bufsiz - effp->oend; + sox_bool il_change = (effp->flows == 1) != + (chain->length == n + 1 || chain->effects[n+1]->flows == 1); +#if DEBUG_EFFECTS_CHAIN + size_t pre_odone = obeg; +#endif + + if (effp->flows == 1) { /* Run effect on all channels at once */ + effstatus = effp->handler.drain(effp, + il_change ? chain->il_buf : effp->obuf + effp->oend, + &obeg); + if (obeg % effp->out_signal.channels != 0) { + lsx_fail("multi-channel effect drained asymmetrically!"); + effstatus = SOX_EOF; + } + if (il_change) + deinterleave(chain->effects[n+1]->flows, obeg, chain->il_buf, + effp->obuf, sox_globals.bufsiz, effp->oend); + } else { /* Run effect on each channel individually */ + sox_sample_t *obuf = il_change ? chain->il_buf : effp->obuf; + size_t flow_offs = sox_globals.bufsiz/effp->flows; + size_t odone_last = 0; /* Initialised to prevent warning */ + + for (f = 0; f < effp->flows; ++f) { + size_t odonec = obeg / effp->flows; + int eff_status_c = effp->handler.drain(&chain->effects[n][f], + obuf + f*flow_offs + effp->oend/effp->flows, + &odonec); + if (f && (odonec != odone_last)) { + lsx_fail("drained asymmetrically!"); + effstatus = SOX_EOF; + } + odone_last = odonec; + + if (eff_status_c != SOX_SUCCESS) + effstatus = SOX_EOF; + } + + obeg = effp->flows * odone_last; + + if (il_change) + interleave(effp->flows, obeg, chain->il_buf, sox_globals.bufsiz, + effp->oend, effp->obuf + effp->oend); + } + if (!obeg) /* This is the only thing that drain has and flow hasn't */ + effstatus = SOX_EOF; + + effp->oend += obeg; + +#if DEBUG_EFFECTS_CHAIN + lsx_report("\t" "drain: %2" PRIuPTR " (%1" PRIuPTR ") " + "%5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR " %5" PRIuPTR, + n, effp->flows, (size_t)0, pre_odone, (size_t)0, obeg); +#endif + + return effstatus == SOX_SUCCESS? SOX_SUCCESS : SOX_EOF; +} + +/* Flow data through the effects chain until an effect or callback gives EOF */ +int sox_flow_effects(sox_effects_chain_t * chain, int (* callback)(sox_bool all_done, void * client_data), void * client_data) +{ + int flow_status = SOX_SUCCESS; + size_t e, source_e = 0; /* effect indices */ + size_t max_flows = 0; + sox_bool draining = sox_true; + + for (e = 0; e < chain->length; ++e) { + sox_effect_t *effp = chain->effects[e]; + effp->obuf = + lsx_realloc(effp->obuf, sox_globals.bufsiz * sizeof(*effp->obuf)); + /* Memory will be freed by sox_delete_effect() later. */ + /* Possibly there was already a buffer, if this is a used effect; + it may still contain samples in that case. */ + if (effp->oend > sox_globals.bufsiz) { + lsx_warn("buffer size insufficient; buffered samples were dropped"); + /* can only happen if bufsize has been reduced since the last run */ + effp->obeg = effp->oend = 0; + } + max_flows = max(max_flows, effp->flows); + } + if (max_flows > 1) /* might need interleave buffer */ + chain->il_buf = lsx_malloc(sox_globals.bufsiz * sizeof(sox_sample_t)); + else + chain->il_buf = NULL; + + /* Go through the effects, and if there are samples in one of the + buffers, deinterleave it (if necessary). */ + for (e = 0; e + 1 < chain->length; e++) { + sox_effect_t *effp = chain->effects[e]; + if (effp->oend > effp->obeg && chain->effects[e+1]->flows > 1) { + sox_sample_t *sw = chain->il_buf; chain->il_buf = effp->obuf; effp->obuf = sw; + deinterleave(chain->effects[e+1]->flows, effp->oend - effp->obeg, + chain->il_buf, effp->obuf, sox_globals.bufsiz, effp->obeg); + } + } + + e = chain->length - 1; + while (source_e < chain->length) { +#define have_imin (e > 0 && e < chain->length && chain->effects[e - 1]->oend - chain->effects[e - 1]->obeg >= chain->effects[e]->imin) + size_t osize = chain->effects[e]->oend - chain->effects[e]->obeg; + if (e == source_e && (draining || !have_imin)) { + if (drain_effect(chain, e) == SOX_EOF) { + ++source_e; + draining = sox_false; + } + } else if (have_imin && flow_effect(chain, e) == SOX_EOF) { + flow_status = SOX_EOF; + if (e == chain->length - 1) + break; + source_e = e; + draining = sox_true; + } + if (e < chain->length && chain->effects[e]->oend - chain->effects[e]->obeg > osize) /* False for output */ + ++e; + else if (e == source_e) + draining = sox_true; + else if (e < source_e) + e = source_e; + else + --e; + + if (callback && callback(source_e == chain->length, client_data) != SOX_SUCCESS) { + flow_status = SOX_EOF; /* Client has requested to stop the flow. */ + break; + } + } + + /* If an effect's output buffer still has samples, and if it is + uninterleaved, then re-interleave it. Necessary since it might + be reused, and at that time possibly followed by an MCHAN effect. */ + for (e = 0; e + 1 < chain->length; e++) { + sox_effect_t *effp = chain->effects[e]; + if (effp->oend > effp->obeg && chain->effects[e+1]->flows > 1) { + sox_sample_t *sw = chain->il_buf; chain->il_buf = effp->obuf; effp->obuf = sw; + interleave(chain->effects[e+1]->flows, effp->oend - effp->obeg, + chain->il_buf, sox_globals.bufsiz, effp->obeg, effp->obuf); + } + } + + free(chain->il_buf); + return flow_status; +} + +sox_uint64_t sox_effects_clips(sox_effects_chain_t * chain) +{ + size_t i, f; + uint64_t clips = 0; + for (i = 1; i < chain->length - 1; ++i) + for (f = 0; f < chain->effects[i][0].flows; ++f) + clips += chain->effects[i][f].clips; + return clips; +} + +sox_uint64_t sox_stop_effect(sox_effect_t *effp) +{ + size_t f; + uint64_t clips = 0; + + for (f = 0; f < effp->flows; ++f) { + effp[f].handler.stop(&effp[f]); + clips += effp[f].clips; + } + return clips; +} + +void sox_push_effect_last(sox_effects_chain_t *chain, sox_effect_t *effp) +{ + if (chain->length == chain->table_size) { + chain->table_size += EFF_TABLE_STEP; + lsx_debug_more("sox_push_effect_last: extending effects table, " + "new size = %" PRIuPTR, chain->table_size); + lsx_revalloc(chain->effects, chain->table_size); + } + + chain->effects[chain->length++] = effp; +} /* sox_push_effect_last */ + +sox_effect_t *sox_pop_effect_last(sox_effects_chain_t *chain) +{ + if (chain->length > 0) + { + sox_effect_t *effp; + chain->length--; + effp = chain->effects[chain->length]; + chain->effects[chain->length] = NULL; + return effp; + } + else + return NULL; +} /* sox_pop_effect_last */ + +/* Free resources related to effect. + * Note: This currently closes down the effect which might + * not be obvious from name. + */ +void sox_delete_effect(sox_effect_t *effp) +{ + uint64_t clips; + size_t f; + + if ((clips = sox_stop_effect(effp)) != 0) + lsx_warn("%s clipped %" PRIu64 " samples; decrease volume?", + effp->handler.name, clips); + if (effp->obeg != effp->oend) + lsx_debug("output buffer still held %" PRIuPTR " samples; dropped.", + (effp->oend - effp->obeg)/effp->out_signal.channels); + /* May or may not indicate a problem; it is normal if the user aborted + processing, or if an effect like "trim" stopped early. */ + effp->handler.kill(effp); /* N.B. only one kill; not one per flow */ + for (f = 0; f < effp->flows; ++f) + free(effp[f].priv); + free(effp->obuf); + free(effp); +} + +void sox_delete_effect_last(sox_effects_chain_t *chain) +{ + if (chain->length > 0) + { + chain->length--; + sox_delete_effect(chain->effects[chain->length]); + chain->effects[chain->length] = NULL; + } +} /* sox_delete_effect_last */ + +/* Remove all effects from the chain. + * Note: This currently closes down the effect which might + * not be obvious from name. + */ +void sox_delete_effects(sox_effects_chain_t * chain) +{ + size_t e; + + for (e = 0; e < chain->length; ++e) { + sox_delete_effect(chain->effects[e]); + chain->effects[e] = NULL; + } + chain->length = 0; +} + +/*----------------------------- Effects library ------------------------------*/ + +static sox_effect_fn_t s_sox_effect_fns[] = { +#define EFFECT(f) lsx_##f##_effect_fn, +#include "effects.h" +#undef EFFECT + NULL +}; + +const sox_effect_fn_t* +sox_get_effect_fns(void) +{ + return s_sox_effect_fns; +} + +/* Find a named effect in the effects library */ +sox_effect_handler_t const * sox_find_effect(char const * name) +{ + int e; + sox_effect_fn_t const * fns = sox_get_effect_fns(); + for (e = 0; fns[e]; ++e) { + const sox_effect_handler_t *eh = fns[e] (); + if (eh && eh->name && strcasecmp(eh->name, name) == 0) + return eh; /* Found it. */ + } + return NULL; +} + + +/*----------------------------- Helper functions -----------------------------*/ + +/* interleave() parameters: + * flows: number of samples per wide sample + * length: number of samples to copy + * [pertaining to the (non-interleaved) source buffer:] + * from: start address + * bufsiz: total size + * offset: position at which to start reading + * [pertaining to the (interleaved) destination buffer:] + * to: start address + */ +static void interleave(size_t flows, size_t length, sox_sample_t *from, + size_t bufsiz, size_t offset, sox_sample_t *to) +{ + size_t i; + const size_t wide_samples = length/flows; + const size_t flow_offs = bufsiz/flows; + from += offset/flows; + for (i = 0; i < wide_samples; i++) { + sox_sample_t *inner_from = from + i; + sox_sample_t *inner_to = to + i * flows; + size_t f; + for (f = 0; f < flows; f++) { + *inner_to++ = *inner_from; + inner_from += flow_offs; + } + } +} + +/* deinterleave() parameters: + * flows: number of samples per wide sample + * length: number of samples to copy + * [pertaining to the (interleaved) source buffer:] + * from: start address + * [pertaining to the (non-interleaved) destination buffer:] + * to: start address + * bufsiz: total size + * offset: position at which to start writing + */ +static void deinterleave(size_t flows, size_t length, sox_sample_t *from, + sox_sample_t *to, size_t bufsiz, size_t offset) +{ + const size_t wide_samples = length/flows; + const size_t flow_offs = bufsiz/flows; + size_t f; + to += offset/flows; + for (f = 0; f < flows; f++) { + sox_sample_t *inner_to = to + f*flow_offs; + sox_sample_t *inner_from = from + f; + size_t i = wide_samples; + while (i--) { + *inner_to++ = *inner_from; + inner_from += flows; + } + } +} diff --git a/app/src/main/cpp/sox/effects.h b/app/src/main/cpp/sox/effects.h new file mode 100644 index 0000000..450a5c2 --- /dev/null +++ b/app/src/main/cpp/sox/effects.h @@ -0,0 +1,90 @@ +/* This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* FIXME: generate this list automatically */ + + EFFECT(allpass) + EFFECT(band) + EFFECT(bandpass) + EFFECT(bandreject) + EFFECT(bass) + EFFECT(bend) + EFFECT(biquad) + EFFECT(chorus) + EFFECT(channels) + EFFECT(compand) + EFFECT(contrast) + EFFECT(dcshift) + EFFECT(deemph) + EFFECT(delay) + EFFECT(dft_filter) /* abstract */ + EFFECT(dither) + EFFECT(divide) + EFFECT(downsample) + EFFECT(earwax) + EFFECT(echo) + EFFECT(echos) + EFFECT(equalizer) + EFFECT(fade) + EFFECT(fir) + EFFECT(firfit) + EFFECT(flanger) + EFFECT(gain) + EFFECT(highpass) + EFFECT(hilbert) + EFFECT(input) +#ifdef HAVE_LADSPA_H + EFFECT(ladspa) +#endif + EFFECT(loudness) + EFFECT(lowpass) + EFFECT(mcompand) + EFFECT(noiseprof) + EFFECT(noisered) + EFFECT(norm) + EFFECT(oops) + EFFECT(output) + EFFECT(overdrive) + EFFECT(pad) + EFFECT(phaser) + EFFECT(pitch) + EFFECT(rate) + EFFECT(remix) + EFFECT(repeat) + EFFECT(reverb) + EFFECT(reverse) + EFFECT(riaa) + EFFECT(silence) + EFFECT(sinc) +#ifdef HAVE_PNG + EFFECT(spectrogram) +#endif + EFFECT(speed) +#ifdef HAVE_SPEEXDSP + EFFECT(speexdsp) +#endif + EFFECT(splice) + EFFECT(stat) + EFFECT(stats) + EFFECT(stretch) + EFFECT(swap) + EFFECT(synth) + EFFECT(tempo) + EFFECT(treble) + EFFECT(tremolo) + EFFECT(trim) + EFFECT(upsample) + EFFECT(vad) + EFFECT(vol) diff --git a/app/src/main/cpp/sox/effects_i.c b/app/src/main/cpp/sox/effects_i.c new file mode 100644 index 0000000..685e962 --- /dev/null +++ b/app/src/main/cpp/sox/effects_i.c @@ -0,0 +1,483 @@ +/* Implements a libSoX internal interface for implementing effects. + * All public functions & data are prefixed with lsx_ . + * + * Copyright (c) 2005-2012 Chris Bagwell and SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define LSX_EFF_ALIAS +#include "sox_i.h" +#include +#include + +int lsx_usage(sox_effect_t * effp) +{ + if (effp->handler.usage) + lsx_fail("usage: %s", effp->handler.usage); + else + lsx_fail("this effect takes no parameters"); + return SOX_EOF; +} + +char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n) +{ + if (!*usage) { + size_t i, len; + for (len = i = 0; i < n; len += strlen(lines[i++]) + 1); + *usage = lsx_malloc(len); /* FIXME: this memory will never be freed */ + strcpy(*usage, lines[0]); + for (i = 1; i < n; ++i) { + strcat(*usage, "\n"); + strcat(*usage, lines[i]); + } + } + return *usage; +} + +static lsx_enum_item const s_lsx_wave_enum[] = { + LSX_ENUM_ITEM(SOX_WAVE_,SINE) + LSX_ENUM_ITEM(SOX_WAVE_,TRIANGLE) + {0, 0}}; + +lsx_enum_item const * lsx_get_wave_enum(void) +{ + return s_lsx_wave_enum; +} + +void lsx_generate_wave_table( + lsx_wave_t wave_type, + sox_data_t data_type, + void *table, + size_t table_size, + double min, + double max, + double phase) +{ + uint32_t t; + uint32_t phase_offset = phase / M_PI / 2 * table_size + 0.5; + + for (t = 0; t < table_size; t++) + { + uint32_t point = (t + phase_offset) % table_size; + double d; + switch (wave_type) + { + case SOX_WAVE_SINE: + d = (sin((double)point / table_size * 2 * M_PI) + 1) / 2; + break; + + case SOX_WAVE_TRIANGLE: + d = (double)point * 2 / table_size; + switch (4 * point / table_size) + { + case 0: d = d + 0.5; break; + case 1: case 2: d = 1.5 - d; break; + case 3: d = d - 1.5; break; + } + break; + + default: /* Oops! FIXME */ + d = 0.0; /* Make sure we have a value */ + break; + } + d = d * (max - min) + min; + switch (data_type) + { + case SOX_FLOAT: + { + float *fp = (float *)table; + *fp++ = (float)d; + table = fp; + continue; + } + case SOX_DOUBLE: + { + double *dp = (double *)table; + *dp++ = d; + table = dp; + continue; + } + default: break; + } + d += d < 0? -0.5 : +0.5; + switch (data_type) + { + case SOX_SHORT: + { + short *sp = table; + *sp++ = (short)d; + table = sp; + continue; + } + case SOX_INT: + { + int *ip = table; + *ip++ = (int)d; + table = ip; + continue; + } + default: break; + } + } +} + +/* + * lsx_parsesamples + * + * Parse a string for # of samples. The input consists of one or more + * parts, with '+' or '-' between them indicating if the sample count + * should be added to or subtracted from the previous value. + * If a part ends with a 's' then it is interpreted as a + * user-calculated # of samples. + * If a part contains ':' or '.' but no 'e' or if it ends with a 't' + * then it is treated as an amount of time. This is converted into + * seconds and fraction of seconds, then the sample rate is used to + * calculate # of samples. + * Parameter def specifies which interpretation should be the default + * for a bare number like "123". It can either be 't' or 's'. + * Returns NULL on error, pointer to next char to parse otherwise. + */ +static char const * parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def, int combine); + +char const * lsx_parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def) +{ + *samples = 0; + return parsesamples(rate, str0, samples, def, '+'); +} + +static char const * parsesamples(sox_rate_t rate, const char *str0, uint64_t *samples, int def, int combine) +{ + char * str = (char *)str0; + + do { + uint64_t samples_part; + sox_bool found_samples = sox_false, found_time = sox_false; + char const * end; + char const * pos; + sox_bool found_colon, found_dot, found_e; + + for (;*str == ' '; ++str); + for (end = str; *end && strchr("0123456789:.ets", *end); ++end); + if (end == str) + return NULL; /* error: empty input */ + + pos = strchr(str, ':'); + found_colon = pos && pos < end; + + pos = strchr(str, '.'); + found_dot = pos && pos < end; + + pos = strchr(str, 'e'); + found_e = pos && pos < end; + + if (found_colon || (found_dot && !found_e) || *(end-1) == 't') + found_time = sox_true; + else if (*(end-1) == 's') + found_samples = sox_true; + + if (found_time || (def == 't' && !found_samples)) { + int i; + if (found_e) + return NULL; /* error: e notation in time */ + + for (samples_part = 0, i = 0; *str != '.' && i < 3; ++i) { + char * last_str = str; + long part = strtol(str, &str, 10); + if (!i && str == last_str) + return NULL; /* error: empty first component */ + samples_part += rate * part; + if (i < 2) { + if (*str != ':') + break; + ++str; + samples_part *= 60; + } + } + if (*str == '.') { + char * last_str = str; + double part = strtod(str, &str); + if (str == last_str) + return NULL; /* error: empty fractional part */ + samples_part += rate * part + .5; + } + if (*str == 't') + str++; + } else { + char * last_str = str; + double part = strtod(str, &str); + if (str == last_str) + return NULL; /* error: no sample count */ + samples_part = part + .5; + if (*str == 's') + str++; + } + if (str != end) + return NULL; /* error: trailing characters */ + + switch (combine) { + case '+': *samples += samples_part; break; + case '-': *samples = samples_part <= *samples ? + *samples - samples_part : 0; + break; + } + combine = '\0'; + if (*str && strchr("+-", *str)) + combine = *str++; + } while (combine); + return str; +} + +#if 0 + +#include + +#define TEST(st, samp, len) \ + str = st; \ + next = lsx_parsesamples(10000, str, &samples, 't'); \ + assert(samples == samp && next == str + len); + +int main(int argc, char * * argv) +{ + char const * str, * next; + uint64_t samples; + + TEST("0" , 0, 1) + TEST("1" , 10000, 1) + + TEST("0s" , 0, 2) + TEST("0s,", 0, 2) + TEST("0s/", 0, 2) + TEST("0s@", 0, 2) + + TEST("0t" , 0, 2) + TEST("0t,", 0, 2) + TEST("0t/", 0, 2) + TEST("0t@", 0, 2) + + TEST("1s" , 1, 2) + TEST("1s,", 1, 2) + TEST("1s/", 1, 2) + TEST("1s@", 1, 2) + TEST(" 01s" , 1, 4) + TEST("1e6s" , 1000000, 4) + + TEST("1t" , 10000, 2) + TEST("1t,", 10000, 2) + TEST("1t/", 10000, 2) + TEST("1t@", 10000, 2) + TEST("1.1t" , 11000, 4) + TEST("1.1t,", 11000, 4) + TEST("1.1t/", 11000, 4) + TEST("1.1t@", 11000, 4) + assert(!lsx_parsesamples(10000, "1e6t", &samples, 't')); + + TEST(".0", 0, 2) + TEST("0.0", 0, 3) + TEST("0:0.0", 0, 5) + TEST("0:0:0.0", 0, 7) + + TEST(".1", 1000, 2) + TEST(".10", 1000, 3) + TEST("0.1", 1000, 3) + TEST("1.1", 11000, 3) + TEST("1:1.1", 611000, 5) + TEST("1:1:1.1", 36611000, 7) + TEST("1:1", 610000, 3) + TEST("1:01", 610000, 4) + TEST("1:1:1", 36610000, 5) + TEST("1:", 600000, 2) + TEST("1::", 36000000, 3) + + TEST("0.444444", 4444, 8) + TEST("0.555555", 5556, 8) + + assert(!lsx_parsesamples(10000, "x", &samples, 't')); + + TEST("1:23+37", 1200000, 7) + TEST("12t+12s", 120012, 7) + TEST("1e6s-10", 900000, 7) + TEST("10-2:00", 0, 7) + TEST("123-45+12s+2:00-3e3s@foo", 1977012, 20) + + TEST("1\0" "2", 10000, 1) + + return 0; +} +#endif + +/* + * lsx_parseposition + * + * Parse a string for an audio position. Similar to lsx_parsesamples + * above, but an initial '=', '+' or '-' indicates that the specified time + * is relative to the start of audio, last used position or end of audio, + * respectively. Parameter def states which of these is the default. + * Parameters latest and end are the positions to which '+' and '-' relate; + * end may be SOX_UNKNOWN_LEN, in which case "-0" is the only valid + * end-relative input and will result in a position of SOX_UNKNOWN_LEN. + * Other parameters and return value are the same as for lsx_parsesamples. + * + * A test parse that only checks for valid syntax can be done by + * specifying samples = NULL. If this passes, a later reparse of the same + * input will only fail if it is relative to the end ("-"), not "-0", and + * the end position is unknown. + */ +char const * lsx_parseposition(sox_rate_t rate, const char *str0, uint64_t *samples, uint64_t latest, uint64_t end, int def) +{ + char *str = (char *)str0; + char anchor, combine; + + if (!strchr("+-=", def)) + return NULL; /* error: invalid default anchor */ + anchor = def; + if (*str && strchr("+-=", *str)) + anchor = *str++; + + combine = '+'; + if (strchr("+-", anchor)) { + combine = anchor; + if (*str && strchr("+-", *str)) + combine = *str++; + } + + if (!samples) { + /* dummy parse, syntax checking only */ + uint64_t dummy = 0; + return parsesamples(0., str, &dummy, 't', '+'); + } + + switch (anchor) { + case '=': *samples = 0; break; + case '+': *samples = latest; break; + case '-': *samples = end; break; + } + + if (anchor == '-' && end == SOX_UNKNOWN_LEN) { + /* "-0" only valid input here */ + char const *l; + for (l = str; *l && strchr("0123456789:.ets+-", *l); ++l); + if (l == str+1 && *str == '0') { + /* *samples already set to SOX_UNKNOWN_LEN */ + return l; + } + return NULL; /* error: end-relative position, but end unknown */ + } + + return parsesamples(rate, str, samples, 't', combine); +} + +/* a note is given as an int, + * 0 => 440 Hz = A + * >0 => number of half notes 'up', + * <0 => number of half notes down, + * example 12 => A of next octave, 880Hz + * + * calculated by freq = 440Hz * 2**(note/12) + */ +static double calc_note_freq(double note, int key) +{ + if (key != INT_MAX) { /* Just intonation. */ + static const int n[] = {16, 9, 6, 5, 4, 7}; /* Numerator. */ + static const int d[] = {15, 8, 5, 4, 3, 5}; /* Denominator. */ + static double j[13]; /* Just semitones */ + int i, m = floor(note); + + if (!j[1]) for (i = 1; i <= 12; ++i) + j[i] = i <= 6? log((double)n[i - 1] / d[i - 1]) / log(2.) : 1 - j[12 - i]; + note -= m; + m -= key = m - ((INT_MAX / 2 - ((INT_MAX / 2) % 12) + m - key) % 12); + return 440 * pow(2., key / 12. + j[m] + (j[m + 1] - j[m]) * note); + } + return 440 * pow(2., note / 12); +} + +int lsx_parse_note(char const * text, char * * end_ptr) +{ + int result = INT_MAX; + + if (*text >= 'A' && *text <= 'G') { + result = (int)(5/3. * (*text++ - 'A') + 9.5) % 12 - 9; + if (*text == 'b') {--result; ++text;} + else if (*text == '#') {++result; ++text;} + if (isdigit((unsigned char)*text)) + result += 12 * (*text++ - '4'); + } + *end_ptr = (char *)text; + return result; +} + +/* Read string 'text' and convert to frequency. + * 'text' can be a positive number which is the frequency in Hz. + * If 'text' starts with a '%' and a following number the corresponding + * note is calculated. + * Return -1 on error. + */ +double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key) +{ + double result; + + if (*text == '%') { + result = strtod(text + 1, end_ptr); + if (*end_ptr == text + 1) + return -1; + return calc_note_freq(result, key); + } + if (*text >= 'A' && *text <= 'G') { + int result2 = lsx_parse_note(text, end_ptr); + return result2 == INT_MAX? - 1 : calc_note_freq((double)result2, key); + } + result = strtod(text, end_ptr); + if (end_ptr) { + if (*end_ptr == text) + return -1; + if (**end_ptr == 'k') { + result *= 1000; + ++*end_ptr; + } + } + return result < 0 ? -1 : result; +} + +FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename, sox_bool text_mode) +{ + FILE * file; + + if (!filename || !strcmp(filename, "-")) { + if (effp->global_info->global_info->stdin_in_use_by) { + lsx_fail("stdin already in use by `%s'", effp->global_info->global_info->stdin_in_use_by); + return NULL; + } + effp->global_info->global_info->stdin_in_use_by = effp->handler.name; + file = stdin; + } + else if (!(file = fopen(filename, text_mode ? "r" : "rb"))) { + lsx_fail("couldn't open file %s: %s", filename, strerror(errno)); + return NULL; + } + return file; +} + +int lsx_effects_init(void) +{ + init_fft_cache(); + return SOX_SUCCESS; +} + +int lsx_effects_quit(void) +{ + clear_fft_cache(); + return SOX_SUCCESS; +} diff --git a/app/src/main/cpp/sox/effects_i_dsp.c b/app/src/main/cpp/sox/effects_i_dsp.c new file mode 100644 index 0000000..88b1b39 --- /dev/null +++ b/app/src/main/cpp/sox/effects_i_dsp.c @@ -0,0 +1,645 @@ +/* libSoX internal DSP functions. + * All public functions & data are prefixed with lsx_ . + * + * Copyright (c) 2008,2012 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef NDEBUG /* Enable assert always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox_i.h" +#include +#include + +/* Concurrent Control with "Readers" and "Writers", P.J. Courtois et al, 1971:*/ + +#if defined HAVE_OPENMP + +typedef struct { + int readcount, writecount; /* initial value = 0 */ + omp_lock_t mutex_1, mutex_2, mutex_3, w, r; /* initial value = 1 */ +} ccrw2_t; /* Problem #2: `writers-preference' */ + +#define ccrw2_become_reader(p) do {\ + omp_set_lock(&p.mutex_3);\ + omp_set_lock(&p.r);\ + omp_set_lock(&p.mutex_1);\ + if (++p.readcount == 1) omp_set_lock(&p.w);\ + omp_unset_lock(&p.mutex_1);\ + omp_unset_lock(&p.r);\ + omp_unset_lock(&p.mutex_3);\ +} while (0) +#define ccrw2_cease_reading(p) do {\ + omp_set_lock(&p.mutex_1);\ + if (!--p.readcount) omp_unset_lock(&p.w);\ + omp_unset_lock(&p.mutex_1);\ +} while (0) +#define ccrw2_become_writer(p) do {\ + omp_set_lock(&p.mutex_2);\ + if (++p.writecount == 1) omp_set_lock(&p.r);\ + omp_unset_lock(&p.mutex_2);\ + omp_set_lock(&p.w);\ +} while (0) +#define ccrw2_cease_writing(p) do {\ + omp_unset_lock(&p.w);\ + omp_set_lock(&p.mutex_2);\ + if (!--p.writecount) omp_unset_lock(&p.r);\ + omp_unset_lock(&p.mutex_2);\ +} while (0) +#define ccrw2_init(p) do {\ + omp_init_lock(&p.mutex_1);\ + omp_init_lock(&p.mutex_2);\ + omp_init_lock(&p.mutex_3);\ + omp_init_lock(&p.w);\ + omp_init_lock(&p.r);\ +} while (0) +#define ccrw2_clear(p) do {\ + omp_destroy_lock(&p.r);\ + omp_destroy_lock(&p.w);\ + omp_destroy_lock(&p.mutex_3);\ + omp_destroy_lock(&p.mutex_2);\ + omp_destroy_lock(&p.mutex_1);\ +} while (0) + +#else + +#define ccrw2_become_reader(x) (void)0 +#define ccrw2_cease_reading(x) (void)0 +#define ccrw2_become_writer(x) (void)0 +#define ccrw2_cease_writing(x) (void)0 +#define ccrw2_init(x) (void)0 +#define ccrw2_clear(x) (void)0 + +#endif /* HAVE_OPENMP */ + +/* Numerical Recipes cubic spline: */ + +void lsx_prepare_spline3(double const * x, double const * y, int n, + double start_1d, double end_1d, double * y_2d) +{ + double p, qn, sig, un, * u = lsx_malloc((n - 1) * sizeof(*u)); + int i; + + if (start_1d == HUGE_VAL) + y_2d[0] = u[0] = 0; /* Start with natural spline or */ + else { /* set the start first derivative */ + y_2d[0] = -.5; + u[0] = (3 / (x[1] - x[0])) * ((y[1] - y[0]) / (x[1] - x[0]) - start_1d); + } + + for (i = 1; i < n - 1; ++i) { + sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); + p = sig * y_2d[i - 1] + 2; + y_2d[i] = (sig - 1) / p; + u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - + (y[i] - y[i - 1]) / (x[i] - x[i - 1]); + u[i] = (6 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; + } + if (end_1d == HUGE_VAL) + qn = un = 0; /* End with natural spline or */ + else { /* set the end first derivative */ + qn = .5; + un = 3 / (x[n - 1] - x[n - 2]) * (end_1d - (y[n - 1] - y[n - 2]) / (x[n - 1] - x[n - 2])); + } + y_2d[n - 1] = (un - qn * u[n - 2]) / (qn * y_2d[n - 2] + 1); + for (i = n - 2; i >= 0; --i) + y_2d[i] = y_2d[i] * y_2d[i + 1] + u[i]; + free(u); +} + +double lsx_spline3(double const * x, double const * y, double const * y_2d, + int n, double x1) +{ + int t, i[2] = {0, 0}; + double d, a, b; + + for (i[1] = n - 1; i[1] - i[0] > 1; t = (i[1] + i[0]) >> 1, i[x[t] > x1] = t); + d = x[i[1]] - x[i[0]]; + assert(d != 0); + a = (x[i[1]] - x1) / d; + b = (x1 - x[i[0]]) / d; + return a * y[i[0]] + b * y[i[1]] + + ((a * a * a - a) * y_2d[i[0]] + (b * b * b - b) * y_2d[i[1]]) * d * d / 6; +} + +double lsx_bessel_I_0(double x) +{ + double term = 1, sum = 1, last_sum, x2 = x / 2; + int i = 1; + do { + double y = x2 / i++; + last_sum = sum, sum += term *= y * y; + } while (sum != last_sum); + return sum; +} + +int lsx_set_dft_length(int num_taps) /* Set to 4 x nearest power of 2 */ +{ /* or half of that if danger of causing too many cache misses. */ + int min = sox_globals.log2_dft_min_size; + double d = log((double)num_taps) / log(2.); + return 1 << range_limit((int)(d + 2.77), min, max((int)(d + 1.77), 17)); +} + +#include "fft4g.h" +static int * lsx_fft_br; +static double * lsx_fft_sc; +static int fft_len = -1; +#if defined HAVE_OPENMP +static ccrw2_t fft_cache_ccrw; +#endif + +void init_fft_cache(void) +{ + assert(lsx_fft_br == NULL); + assert(lsx_fft_sc == NULL); + assert(fft_len == -1); + ccrw2_init(fft_cache_ccrw); + fft_len = 0; +} + +void clear_fft_cache(void) +{ + assert(fft_len >= 0); + ccrw2_clear(fft_cache_ccrw); + free(lsx_fft_br); + free(lsx_fft_sc); + lsx_fft_sc = NULL; + lsx_fft_br = NULL; + fft_len = -1; +} + +static sox_bool update_fft_cache(int len) +{ + assert(lsx_is_power_of_2(len)); + assert(fft_len >= 0); + ccrw2_become_reader(fft_cache_ccrw); + if (len > fft_len) { + ccrw2_cease_reading(fft_cache_ccrw); + ccrw2_become_writer(fft_cache_ccrw); + if (len > fft_len) { + int old_n = fft_len; + fft_len = len; + lsx_fft_br = lsx_realloc(lsx_fft_br, dft_br_len(fft_len) * sizeof(*lsx_fft_br)); + lsx_fft_sc = lsx_realloc(lsx_fft_sc, dft_sc_len(fft_len) * sizeof(*lsx_fft_sc)); + if (!old_n) + lsx_fft_br[0] = 0; + return sox_true; + } + ccrw2_cease_writing(fft_cache_ccrw); + ccrw2_become_reader(fft_cache_ccrw); + } + return sox_false; +} + +static void done_with_fft_cache(sox_bool is_writer) +{ + if (is_writer) + ccrw2_cease_writing(fft_cache_ccrw); + else ccrw2_cease_reading(fft_cache_ccrw); +} + +void lsx_safe_rdft(int len, int type, double * d) +{ + sox_bool is_writer = update_fft_cache(len); + lsx_rdft(len, type, d, lsx_fft_br, lsx_fft_sc); + done_with_fft_cache(is_writer); +} + +void lsx_safe_cdft(int len, int type, double * d) +{ + sox_bool is_writer = update_fft_cache(len); + lsx_cdft(len, type, d, lsx_fft_br, lsx_fft_sc); + done_with_fft_cache(is_writer); +} + +void lsx_power_spectrum(int n, double const * in, double * out) +{ + int i; + double * work = lsx_memdup(in, n * sizeof(*work)); + lsx_safe_rdft(n, 1, work); + out[0] = sqr(work[0]); + for (i = 2; i < n; i += 2) + out[i >> 1] = sqr(work[i]) + sqr(work[i + 1]); + out[i >> 1] = sqr(work[1]); + free(work); +} + +void lsx_power_spectrum_f(int n, float const * in, float * out) +{ + int i; + double * work = lsx_malloc(n * sizeof(*work)); + for (i = 0; i< n; ++i) work[i] = in[i]; + lsx_safe_rdft(n, 1, work); + out[0] = sqr(work[0]); + for (i = 2; i < n; i += 2) + out[i >> 1] = sqr(work[i]) + sqr(work[i + 1]); + out[i >> 1] = sqr(work[1]); + free(work); +} + +void lsx_apply_hann_f(float h[], const int num_points) +{ + int i, m = num_points - 1; + for (i = 0; i < num_points; ++i) { + double x = 2 * M_PI * i / m; + h[i] *= .5 - .5 * cos(x); + } +} + +void lsx_apply_hann(double h[], const int num_points) +{ + int i, m = num_points - 1; + for (i = 0; i < num_points; ++i) { + double x = 2 * M_PI * i / m; + h[i] *= .5 - .5 * cos(x); + } +} + +void lsx_apply_hamming(double h[], const int num_points) +{ + int i, m = num_points - 1; + for (i = 0; i < num_points; ++i) { + double x = 2 * M_PI * i / m; + h[i] *= .53836 - .46164 * cos(x); + } +} + +void lsx_apply_bartlett(double h[], const int num_points) +{ + int i, m = num_points - 1; + for (i = 0; i < num_points; ++i) { + h[i] *= 2. / m * (m / 2. - fabs(i - m / 2.)); + } +} + +void lsx_apply_blackman(double h[], const int num_points, double alpha /*.16*/) +{ + int i, m = num_points - 1; + for (i = 0; i < num_points; ++i) { + double x = 2 * M_PI * i / m; + h[i] *= (1 - alpha) *.5 - .5 * cos(x) + alpha * .5 * cos(2 * x); + } +} + +void lsx_apply_blackman_nutall(double h[], const int num_points) +{ + int i, m = num_points - 1; + for (i = 0; i < num_points; ++i) { + double x = 2 * M_PI * i / m; + h[i] *= .3635819 - .4891775 * cos(x) + .1365995 * cos(2 * x) - .0106411 * cos(3 * x); + } +} + +double lsx_kaiser_beta(double att, double tr_bw) +{ + if (att >= 60) { + static const double coefs[][4] = { + {-6.784957e-10,1.02856e-05,0.1087556,-0.8988365+.001}, + {-6.897885e-10,1.027433e-05,0.10876,-0.8994658+.002}, + {-1.000683e-09,1.030092e-05,0.1087677,-0.9007898+.003}, + {-3.654474e-10,1.040631e-05,0.1087085,-0.8977766+.006}, + {8.106988e-09,6.983091e-06,0.1091387,-0.9172048+.015}, + {9.519571e-09,7.272678e-06,0.1090068,-0.9140768+.025}, + {-5.626821e-09,1.342186e-05,0.1083999,-0.9065452+.05}, + {-9.965946e-08,5.073548e-05,0.1040967,-0.7672778+.085}, + {1.604808e-07,-5.856462e-05,0.1185998,-1.34824+.1}, + {-1.511964e-07,6.363034e-05,0.1064627,-0.9876665+.18}, + }; + double realm = log(tr_bw/.0005)/log(2.); + double const * c0 = coefs[range_limit( (int)realm, 0, (int)array_length(coefs)-1)]; + double const * c1 = coefs[range_limit(1+(int)realm, 0, (int)array_length(coefs)-1)]; + double b0 = ((c0[0]*att + c0[1])*att + c0[2])*att + c0[3]; + double b1 = ((c1[0]*att + c1[1])*att + c1[2])*att + c1[3]; + return b0 + (b1 - b0) * (realm - (int)realm); + } + if (att > 50 ) return .1102 * (att - 8.7); + if (att > 20.96) return .58417 * pow(att -20.96, .4) + .07886 * (att - 20.96); + return 0; +} + +void lsx_apply_kaiser(double h[], const int num_points, double beta) +{ + int i, m = num_points - 1; + for (i = 0; i <= m; ++i) { + double x = 2. * i / m - 1; + h[i] *= lsx_bessel_I_0(beta * sqrt(1 - x * x)) / lsx_bessel_I_0(beta); + } +} + +void lsx_apply_dolph(double h[], const int N, double att) +{ + double b = cosh(acosh(pow(10., att/20)) / (N-1)), sum, t, c, norm = 0; + int i, j; + for (c = 1 - 1 / (b*b), i = (N-1) / 2; i >= 0; --i) { + for (sum = !i, b = t = j = 1; j <= i && sum != t; b *= (i-j) * (1./j), ++j) + t = sum, sum += (b *= c * (N - i - j) * (1./j)); + sum /= (N - 1 - i), sum /= (norm = norm? norm : sum); + h[i] *= sum, h[N - 1 - i] *= sum; + } +} + +double * lsx_make_lpf(int num_taps, double Fc, double beta, double rho, + double scale, sox_bool dc_norm) +{ + int i, m = num_taps - 1; + double * h = calloc(num_taps, sizeof(*h)), sum = 0; + double mult = scale / lsx_bessel_I_0(beta), mult1 = 1 / (.5 * m + rho); + assert(Fc >= 0 && Fc <= 1); + lsx_debug("make_lpf(n=%i Fc=%.7g β=%g ρ=%g dc-norm=%i scale=%g)", num_taps, Fc, beta, rho, dc_norm, scale); + + if (!h) + return NULL; + + for (i = 0; i <= m / 2; ++i) { + double z = i - .5 * m, x = z * M_PI, y = z * mult1; + h[i] = x? sin(Fc * x) / x : Fc; + sum += h[i] *= lsx_bessel_I_0(beta * sqrt(1 - y * y)) * mult; + if (m - i != i) + sum += h[m - i] = h[i]; + } + for (i = 0; dc_norm && i < num_taps; ++i) h[i] *= scale / sum; + return h; +} + +void lsx_kaiser_params(double att, double Fc, double tr_bw, double * beta, int * num_taps) +{ + *beta = *beta < 0? lsx_kaiser_beta(att, tr_bw * .5 / Fc): *beta; + att = att < 60? (att - 7.95) / (2.285 * M_PI * 2) : + ((.0007528358-1.577737e-05**beta)**beta+.6248022)**beta+.06186902; + *num_taps = !*num_taps? ceil(att/tr_bw + 1) : *num_taps; +} + +double * lsx_design_lpf( + double Fp, /* End of pass-band */ + double Fs, /* Start of stop-band */ + double Fn, /* Nyquist freq; e.g. 0.5, 1, PI */ + double att, /* Stop-band attenuation in dB */ + int * num_taps, /* 0: value will be estimated */ + int k, /* >0: number of phases; <0: num_taps ≡ 1 (mod -k) */ + double beta) /* <0: value will be estimated */ +{ + int n = *num_taps, phases = max(k, 1), modulo = max(-k, 1); + double tr_bw, Fc, rho = phases == 1? .5 : att < 120? .63 : .75; + + Fp /= fabs(Fn), Fs /= fabs(Fn); /* Normalise to Fn = 1 */ + tr_bw = .5 * (Fs - Fp); /* Transition band-width: 6dB to stop points */ + tr_bw /= phases, Fs /= phases; + tr_bw = min(tr_bw, .5 * Fs); + Fc = Fs - tr_bw; + assert(Fc - tr_bw >= 0); + lsx_kaiser_params(att, Fc, tr_bw, &beta, num_taps); + if (!n) + *num_taps = phases > 1? *num_taps / phases * phases + phases - 1 : (*num_taps + modulo - 2) / modulo * modulo + 1; + return Fn < 0? 0 : lsx_make_lpf( + *num_taps, Fc, beta, rho, (double)phases, sox_false); +} + +static double safe_log(double x) +{ + assert(x >= 0); + if (x) + return log(x); + lsx_debug("log(0)"); + return -26; +} + +void lsx_fir_to_phase(double * * h, int * len, int * post_len, double phase) +{ + double * pi_wraps, * work, phase1 = (phase > 50 ? 100 - phase : phase) / 50; + int i, work_len, begin, end, imp_peak = 0, peak = 0; + double imp_sum = 0, peak_imp_sum = 0; + double prev_angle2 = 0, cum_2pi = 0, prev_angle1 = 0, cum_1pi = 0; + + for (i = *len, work_len = 2 * 2 * 8; i > 1; work_len <<= 1, i >>= 1); + + work = lsx_calloc((size_t)work_len + 2, sizeof(*work)); /* +2: (UN)PACK */ + pi_wraps = lsx_malloc((((size_t)work_len + 2) / 2) * sizeof(*pi_wraps)); + + memcpy(work, *h, *len * sizeof(*work)); + lsx_safe_rdft(work_len, 1, work); /* Cepstral: */ + LSX_UNPACK(work, work_len); + + for (i = 0; i <= work_len; i += 2) { + double angle = atan2(work[i + 1], work[i]); + double detect = 2 * M_PI; + double delta = angle - prev_angle2; + double adjust = detect * ((delta < -detect * .7) - (delta > detect * .7)); + prev_angle2 = angle; + cum_2pi += adjust; + angle += cum_2pi; + detect = M_PI; + delta = angle - prev_angle1; + adjust = detect * ((delta < -detect * .7) - (delta > detect * .7)); + prev_angle1 = angle; + cum_1pi += fabs(adjust); /* fabs for when 2pi and 1pi have combined */ + pi_wraps[i >> 1] = cum_1pi; + + work[i] = safe_log(sqrt(sqr(work[i]) + sqr(work[i + 1]))); + work[i + 1] = 0; + } + LSX_PACK(work, work_len); + lsx_safe_rdft(work_len, -1, work); + for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len; + + for (i = 1; i < work_len / 2; ++i) { /* Window to reject acausal components */ + work[i] *= 2; + work[i + work_len / 2] = 0; + } + lsx_safe_rdft(work_len, 1, work); + + for (i = 2; i < work_len; i += 2) /* Interpolate between linear & min phase */ + work[i + 1] = phase1 * i / work_len * pi_wraps[work_len >> 1] + + (1 - phase1) * (work[i + 1] + pi_wraps[i >> 1]) - pi_wraps[i >> 1]; + + work[0] = exp(work[0]), work[1] = exp(work[1]); + for (i = 2; i < work_len; i += 2) { + double x = exp(work[i]); + work[i ] = x * cos(work[i + 1]); + work[i + 1] = x * sin(work[i + 1]); + } + + lsx_safe_rdft(work_len, -1, work); + for (i = 0; i < work_len; ++i) work[i] *= 2. / work_len; + + /* Find peak pos. */ + for (i = 0; i <= (int)(pi_wraps[work_len >> 1] / M_PI + .5); ++i) { + imp_sum += work[i]; + if (fabs(imp_sum) > fabs(peak_imp_sum)) { + peak_imp_sum = imp_sum; + peak = i; + } + if (work[i] > work[imp_peak]) /* For debug check only */ + imp_peak = i; + } + while (peak && fabs(work[peak-1]) > fabs(work[peak]) && work[peak-1] * work[peak] > 0) + --peak; + + if (!phase1) + begin = 0; + else if (phase1 == 1) + begin = peak - *len / 2; + else { + begin = (.997 - (2 - phase1) * .22) * *len + .5; + end = (.997 + (0 - phase1) * .22) * *len + .5; + begin = peak - (begin & ~3); + end = peak + 1 + ((end + 3) & ~3); + *len = end - begin; + *h = lsx_realloc(*h, *len * sizeof(**h)); + } + for (i = 0; i < *len; ++i) (*h)[i] = + work[(begin + (phase > 50 ? *len - 1 - i : i) + work_len) & (work_len - 1)]; + *post_len = phase > 50 ? peak - begin : begin + *len - (peak + 1); + + lsx_debug("nPI=%g peak-sum@%i=%g (val@%i=%g); len=%i post=%i (%g%%)", + pi_wraps[work_len >> 1] / M_PI, peak, peak_imp_sum, imp_peak, + work[imp_peak], *len, *post_len, 100 - 100. * *post_len / (*len - 1)); + free(pi_wraps), free(work); +} + +void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2) +{ + int i, N = lsx_set_dft_length(num_points); + if (type == sox_plot_gnuplot) { + double * h1 = lsx_calloc(N, sizeof(*h1)); + double * H = lsx_malloc((N / 2 + 1) * sizeof(*H)); + memcpy(h1, h, sizeof(*h1) * num_points); + lsx_power_spectrum(N, h1, H); + printf( + "# gnuplot file\n" + "set title '%s'\n" + "set xlabel 'Frequency (Hz)'\n" + "set ylabel 'Amplitude Response (dB)'\n" + "set grid xtics ytics\n" + "set key off\n" + "plot '-' with lines\n" + , title); + for (i = 0; i <= N/2; ++i) + printf("%g %g\n", i * rate / N, 10 * log10(H[i])); + printf( + "e\n" + "pause -1 'Hit return to continue'\n"); + free(H); + free(h1); + } + else if (type == sox_plot_octave) { + printf("%% GNU Octave file (may also work with MATLAB(R) )\nb=["); + for (i = 0; i < num_points; ++i) + printf("%24.16e\n", h[i]); + printf("];\n" + "[h,w]=freqz(b,1,%i);\n" + "plot(%g*w/pi,20*log10(h))\n" + "title('%s')\n" + "xlabel('Frequency (Hz)')\n" + "ylabel('Amplitude Response (dB)')\n" + "grid on\n" + "axis([0 %g %g %g])\n" + "disp('Hit return to continue')\n" + "pause\n" + , N, rate * .5, title, rate * .5, y1, y2); + } + else if (type == sox_plot_data) { + printf("# %s\n" + "# FIR filter\n" + "# rate: %g\n" + "# name: b\n" + "# type: matrix\n" + "# rows: %i\n" + "# columns: 1\n", title, rate, num_points); + for (i = 0; i < num_points; ++i) + printf("%24.16e\n", h[i]); + } +} + +#if HAVE_FENV_H + #include + #if defined FE_INVALID + #if HAVE_LRINT && LONG_MAX == 2147483647 + #define lrint32 lrint + #elif defined __GNUC__ && defined __x86_64__ + #define lrint32 lrint32 + static __inline sox_int32_t lrint32(double input) { + sox_int32_t result; + __asm__ __volatile__("fistpl %0": "=m"(result): "t"(input): "st"); + return result; + } + #endif + #endif +#endif + +#if defined lrint32 +#define _ dest[i] = lrint32(src[i]), ++i, +#pragma STDC FENV_ACCESS ON + +static void rint_clip(sox_sample_t * const dest, double const * const src, + size_t i, size_t const n, sox_uint64_t * const clips) +{ + for (; i < n; ++i) { + dest[i] = lrint32(src[i]); + if (fetestexcept(FE_INVALID)) { + feclearexcept(FE_INVALID); + dest[i] = src[i] > 0? SOX_SAMPLE_MAX : SOX_SAMPLE_MIN; + ++*clips; + } + } +} + +void lsx_save_samples(sox_sample_t * const dest, double const * const src, + size_t const n, sox_uint64_t * const clips) +{ + size_t i; + feclearexcept(FE_INVALID); + for (i = 0; i < (n & ~7);) { + _ _ _ _ _ _ _ _ 0; + if (fetestexcept(FE_INVALID)) { + feclearexcept(FE_INVALID); + rint_clip(dest, src, i - 8, i, clips); + } + } + rint_clip(dest, src, i, n, clips); +} + +void lsx_load_samples(double * const dest, sox_sample_t const * const src, + size_t const n) +{ + size_t i; + for (i = 0; i < n; ++i) + dest[i] = src[i]; +} + +#pragma STDC FENV_ACCESS OFF +#undef _ +#else + +void lsx_save_samples(sox_sample_t * const dest, double const * const src, + size_t const n, sox_uint64_t * const clips) +{ + SOX_SAMPLE_LOCALS; + size_t i; + for (i = 0; i < n; ++i) + dest[i] = SOX_FLOAT_64BIT_TO_SAMPLE(src[i], *clips); +} + +void lsx_load_samples(double * const dest, sox_sample_t const * const src, + size_t const n) +{ + size_t i; + for (i = 0; i < n; ++i) + dest[i] = SOX_SAMPLE_TO_FLOAT_64BIT(src[i],); +} + +#endif diff --git a/app/src/main/cpp/sox/example0.c b/app/src/main/cpp/sox/example0.c new file mode 100644 index 0000000..a7bc48c --- /dev/null +++ b/app/src/main/cpp/sox/example0.c @@ -0,0 +1,97 @@ +/* Simple example of using SoX libraries + * + * Copyright (c) 2007-8 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox.h" +#include +#include +#include + +/* + * Reads input file, applies vol & flanger effects, stores in output file. + * E.g. example1 monkey.au monkey.aiff + */ +int main(int argc, char * argv[]) +{ + static sox_format_t * in, * out; /* input and output files */ + sox_effects_chain_t * chain; + sox_effect_t * e; + char * args[10]; + + assert(argc == 3); + + /* All libSoX applications must start by initialising the SoX library */ + assert(sox_init() == SOX_SUCCESS); + + /* Open the input file (with default parameters) */ + assert((in = sox_open_read(argv[1], NULL, NULL, NULL))); + + /* Open the output file; we must specify the output signal characteristics. + * Since we are using only simple effects, they are the same as the input + * file characteristics */ + assert((out = sox_open_write(argv[2], &in->signal, NULL, NULL, NULL, NULL))); + + /* Create an effects chain; some effects need to know about the input + * or output file encoding so we provide that information here */ + chain = sox_create_effects_chain(&in->encoding, &out->encoding); + + /* The first effect in the effect chain must be something that can source + * samples; in this case, we use the built-in handler that inputs + * data from an audio file */ + e = sox_create_effect(sox_find_effect("input")); + args[0] = (char *)in, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + /* This becomes the first `effect' in the chain */ + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* Create the `vol' effect, and initialise it with the desired parameters: */ + e = sox_create_effect(sox_find_effect("vol")); + args[0] = "3dB", assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + /* Add the effect to the end of the effects processing chain: */ + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* Create the `flanger' effect, and initialise it with default parameters: */ + e = sox_create_effect(sox_find_effect("flanger")); + assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); + /* Add the effect to the end of the effects processing chain: */ + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* The last effect in the effect chain must be something that only consumes + * samples; in this case, we use the built-in handler that outputs + * data to an audio file */ + e = sox_create_effect(sox_find_effect("output")); + args[0] = (char *)out, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* Flow samples through the effects processing chain until EOF is reached */ + sox_flow_effects(chain, NULL, NULL); + + /* All done; tidy up: */ + sox_delete_effects_chain(chain); + sox_close(out); + sox_close(in); + sox_quit(); + return 0; +} diff --git a/app/src/main/cpp/sox/example1.c b/app/src/main/cpp/sox/example1.c new file mode 100644 index 0000000..26118f8 --- /dev/null +++ b/app/src/main/cpp/sox/example1.c @@ -0,0 +1,167 @@ +/* Simple example of using SoX libraries + * + * Copyright (c) 2007-8 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox.h" +#include +#include +#include + +static sox_format_t * in, * out; /* input and output files */ + +/* The function that will be called to input samples into the effects chain. + * In this example, we get samples to process from a SoX-openned audio file. + * In a different application, they might be generated or come from a different + * part of the application. */ +static int input_drain( + sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + (void)effp; /* This parameter is not needed in this example */ + + /* ensure that *osamp is a multiple of the number of channels. */ + *osamp -= *osamp % effp->out_signal.channels; + + /* Read up to *osamp samples into obuf; store the actual number read + * back to *osamp */ + *osamp = sox_read(in, obuf, *osamp); + + /* sox_read may return a number that is less than was requested; only if + * 0 samples is returned does it indicate that end-of-file has been reached + * or an error has occurred */ + if (!*osamp && in->sox_errno) + fprintf(stderr, "%s: %s\n", in->filename, in->sox_errstr); + return *osamp? SOX_SUCCESS : SOX_EOF; +} + +/* The function that will be called to output samples from the effects chain. + * In this example, we store the samples in a SoX-opened audio file. + * In a different application, they might perhaps be analysed in some way, + * or displayed as a wave-form */ +static int output_flow(sox_effect_t *effp LSX_UNUSED, sox_sample_t const * ibuf, + sox_sample_t * obuf LSX_UNUSED, size_t * isamp, size_t * osamp) +{ + /* Write out *isamp samples */ + size_t len = sox_write(out, ibuf, *isamp); + + /* len is the number of samples that were actually written out; if this is + * different to *isamp, then something has gone wrong--most often, it's + * out of disc space */ + if (len != *isamp) { + fprintf(stderr, "%s: %s\n", out->filename, out->sox_errstr); + return SOX_EOF; + } + + /* Outputting is the last `effect' in the effect chain so always passes + * 0 samples on to the next effect (as there isn't one!) */ + *osamp = 0; + + (void)effp; /* This parameter is not needed in this example */ + + return SOX_SUCCESS; /* All samples output successfully */ +} + +/* A `stub' effect handler to handle inputting samples to the effects + * chain; the only function needed for this example is `drain' */ +static sox_effect_handler_t const * input_handler(void) +{ + static sox_effect_handler_t handler = { + "input", NULL, SOX_EFF_MCHAN, NULL, NULL, NULL, input_drain, NULL, NULL, 0 + }; + return &handler; +} + +/* A `stub' effect handler to handle outputting samples from the effects + * chain; the only function needed for this example is `flow' */ +static sox_effect_handler_t const * output_handler(void) +{ + static sox_effect_handler_t handler = { + "output", NULL, SOX_EFF_MCHAN, NULL, NULL, output_flow, NULL, NULL, NULL, 0 + }; + return &handler; +} + +/* + * Reads input file, applies vol & flanger effects, stores in output file. + * E.g. example1 monkey.au monkey.aiff + */ +int main(int argc, char * argv[]) +{ + sox_effects_chain_t * chain; + sox_effect_t * e; + char * vol[] = {"3dB"}; + + assert(argc == 3); + + /* All libSoX applications must start by initialising the SoX library */ + assert(sox_init() == SOX_SUCCESS); + + /* Open the input file (with default parameters) */ + assert((in = sox_open_read(argv[1], NULL, NULL, NULL))); + + /* Open the output file; we must specify the output signal characteristics. + * Since we are using only simple effects, they are the same as the input + * file characteristics */ + assert((out = sox_open_write(argv[2], &in->signal, NULL, NULL, NULL, NULL))); + + /* Create an effects chain; some effects need to know about the input + * or output file encoding so we provide that information here */ + chain = sox_create_effects_chain(&in->encoding, &out->encoding); + + /* The first effect in the effect chain must be something that can source + * samples; in this case, we have defined an input handler that inputs + * data from an audio file */ + e = sox_create_effect(input_handler()); + /* This becomes the first `effect' in the chain */ + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* Create the `vol' effect, and initialise it with the desired parameters: */ + e = sox_create_effect(sox_find_effect("vol")); + assert(sox_effect_options(e, 1, vol) == SOX_SUCCESS); + /* Add the effect to the end of the effects processing chain: */ + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* Create the `flanger' effect, and initialise it with default parameters: */ + e = sox_create_effect(sox_find_effect("flanger")); + assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); + /* Add the effect to the end of the effects processing chain: */ + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* The last effect in the effect chain must be something that only consumes + * samples; in this case, we have defined an output handler that outputs + * data to an audio file */ + e = sox_create_effect(output_handler()); + assert(sox_add_effect(chain, e, &in->signal, &in->signal) == SOX_SUCCESS); + free(e); + + /* Flow samples through the effects processing chain until EOF is reached */ + sox_flow_effects(chain, NULL, NULL); + + /* All done; tidy up: */ + sox_delete_effects_chain(chain); + sox_close(out); + sox_close(in); + sox_quit(); + return 0; +} diff --git a/app/src/main/cpp/sox/example2.c b/app/src/main/cpp/sox/example2.c new file mode 100644 index 0000000..20d4ba0 --- /dev/null +++ b/app/src/main/cpp/sox/example2.c @@ -0,0 +1,118 @@ +/* Simple example of using SoX libraries + * + * Copyright (c) 2008 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox.h" +#include "util.h" +#include +#include +#include + +/* + * Reads input file and displays a few seconds of wave-form, starting from + * a given time through the audio. E.g. example2 song2.au 30.75 1 + */ +int main(int argc, char * argv[]) +{ + sox_format_t * in; + sox_sample_t * buf; + size_t blocks, block_size; + /* Period of audio over which we will measure its volume in order to + * display the wave-form: */ + static const double block_period = 0.025; /* seconds */ + double start_secs = 0, period = 2; + char dummy; + uint64_t seek; + + /* All libSoX applications must start by initialising the SoX library */ + assert(sox_init() == SOX_SUCCESS); + + assert(argc > 1); + ++argv, --argc; /* Move to 1st parameter */ + + /* Open the input file (with default parameters) */ + assert((in = sox_open_read(*argv, NULL, NULL, NULL))); + ++argv, --argc; /* Move past this parameter */ + + if (argc) { /* If given, read the start time: */ + assert(sscanf(*argv, "%lf%c", &start_secs, &dummy) == 1); + ++argv, --argc; /* Move past this parameter */ + } + + if (argc) { /* If given, read the period of time to display: */ + assert(sscanf(*argv, "%lf%c", &period, &dummy) == 1); + ++argv, --argc; /* Move past this parameter */ + } + + /* Calculate the start position in number of samples: */ + seek = start_secs * in->signal.rate * in->signal.channels + .5; + /* Make sure that this is at a `wide sample' boundary: */ + seek -= seek % in->signal.channels; + /* Move the file pointer to the desired starting position */ + assert(sox_seek(in, seek, SOX_SEEK_SET) == SOX_SUCCESS); + + /* Convert block size (in seconds) to a number of samples: */ + block_size = block_period * in->signal.rate * in->signal.channels + .5; + /* Make sure that this is at a `wide sample' boundary: */ + block_size -= block_size % in->signal.channels; + /* Allocate a block of memory to store the block of audio samples: */ + assert((buf = malloc(sizeof(sox_sample_t) * block_size))); + + /* This example program requires that the audio has precisely 2 channels: */ + assert(in->signal.channels == 2); + + /* Read and process blocks of audio for the selected period or until EOF: */ + for (blocks = 0; sox_read(in, buf, block_size) == block_size && blocks * block_period < period; ++blocks) { + double left = 0, right = 0; + size_t i; + static const char line[] = "==================================="; + int l, r; + + for (i = 0; i < block_size; ++i) { + SOX_SAMPLE_LOCALS; + /* convert the sample from SoX's internal format to a `double' for + * processing in this application: */ + double sample = SOX_SAMPLE_TO_FLOAT_64BIT(buf[i],); + + /* The samples for each channel are interleaved; in this example + * we allow only stereo audio, so the left channel audio can be found in + * even-numbered samples, and the right channel audio in odd-numbered + * samples: */ + if (i & 1) + right = max(right, fabs(sample)); /* Find the peak volume in the block */ + else + left = max(left, fabs(sample)); /* Find the peak volume in the block */ + } + + /* Build up the wave form by displaying the left & right channel + * volume as a line length: */ + l = (1 - left) * 35 + .5; + r = (1 - right) * 35 + .5; + printf("%8.3f%36s|%s\n", start_secs + blocks * block_period, line + l, line + r); + } + + /* All done; tidy up: */ + free(buf); + sox_close(in); + sox_quit(); + return 0; +} diff --git a/app/src/main/cpp/sox/example3.c b/app/src/main/cpp/sox/example3.c new file mode 100644 index 0000000..e49d126 --- /dev/null +++ b/app/src/main/cpp/sox/example3.c @@ -0,0 +1,113 @@ +/* Simple example of using SoX libraries + * + * Copyright (c) 2007-9 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox.h" +#include "util.h" +#include +#include + +/* + * Example of a custom output message handler. + */ +static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap) +{ + char const * const str[] = {"FAIL", "WARN", "INFO", "DBUG"}; + if (sox_globals.verbosity >= level) { + char base_name[128]; + sox_basename(base_name, sizeof(base_name), filename); + fprintf(stderr, "%s %s: ", str[min(level - 1, 3)], base_name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } +} + +/* + * On an alsa capable system, plays an audio file starting 10 seconds in. + * Copes with sample-rate and channel change if necessary since its + * common for audio drivers to support a subset of rates and channel + * counts. + * E.g. example3 song2.ogg + * + * Can easily be changed to work with other audio device drivers supported + * by libSoX; e.g. "oss", "ao", "coreaudio", etc. + * See the soxformat(7) manual page. + */ +int main(int argc, char * argv[]) +{ + static sox_format_t * in, * out; /* input and output files */ + sox_effects_chain_t * chain; + sox_effect_t * e; + sox_signalinfo_t interm_signal; + char * args[10]; + + assert(argc == 2); + sox_globals.output_message_handler = output_message; + sox_globals.verbosity = 1; + + assert(sox_init() == SOX_SUCCESS); + assert((in = sox_open_read(argv[1], NULL, NULL, NULL))); + /* Change "alsa" in this line to use an alternative audio device driver: */ + assert((out= sox_open_write("default", &in->signal, NULL, "alsa", NULL, NULL))); + + chain = sox_create_effects_chain(&in->encoding, &out->encoding); + + interm_signal = in->signal; /* NB: deep copy */ + + e = sox_create_effect(sox_find_effect("input")); + args[0] = (char *)in, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS); + free(e); + + e = sox_create_effect(sox_find_effect("trim")); + args[0] = "10", assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS); + free(e); + + if (in->signal.rate != out->signal.rate) { + e = sox_create_effect(sox_find_effect("rate")); + assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS); + free(e); + } + + if (in->signal.channels != out->signal.channels) { + e = sox_create_effect(sox_find_effect("channels")); + assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS); + free(e); + } + + e = sox_create_effect(sox_find_effect("output")); + args[0] = (char *)out, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS); + free(e); + + sox_flow_effects(chain, NULL, NULL); + + sox_delete_effects_chain(chain); + sox_close(out); + sox_close(in); + sox_quit(); + + return 0; +} diff --git a/app/src/main/cpp/sox/example4.c b/app/src/main/cpp/sox/example4.c new file mode 100644 index 0000000..1141831 --- /dev/null +++ b/app/src/main/cpp/sox/example4.c @@ -0,0 +1,98 @@ +/* Simple example of using SoX libraries + * + * Copyright (c) 2009 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "sox.h" +#include + +/* Concatenate audio files. Note that the files must have the same number + * of channels and the same sample rate. + * + * Usage: example4 input-1 input-2 [... input-n] output + */ + +#define check(x) do if (!(x)) { \ + fprintf(stderr, "check failed: %s\n", #x); goto error; } while (0) + +int main(int argc, char * argv[]) +{ + sox_format_t * output = NULL; + int i; + + check(argc >= 1 + 2 + 1); /* Need at least 2 input files + 1 output file. */ + check(sox_init() == SOX_SUCCESS); + + /* Defer openning the output file as we want to set its characteristics + * based on those of the input files. */ + + for (i = 1; i < argc - 1; ++i) { /* For each input file... */ + sox_format_t * input; + static sox_signalinfo_t signal; /* static quashes `uninitialised' warning.*/ + + /* The (maximum) number of samples that we shall read/write at a time; + * chosen as a rough match to typical operating system I/O buffer size: */ + #define MAX_SAMPLES (size_t)2048 + sox_sample_t samples[MAX_SAMPLES]; /* Temporary store whilst copying. */ + size_t number_read; + + /* Open this input file: */ + check(input = sox_open_read(argv[i], NULL, NULL, NULL)); + + if (i == 1) { /* If this is the first input file... */ + + /* Open the output file using the same signal and encoding character- + * istics as the first input file. Note that here, input->signal.length + * will not be equal to the output file length so we are relying on + * libSoX to set the output length correctly (i.e. non-seekable output + * is not catered for); an alternative would be to first calculate the + * output length by summing the lengths of the input files and modifying + * the second parameter to sox_open_write accordingly. */ + check(output = sox_open_write(argv[argc - 1], + &input->signal, &input->encoding, NULL, NULL, NULL)); + + /* Also, we'll store the signal characteristics of the first file + * so that we can check that these match those of the other inputs: */ + signal = input->signal; + } + else { /* Second or subsequent input file... */ + + /* Check that this input file's signal matches that of the first file: */ + check(input->signal.channels == signal.channels); + check(input->signal.rate == signal.rate); + } + + /* Copy all of the audio from this input file to the output file: */ + while ((number_read = sox_read(input, samples, MAX_SAMPLES))) + check(sox_write(output, samples, number_read) == number_read); + + check(sox_close(input) == SOX_SUCCESS); /* Finished with this input file.*/ + } + + check(sox_close(output) == SOX_SUCCESS); /* Finished with the output file. */ + output = NULL; + check(sox_quit() == SOX_SUCCESS); + return 0; + +error: /* Truncate output file on error: */ + if (output) { + FILE * f; + sox_close(output); + if ((f = fopen(argv[argc - 1], "w"))) fclose(f); + } + return 1; +} diff --git a/app/src/main/cpp/sox/example5.c b/app/src/main/cpp/sox/example5.c new file mode 100644 index 0000000..db1fbf6 --- /dev/null +++ b/app/src/main/cpp/sox/example5.c @@ -0,0 +1,83 @@ +/* Simple example of using SoX libraries + * + * Copyright (c) 2009 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox.h" +#include "util.h" +#include +#include + +/* Example of reading and writing audio files stored in memory buffers + * rather than actual files. + * + * Usage: example5 input output + */ + +/* Uncomment following line for fixed instead of malloc'd buffer: */ +/*#define FIXED_BUFFER */ + +#if defined FIXED_BUFFER +#define buffer_size 123456 +static char buffer[buffer_size]; +#endif + +int main(int argc, char * argv[]) +{ + static sox_format_t * in, * out; /* input and output files */ + #define MAX_SAMPLES (size_t)2048 + sox_sample_t samples[MAX_SAMPLES]; /* Temporary store whilst copying. */ +#if !defined FIXED_BUFFER + char * buffer; + size_t buffer_size; +#endif + size_t number_read; + + assert(argc == 3); + + /* All libSoX applications must start by initialising the SoX library */ + assert(sox_init() == SOX_SUCCESS); + + /* Open the input file (with default parameters) */ + assert((in = sox_open_read(argv[1], NULL, NULL, NULL))); +#if defined FIXED_BUFFER + assert((out = sox_open_mem_write(buffer, buffer_size, &in->signal, NULL, "sox", NULL))); +#else + assert((out = sox_open_memstream_write(&buffer, &buffer_size, &in->signal, NULL, "sox", NULL))); +#endif + while ((number_read = sox_read(in, samples, MAX_SAMPLES))) + assert(sox_write(out, samples, number_read) == number_read); + sox_close(out); + sox_close(in); + + assert((in = sox_open_mem_read(buffer, buffer_size, NULL, NULL, NULL))); + assert((out = sox_open_write(argv[2], &in->signal, NULL, NULL, NULL, NULL))); + while ((number_read = sox_read(in, samples, MAX_SAMPLES))) + assert(sox_write(out, samples, number_read) == number_read); + sox_close(out); + sox_close(in); +#if !defined FIXED_BUFFER + free(buffer); +#endif + + sox_quit(); + return 0; +} diff --git a/app/src/main/cpp/sox/example6.c b/app/src/main/cpp/sox/example6.c new file mode 100644 index 0000000..2506c43 --- /dev/null +++ b/app/src/main/cpp/sox/example6.c @@ -0,0 +1,128 @@ +/* Simple example of using SoX libraries + * + * Copyright (c) 2007-14 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef NDEBUG /* N.B. assert used with active statements so enable always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox.h" +#include "util.h" +#include +#include + +/* + * Shows how to explicitly specify output file signal and encoding attributes. + * + * The example converts a given input file of any type to mono mu-law at 8kHz + * sampling-rate (providing that this is supported by the given output file + * type). + * + * For example: + * + * sox -r 16k -n input.wav synth 8 sin 0:8k sin 8k:0 gain -1 + * ./example6 input.wav output.wav + * soxi input.wav output.wav + * + * gives: + * + * Input File : 'input.wav' + * Channels : 2 + * Sample Rate : 16000 + * Precision : 32-bit + * Duration : 00:00:08.00 = 128000 samples ~ 600 CDDA sectors + * File Size : 1.02M + * Bit Rate : 1.02M + * Sample Encoding: 32-bit Signed Integer PCM + * + * Input File : 'output.wav' + * Channels : 1 + * Sample Rate : 8000 + * Precision : 14-bit + * Duration : 00:00:08.00 = 64000 samples ~ 600 CDDA sectors + * File Size : 64.1k + * Bit Rate : 64.1k + * Sample Encoding: 8-bit u-law + */ + +int main(int argc, char * argv[]) +{ + static sox_format_t * in, * out; /* input and output files */ + sox_effects_chain_t * chain; + sox_effect_t * e; + char * args[10]; + sox_signalinfo_t interm_signal; /* @ intermediate points in the chain. */ + sox_encodinginfo_t out_encoding = { + SOX_ENCODING_ULAW, + 8, + 0, + sox_option_default, + sox_option_default, + sox_option_default, + sox_false + }; + sox_signalinfo_t out_signal = { + 8000, + 1, + 0, + 0, + NULL + }; + + assert(argc == 3); + assert(sox_init() == SOX_SUCCESS); + assert((in = sox_open_read(argv[1], NULL, NULL, NULL))); + assert((out = sox_open_write(argv[2], &out_signal, &out_encoding, NULL, NULL, NULL))); + + chain = sox_create_effects_chain(&in->encoding, &out->encoding); + + interm_signal = in->signal; /* NB: deep copy */ + + e = sox_create_effect(sox_find_effect("input")); + args[0] = (char *)in, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &in->signal) == SOX_SUCCESS); + free(e); + + if (in->signal.rate != out->signal.rate) { + e = sox_create_effect(sox_find_effect("rate")); + assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS); + free(e); + } + + if (in->signal.channels != out->signal.channels) { + e = sox_create_effect(sox_find_effect("channels")); + assert(sox_effect_options(e, 0, NULL) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS); + free(e); + } + + e = sox_create_effect(sox_find_effect("output")); + args[0] = (char *)out, assert(sox_effect_options(e, 1, args) == SOX_SUCCESS); + assert(sox_add_effect(chain, e, &interm_signal, &out->signal) == SOX_SUCCESS); + free(e); + + sox_flow_effects(chain, NULL, NULL); + + sox_delete_effects_chain(chain); + sox_close(out); + sox_close(in); + sox_quit(); + + return 0; +} diff --git a/app/src/main/cpp/sox/f4-fmt.c b/app/src/main/cpp/sox/f4-fmt.c new file mode 100644 index 0000000..8dde5d3 --- /dev/null +++ b/app/src/main/cpp/sox/f4-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT1(f4, "f32", 32, 0, FLOAT) diff --git a/app/src/main/cpp/sox/f8-fmt.c b/app/src/main/cpp/sox/f8-fmt.c new file mode 100644 index 0000000..86cdd4a --- /dev/null +++ b/app/src/main/cpp/sox/f8-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT1(f8, "f64", 64, 0, FLOAT) diff --git a/app/src/main/cpp/sox/fade.c b/app/src/main/cpp/sox/fade.c new file mode 100644 index 0000000..3cf4876 --- /dev/null +++ b/app/src/main/cpp/sox/fade.c @@ -0,0 +1,399 @@ +/* Ari Moisio Aug 29 2000, based on skeleton effect + * Written by Chris Bagwell (cbagwell@sprynet.com) - March 16, 1999 + * + * Copyright 1999 Chris Bagwell And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Chris Bagwell And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" + +/* Fade curves */ +#define FADE_QUARTER 'q' /* Quarter of sine wave, 0 to pi/2 */ +#define FADE_HALF 'h' /* Half of sine wave, pi/2 to 1.5 * pi + * scaled so that -1 means no output + * and 1 means 0 db attenuation. */ +#define FADE_LOG 'l' /* Logarithmic curve. Fades -100 db + * in given time. */ +#define FADE_TRI 't' /* Linear slope. */ +#define FADE_PAR 'p' /* Inverted parabola. */ + +#include + +/* Private data for fade file */ +typedef struct { /* These are measured as samples */ + uint64_t in_start, in_stop, out_start, out_stop, samplesdone; + char *in_stop_str, *out_start_str, *out_stop_str; + char in_fadetype, out_fadetype; + char do_out; + int endpadwarned; +} priv_t; + +/* prototypes */ +static double fade_gain(uint64_t index, uint64_t range, int fadetype); + +/* + * Process options + * + * Don't do initialization now. + * The 'info' fields are not yet filled in. + */ + +static int sox_fade_getopts(sox_effect_t * effp, int argc, char **argv) +{ + + priv_t * fade = (priv_t *) effp->priv; + char t_char[2]; + int t_argno; + uint64_t samples; + const char *n; + --argc, ++argv; + + if (argc < 1 || argc > 4) + return lsx_usage(effp); + + /* because sample rate is unavailable at this point we store the + * string off for later computations. + */ + + if (sscanf(argv[0], "%1[qhltp]", t_char)) + { + fade->in_fadetype = *t_char; + fade->out_fadetype = *t_char; + + argv++; + argc--; + } + else + { + /* No type given. */ + fade->in_fadetype = 'l'; + fade->out_fadetype = 'l'; + } + + fade->in_stop_str = lsx_strdup(argv[0]); + /* Do a dummy parse to see if it will fail */ + n = lsx_parsesamples(0., fade->in_stop_str, &samples, 't'); + if (!n || *n) + return lsx_usage(effp); + + fade->in_stop = samples; + fade->out_start_str = fade->out_stop_str = 0; + + for (t_argno = 1; t_argno < argc && t_argno < 3; t_argno++) + { + /* See if there is fade-in/fade-out times/curves specified. */ + if(t_argno == 1) + { + fade->out_stop_str = lsx_strdup(argv[t_argno]); + + /* Do a dummy parse to see if it will fail */ + n = lsx_parseposition(0., fade->out_stop_str, NULL, (uint64_t)0, (uint64_t)0, '='); + if (!n || *n) + return lsx_usage(effp); + fade->out_stop = samples; + } + else + { + fade->out_start_str = lsx_strdup(argv[t_argno]); + + /* Do a dummy parse to see if it will fail */ + n = lsx_parsesamples(0., fade->out_start_str, &samples, 't'); + if (!n || *n) + return lsx_usage(effp); + fade->out_start = samples; + } + } /* End for(t_argno) */ + + return(SOX_SUCCESS); +} + +/* + * Prepare processing. + * Do all initializations. + */ +static int sox_fade_start(sox_effect_t * effp) +{ + priv_t * fade = (priv_t *) effp->priv; + sox_bool truncate = sox_false; + uint64_t samples; + uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN; + + /* converting time values to samples */ + fade->in_start = 0; + if (lsx_parsesamples(effp->in_signal.rate, fade->in_stop_str, + &samples, 't') == NULL) + return lsx_usage(effp); + + fade->in_stop = samples; + fade->do_out = 0; + /* See if user specified a stop time */ + if (fade->out_stop_str) + { + fade->do_out = 1; + if (!lsx_parseposition(effp->in_signal.rate, fade->out_stop_str, + &samples, (uint64_t)0, in_length, '=') || + samples == SOX_UNKNOWN_LEN) { + lsx_fail("audio length is unknown"); + return SOX_EOF; + } + fade->out_stop = samples; + + if (!(truncate = !!fade->out_stop)) { + fade->out_stop = effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : + 0; + if (!fade->out_stop) { + lsx_fail("cannot fade out: audio length is neither known nor given"); + return SOX_EOF; + } + } + + /* See if user wants to fade out. */ + if (fade->out_start_str) + { + if (lsx_parsesamples(effp->in_signal.rate, fade->out_start_str, + &samples, 't') == NULL) + return lsx_usage(effp); + /* Fade time is relative to stop time. */ + fade->out_start = fade->out_stop - samples; + } + else + /* If user doesn't specify fade out length then + * use same length as input side. This is stored + * in in_stop. + */ + fade->out_start = fade->out_stop - fade->in_stop; + } + else + /* If not specified then user wants to process all + * of file. Use a value of zero to indicate this. + */ + fade->out_stop = 0; + + if (fade->out_start) { /* Sanity check */ + if (fade->in_stop > fade->out_start) + --fade->in_stop; /* 1 sample grace for rounding error. */ + if (fade->in_stop > fade->out_start) { + lsx_fail("fade-out overlaps fade-in"); + return SOX_EOF; + } + } + + fade->samplesdone = fade->in_start; + fade->endpadwarned = 0; + + lsx_debug("in_start = %" PRIu64 " in_stop = %" PRIu64 " " + "out_start = %" PRIu64 " out_stop = %" PRIu64, + fade->in_start, fade->in_stop, fade->out_start, fade->out_stop); + + if (fade->in_start == fade->in_stop && !truncate && + fade->out_start == fade->out_stop) + return SOX_EFF_NULL; + + effp->out_signal.length = truncate ? + fade->out_stop * effp->in_signal.channels : effp->in_signal.length; + + return SOX_SUCCESS; +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +static int sox_fade_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * fade = (priv_t *) effp->priv; + /* len is total samples, chcnt counts channels */ + int len = 0, t_output = 1, more_output = 1; + sox_sample_t t_ibuf; + size_t chcnt = 0; + + len = ((*isamp > *osamp) ? *osamp : *isamp); + + *osamp = 0; + *isamp = 0; + + for(; len && more_output; len--) + { + t_ibuf = *ibuf; + + if ((fade->samplesdone >= fade->in_start) && + (!fade->do_out || fade->samplesdone < fade->out_stop)) + { /* something to generate output */ + + if (fade->samplesdone < fade->in_stop) + { /* fade-in phase, increase gain */ + *obuf = t_ibuf * + fade_gain(fade->samplesdone - fade->in_start, + fade->in_stop - fade->in_start, + fade->in_fadetype); + } /* endif fade-in */ + else if (!fade->do_out || fade->samplesdone < fade->out_start) + { /* steady gain phase */ + *obuf = t_ibuf; + } /* endif steady phase */ + else + { /* fade-out phase, decrease gain */ + *obuf = t_ibuf * + fade_gain(fade->out_stop - fade->samplesdone, + fade->out_stop - fade->out_start, + fade->out_fadetype); + } /* endif fade-out */ + + if (!(!fade->do_out || fade->samplesdone < fade->out_stop)) + more_output = 0; + + t_output = 1; + } + else + { /* No output generated */ + t_output = 0; + } /* endif something to output */ + + *isamp += 1; + ibuf++; + + if (t_output) + { /* Output generated, update pointers and counters */ + obuf++; + *osamp += 1; + } /* endif t_output */ + + /* Process next channel */ + chcnt++; + if (chcnt >= effp->in_signal.channels) + { /* all channels of this sample processed */ + chcnt = 0; + fade->samplesdone += 1; + } /* endif all channels */ + } /* endfor */ + + /* If not more samples will be returned, let application know + * this. + */ + if (fade->do_out && fade->samplesdone >= fade->out_stop) + return SOX_EOF; + else + return SOX_SUCCESS; +} + +/* + * Drain out remaining samples if the effect generates any. + */ +static int sox_fade_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * fade = (priv_t *) effp->priv; + int len; + size_t t_chan = 0; + + len = *osamp; + len -= len % effp->in_signal.channels; + *osamp = 0; + + if (fade->do_out && fade->samplesdone < fade->out_stop && + !(fade->endpadwarned)) + { /* Warning about padding silence into end of sample */ + lsx_warn("End time past end of audio. Padding with silence"); + fade->endpadwarned = 1; + } /* endif endpadwarned */ + + for (;len && (fade->do_out && + fade->samplesdone < fade->out_stop); len--) + { + *obuf = 0; + obuf++; + *osamp += 1; + + t_chan++; + if (t_chan >= effp->in_signal.channels) + { + fade->samplesdone += 1; + t_chan = 0; + } /* endif channels */ + } /* endfor */ + + if (fade->do_out && fade->samplesdone >= fade->out_stop) + return SOX_EOF; + else + return SOX_SUCCESS; +} + +/* + * Do anything required when you stop reading samples. + * (free allocated memory, etc.) + */ +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * fade = (priv_t *) effp->priv; + + free(fade->in_stop_str); + free(fade->out_start_str); + free(fade->out_stop_str); + return (SOX_SUCCESS); +} + +/* Function returns gain value 0.0 - 1.0 according index / range ratio +* and -1.0 if type is invalid +* todo: to optimize performance calculate gain every now and then and interpolate */ +static double fade_gain(uint64_t index, uint64_t range, int type) +{ + double retval = 0.0, findex = 0.0; + + /* TODO: does it really have to be contrained to [0.0, 1.0]? */ + findex = max(0.0, min(1.0, 1.0 * index / range)); + + switch (type) { + case FADE_TRI : /* triangle */ + retval = findex; + break; + + case FADE_QUARTER : /* quarter of sinewave */ + retval = sin(findex * M_PI / 2); + break; + + case FADE_HALF : /* half of sinewave... eh cosine wave */ + retval = (1 - cos(findex * M_PI )) / 2 ; + break; + + case FADE_LOG : /* logarithmic */ + /* 5 means 100 db attenuation. */ + /* TODO: should this be adopted with bit depth */ + retval = pow(0.1, (1 - findex) * 5); + break; + + case FADE_PAR : /* inverted parabola */ + retval = (1 - (1 - findex) * (1 - findex)); + break; + + /* TODO: more fade curves? */ + default : /* Error indicating wrong fade curve */ + retval = -1.0; + break; + } + + return retval; +} + +static sox_effect_handler_t sox_fade_effect = { + "fade", + "[ type ] fade-in-length [ stop-position [ fade-out-length ] ]\n" + " Time is in hh:mm:ss.frac format.\n" + " Fade type one of q, h, t, l or p.", + SOX_EFF_MCHAN | SOX_EFF_LENGTH, + sox_fade_getopts, + sox_fade_start, + sox_fade_flow, + sox_fade_drain, + NULL, + lsx_kill, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_fade_effect_fn(void) +{ + return &sox_fade_effect; +} diff --git a/app/src/main/cpp/sox/fap.c b/app/src/main/cpp/sox/fap.c new file mode 100644 index 0000000..4c9b946 --- /dev/null +++ b/app/src/main/cpp/sox/fap.c @@ -0,0 +1,31 @@ +/* libSoX file format: FAP Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(fap) +{ + static char const * const names[] = {"fap", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 24, 16, 8,0,0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = + "Ensoniq PARIS digital audio editing system (little endian)"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/fft4g.c b/app/src/main/cpp/sox/fft4g.c new file mode 100644 index 0000000..88a2a7e --- /dev/null +++ b/app/src/main/cpp/sox/fft4g.c @@ -0,0 +1,1362 @@ +/* Copyright Takuya OOURA, 1996-2001. + +You may use, copy, modify and distribute this code for any +purpose (include commercial use) and without fee. Please +refer to this package when you modify this code. + +Package home: http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html + +Fast Fourier/Cosine/Sine Transform + dimension :one + data length :power of 2 + decimation :frequency + radix :4, 2 + data :inplace + table :use +functions + cdft: Complex Discrete Fourier Transform + rdft: Real Discrete Fourier Transform + ddct: Discrete Cosine Transform + ddst: Discrete Sine Transform + dfct: Cosine Transform of RDFT (Real Symmetric DFT) + dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) +function prototypes + void cdft(int, int, double *, int *, double *); + void rdft(int, int, double *, int *, double *); + void ddct(int, int, double *, int *, double *); + void ddst(int, int, double *, int *, double *); + void dfct(int, double *, double *, int *, double *); + void dfst(int, double *, double *, int *, double *); + + +-------- Complex DFT (Discrete Fourier Transform) -------- + [definition] + + X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k + X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k + ip[0] = 0; // first time only + cdft(2*n, 1, a, ip, w); + + ip[0] = 0; // first time only + cdft(2*n, -1, a, ip, w); + [parameters] + 2*n :data length (int) + n >= 1, n = power of 2 + a[0...2*n-1] :input/output data (double *) + input data + a[2*j] = Re(x[j]), + a[2*j+1] = Im(x[j]), 0<=j= 2+sqrt(n) + strictly, + length of ip >= + 2+(1<<(int)(log(n+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + cdft(2*n, -1, a, ip, w); + is + cdft(2*n, 1, a, ip, w); + for (j = 0; j <= 2 * n - 1; j++) { + a[j] *= 1.0 / n; + } + . + + +-------- Real DFT / Inverse of Real DFT -------- + [definition] + RDFT + R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 + I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0 IRDFT (excluding scale) + a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + + sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + + sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k + ip[0] = 0; // first time only + rdft(n, 1, a, ip, w); + + ip[0] = 0; // first time only + rdft(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + + output data + a[2*k] = R[k], 0<=k + input data + a[2*j] = R[j], 0<=j= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + rdft(n, 1, a, ip, w); + is + rdft(n, -1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + IDCT (excluding scale) + C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k DCT + C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k + ip[0] = 0; // first time only + ddct(n, 1, a, ip, w); + + ip[0] = 0; // first time only + ddct(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + output data + a[k] = C[k], 0<=k= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddct(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddct(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DST (Discrete Sine Transform) / Inverse of DST -------- + [definition] + IDST (excluding scale) + S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k DST + S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0 + ip[0] = 0; // first time only + ddst(n, 1, a, ip, w); + + ip[0] = 0; // first time only + ddst(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + + input data + a[j] = A[j], 0 + output data + a[k] = S[k], 0= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddst(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddst(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Cosine Transform of RDFT (Real Symmetric DFT) -------- + [definition] + C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n + [usage] + ip[0] = 0; // first time only + dfct(n, a, t, ip, w); + [parameters] + n :data length - 1 (int) + n >= 2, n = power of 2 + a[0...n] :input/output data (double *) + output data + a[k] = C[k], 0<=k<=n + t[0...n/2] :work area (double *) + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + is + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + for (j = 0; j <= n; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Sine Transform of RDFT (Real Anti-symmetric DFT) -------- + [definition] + S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0= 2, n = power of 2 + a[0...n-1] :input/output data (double *) + output data + a[k] = S[k], 0= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (double *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + dfst(n, a, t, ip, w); + is + dfst(n, a, t, ip, w); + for (j = 1; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +Appendix : + The cos/sin table is recalculated when the larger table required. + w[] and ip[] are compatible with all routines. +*/ + + +#include +#include "fft4g.h" + +#ifdef FFT4G_FLOAT + #define double float + #define sin sinf + #define cos cosf + #define atan atanf + + #define cdft lsx_cdft_f + #define rdft lsx_rdft_f + #define ddct lsx_ddct_f + #define ddst lsx_ddst_f + #define dfct lsx_dfct_f + #define dfst lsx_dfst_f +#else + #define cdft lsx_cdft + #define rdft lsx_rdft + #define ddct lsx_ddct + #define ddst lsx_ddst + #define dfct lsx_dfct + #define dfst lsx_dfst +#endif + +static void bitrv2conj(int n, int *ip, double *a); +static void bitrv2(int n, int *ip, double *a); +static void cft1st(int n, double *a, double const *w); +static void cftbsub(int n, double *a, double const *w); +static void cftfsub(int n, double *a, double const *w); +static void cftmdl(int n, int l, double *a, double const *w); +static void dctsub(int n, double *a, int nc, double const *c); +static void dstsub(int n, double *a, int nc, double const *c); +static void makect(int nc, int *ip, double *c); +static void makewt(int nw, int *ip, double *w); +static void rftbsub(int n, double *a, int nc, double const *c); +static void rftfsub(int n, double *a, int nc, double const *c); + + +void cdft(int n, int isgn, double *a, int *ip, double *w) +{ + if (n > FFT4G_MAX_SIZE) + return; + + if (n > (ip[0] << 2)) { + makewt(n >> 2, ip, w); + } + if (n > 4) { + if (isgn >= 0) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + } else { + bitrv2conj(n, ip + 2, a); + cftbsub(n, a, w); + } + } else if (n == 4) { + cftfsub(n, a, w); + } +} + + +void rdft(int n, int isgn, double *a, int *ip, double *w) +{ + int nw, nc; + double xi; + + if (n > FFT4G_MAX_SIZE) + return; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 2)) { + nc = n >> 2; + makect(nc, ip, w + nw); + } + if (isgn >= 0) { + if (n > 4) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, w); + } + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } else { + a[1] = 0.5 * (a[0] - a[1]); + a[0] -= a[1]; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } else if (n == 4) { + cftfsub(n, a, w); + } + } +} + + +void ddct(int n, int isgn, double *a, int *ip, double *w) +{ + int j, nw, nc; + double xr; + + if (n > FFT4G_MAX_SIZE) + return; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + if (isgn < 0) { + xr = a[n - 1]; + for (j = n - 2; j >= 2; j -= 2) { + a[j + 1] = a[j] - a[j - 1]; + a[j] += a[j - 1]; + } + a[1] = a[0] - xr; + a[0] += xr; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } else if (n == 4) { + cftfsub(n, a, w); + } + } + dctsub(n, a, nc, w + nw); + if (isgn >= 0) { + if (n > 4) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, w); + } + xr = a[0] - a[1]; + a[0] += a[1]; + for (j = 2; j < n; j += 2) { + a[j - 1] = a[j] - a[j + 1]; + a[j] += a[j + 1]; + } + a[n - 1] = xr; + } +} + + +void ddst(int n, int isgn, double *a, int *ip, double *w) +{ + int j, nw, nc; + double xr; + + if (n > FFT4G_MAX_SIZE) + return; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > nc) { + nc = n; + makect(nc, ip, w + nw); + } + if (isgn < 0) { + xr = a[n - 1]; + for (j = n - 2; j >= 2; j -= 2) { + a[j + 1] = -a[j] - a[j - 1]; + a[j] -= a[j - 1]; + } + a[1] = a[0] + xr; + a[0] -= xr; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } else if (n == 4) { + cftfsub(n, a, w); + } + } + dstsub(n, a, nc, w + nw); + if (isgn >= 0) { + if (n > 4) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, w); + } + xr = a[0] - a[1]; + a[0] += a[1]; + for (j = 2; j < n; j += 2) { + a[j - 1] = -a[j] - a[j + 1]; + a[j] -= a[j + 1]; + } + a[n - 1] = -xr; + } +} + + +void dfct(int n, double *a, double *t, int *ip, double *w) +{ + int j, k, l, m, mh, nw, nc; + double xr, xi, yr, yi; + + if (n > FFT4G_MAX_SIZE) + return; + + nw = ip[0]; + if (n > (nw << 3)) { + nw = n >> 3; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 1)) { + nc = n >> 1; + makect(nc, ip, w + nw); + } + m = n >> 1; + yi = a[m]; + xi = a[0] + a[n]; + a[0] -= a[n]; + t[0] = xi - yi; + t[m] = xi + yi; + if (n > 2) { + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + xr = a[j] - a[n - j]; + xi = a[j] + a[n - j]; + yr = a[k] - a[n - k]; + yi = a[k] + a[n - k]; + a[j] = xr; + a[k] = yr; + t[j] = xi - yi; + t[k] = xi + yi; + } + t[mh] = a[mh] + a[n - mh]; + a[mh] -= a[n - mh]; + dctsub(m, a, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, a); + cftfsub(m, a, w); + rftfsub(m, a, nc, w + nw); + } else if (m == 4) { + cftfsub(m, a, w); + } + a[n - 1] = a[0] - a[1]; + a[1] = a[0] + a[1]; + for (j = m - 2; j >= 2; j -= 2) { + a[2 * j + 1] = a[j] + a[j + 1]; + a[2 * j - 1] = a[j] - a[j + 1]; + } + l = 2; + m = mh; + while (m >= 2) { + dctsub(m, t, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, t); + cftfsub(m, t, w); + rftfsub(m, t, nc, w + nw); + } else if (m == 4) { + cftfsub(m, t, w); + } + a[n - l] = t[0] - t[1]; + a[l] = t[0] + t[1]; + k = 0; + for (j = 2; j < m; j += 2) { + k += l << 2; + a[k - l] = t[j] - t[j + 1]; + a[k + l] = t[j] + t[j + 1]; + } + l <<= 1; + mh = m >> 1; + for (j = 0; j < mh; j++) { + k = m - j; + t[j] = t[m + k] - t[m + j]; + t[k] = t[m + k] + t[m + j]; + } + t[mh] = t[m + mh]; + m = mh; + } + a[l] = t[0]; + a[n] = t[2] - t[1]; + a[0] = t[2] + t[1]; + } else { + a[1] = a[0]; + a[2] = t[0]; + a[0] = t[1]; + } +} + + +void dfst(int n, double *a, double *t, int *ip, double *w) +{ + int j, k, l, m, mh, nw, nc; + double xr, xi, yr, yi; + + if (n > FFT4G_MAX_SIZE) + return; + + nw = ip[0]; + if (n > (nw << 3)) { + nw = n >> 3; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 1)) { + nc = n >> 1; + makect(nc, ip, w + nw); + } + if (n > 2) { + m = n >> 1; + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + xr = a[j] + a[n - j]; + xi = a[j] - a[n - j]; + yr = a[k] + a[n - k]; + yi = a[k] - a[n - k]; + a[j] = xr; + a[k] = yr; + t[j] = xi + yi; + t[k] = xi - yi; + } + t[0] = a[mh] - a[n - mh]; + a[mh] += a[n - mh]; + a[0] = a[m]; + dstsub(m, a, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, a); + cftfsub(m, a, w); + rftfsub(m, a, nc, w + nw); + } else if (m == 4) { + cftfsub(m, a, w); + } + a[n - 1] = a[1] - a[0]; + a[1] = a[0] + a[1]; + for (j = m - 2; j >= 2; j -= 2) { + a[2 * j + 1] = a[j] - a[j + 1]; + a[2 * j - 1] = -a[j] - a[j + 1]; + } + l = 2; + m = mh; + while (m >= 2) { + dstsub(m, t, nc, w + nw); + if (m > 4) { + bitrv2(m, ip + 2, t); + cftfsub(m, t, w); + rftfsub(m, t, nc, w + nw); + } else if (m == 4) { + cftfsub(m, t, w); + } + a[n - l] = t[1] - t[0]; + a[l] = t[0] + t[1]; + k = 0; + for (j = 2; j < m; j += 2) { + k += l << 2; + a[k - l] = -t[j] - t[j + 1]; + a[k + l] = t[j] - t[j + 1]; + } + l <<= 1; + mh = m >> 1; + for (j = 1; j < mh; j++) { + k = m - j; + t[j] = t[m + k] + t[m + j]; + t[k] = t[m + k] - t[m + j]; + } + t[0] = t[m + mh]; + m = mh; + } + a[l] = t[0]; + } + a[0] = 0; +} + + +/* -------- initializing routines -------- */ + + +static void makewt(int nw, int *ip, double *w) +{ + int j, nwh; + double delta, x, y; + + ip[0] = nw; + ip[1] = 1; + if (nw > 2) { + nwh = nw >> 1; + delta = atan(1.0) / nwh; + w[0] = 1; + w[1] = 0; + w[nwh] = cos(delta * nwh); + w[nwh + 1] = w[nwh]; + if (nwh > 2) { + for (j = 2; j < nwh; j += 2) { + x = cos(delta * j); + y = sin(delta * j); + w[j] = x; + w[j + 1] = y; + w[nw - j] = y; + w[nw - j + 1] = x; + } + bitrv2(nw, ip + 2, w); + } + } +} + + +static void makect(int nc, int *ip, double *c) +{ + int j, nch; + double delta; + + ip[1] = nc; + if (nc > 1) { + nch = nc >> 1; + delta = atan(1.0) / nch; + c[0] = cos(delta * nch); + c[nch] = 0.5 * c[0]; + for (j = 1; j < nch; j++) { + c[j] = 0.5 * cos(delta * j); + c[nc - j] = 0.5 * sin(delta * j); + } + } +} + + +/* -------- child routines -------- */ + + +static void bitrv2(int n, int *ip0, double *a) +{ + int j, j1, k, k1, l, m, m2, ip[256]; + double xr, xi, yr, yi; + + (void)ip0; + ip[0] = 0; + l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + m2 = 2 * m; + if ((m << 3) == l) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + j1 = 2 * k + m2 + ip[k]; + k1 = j1 + m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } else { + for (k = 1; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } + } +} + + +static void bitrv2conj(int n, int *ip0, double *a) +{ + int j, j1, k, k1, l, m, m2, ip[256]; + double xr, xi, yr, yi; + + (void)ip0; + ip[0] = 0; + l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + m2 = 2 * m; + if ((m << 3) == l) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 2 * k + ip[k]; + a[k1 + 1] = -a[k1 + 1]; + j1 = k1 + m2; + k1 = j1 + m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + k1 += m2; + a[k1 + 1] = -a[k1 + 1]; + } + } else { + a[1] = -a[1]; + a[m2 + 1] = -a[m2 + 1]; + for (k = 1; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = -a[j1 + 1]; + yr = a[k1]; + yi = -a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + k1 = 2 * k + ip[k]; + a[k1 + 1] = -a[k1 + 1]; + a[k1 + m2 + 1] = -a[k1 + m2 + 1]; + } + } +} + + +static void cftfsub(int n, double *a, double const *w) +{ + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = a[j + 1] - a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] += a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + + +static void cftbsub(int n, double *a, double const *w) +{ + int j, j1, j2, j3, l; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = -a[j + 1] + a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] = -a[j + 1] - a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + + +static void cft1st(int n, double *a, double const *w) +{ + int j, k1, k2; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wk1r = w[2]; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wk1r * (x0r - x0i); + a[11] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wk1r * (x0i - x0r); + a[15] = wk1r * (x0i + x0r); + k1 = 0; + for (j = 16; j < n; j += 16) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + x0r = a[j] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } +} + + +static void cftmdl(int n, int l, double *a, double const *w) +{ + int j, j1, j2, j3, k, k1, k2, m, m2; + double wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + m = l << 2; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wk1r = w[2]; + for (j = m; j < l + m; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * (x0r - x0i); + a[j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3] = wk1r * (x0i - x0r); + a[j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j < l + k; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + for (j = k + m; j < l + (k + m); j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } +} + + +static void rftfsub(int n, double *a, int nc, double const *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + } +} + + +static void rftbsub(int n, double *a, int nc, double const *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr, xi, yr, yi; + + a[1] = -a[1]; + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5 - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j] -= yr; + a[j + 1] = yi - a[j + 1]; + a[k] += yr; + a[k + 1] = yi - a[k + 1]; + } + a[m + 1] = -a[m + 1]; +} + + +static void dctsub(int n, double *a, int nc, double const *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr; + + m = n >> 1; + ks = nc / n; + kk = 0; + for (j = 1; j < m; j++) { + k = n - j; + kk += ks; + wkr = c[kk] - c[nc - kk]; + wki = c[kk] + c[nc - kk]; + xr = wki * a[j] - wkr * a[k]; + a[j] = wkr * a[j] + wki * a[k]; + a[k] = xr; + } + a[m] *= c[0]; +} + + +static void dstsub(int n, double *a, int nc, double const *c) +{ + int j, k, kk, ks, m; + double wkr, wki, xr; + + m = n >> 1; + ks = nc / n; + kk = 0; + for (j = 1; j < m; j++) { + k = n - j; + kk += ks; + wkr = c[kk] - c[nc - kk]; + wki = c[kk] + c[nc - kk]; + xr = wki * a[k] - wkr * a[j]; + a[k] = wkr * a[k] + wki * a[j]; + a[j] = xr; + } + a[m] *= c[0]; +} + diff --git a/app/src/main/cpp/sox/fft4g.h b/app/src/main/cpp/sox/fft4g.h new file mode 100644 index 0000000..95ee341 --- /dev/null +++ b/app/src/main/cpp/sox/fft4g.h @@ -0,0 +1,37 @@ +/* This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define FFT4G_MAX_SIZE 262144 + +void lsx_cdft(int, int, double *, int *, double *); +void lsx_rdft(int, int, double *, int *, double *); +void lsx_ddct(int, int, double *, int *, double *); +void lsx_ddst(int, int, double *, int *, double *); +void lsx_dfct(int, double *, double *, int *, double *); +void lsx_dfst(int, double *, double *, int *, double *); + +void lsx_cdft_f(int, int, float *, int *, float *); +void lsx_rdft_f(int, int, float *, int *, float *); +void lsx_ddct_f(int, int, float *, int *, float *); +void lsx_ddst_f(int, int, float *, int *, float *); +void lsx_dfct_f(int, float *, float *, int *, float *); +void lsx_dfst_f(int, float *, float *, int *, float *); + +#define dft_br_len(l) (2 + (1 << (int)(log(l / 2 + .5) / log(2.)) / 2)) +#define dft_sc_len(l) (l / 2) + +/* Over-allocate h by 2 to use these macros */ +#define LSX_PACK(h, n) h[1] = h[n] +#define LSX_UNPACK(h, n) h[n] = h[1], h[n + 1] = h[1] = 0; diff --git a/app/src/main/cpp/sox/fifo.h b/app/src/main/cpp/sox/fifo.h new file mode 100644 index 0000000..2e65afa --- /dev/null +++ b/app/src/main/cpp/sox/fifo.h @@ -0,0 +1,119 @@ +/* Addressable FIFO buffer Copyright (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef fifo_included +#define fifo_included + +#include + +#ifndef FIFO_SIZE_T +#define FIFO_SIZE_T size_t +#endif + +typedef struct { + char * data; + size_t allocation; /* Number of bytes allocated for data. */ + size_t item_size; /* Size of each item in data */ + size_t begin; /* Offset of the first byte to read. */ + size_t end; /* 1 + Offset of the last byte byte to read. */ +} fifo_t; + +#define FIFO_MIN 0x4000 + +UNUSED static void fifo_clear(fifo_t * f) +{ + f->end = f->begin = 0; +} + +UNUSED static void * fifo_reserve(fifo_t * f, FIFO_SIZE_T n) +{ + n *= f->item_size; + + if (f->begin == f->end) + fifo_clear(f); + + while (1) { + if (f->end + n <= f->allocation) { + void *p = f->data + f->end; + + f->end += n; + return p; + } + if (f->begin > FIFO_MIN) { + memmove(f->data, f->data + f->begin, f->end - f->begin); + f->end -= f->begin; + f->begin = 0; + continue; + } + f->allocation += n; + f->data = lsx_realloc(f->data, f->allocation); + } +} + +UNUSED static void * fifo_write(fifo_t * f, FIFO_SIZE_T n, void const * data) +{ + void * s = fifo_reserve(f, n); + if (data) + memcpy(s, data, n * f->item_size); + return s; +} + +UNUSED static void fifo_trim_to(fifo_t * f, FIFO_SIZE_T n) +{ + n *= f->item_size; + f->end = f->begin + n; +} + +UNUSED static void fifo_trim_by(fifo_t * f, FIFO_SIZE_T n) +{ + n *= f->item_size; + f->end -= n; +} + +UNUSED static FIFO_SIZE_T fifo_occupancy(fifo_t * f) +{ + return (f->end - f->begin) / f->item_size; +} + +UNUSED static void * fifo_read(fifo_t * f, FIFO_SIZE_T n, void * data) +{ + char * ret = f->data + f->begin; + n *= f->item_size; + if (n > (FIFO_SIZE_T)(f->end - f->begin)) + return NULL; + if (data) + memcpy(data, ret, (size_t)n); + f->begin += n; + return ret; +} + +#define fifo_read_ptr(f) fifo_read(f, (FIFO_SIZE_T)0, NULL) + +UNUSED static void fifo_delete(fifo_t * f) +{ + free(f->data); +} + +UNUSED static void fifo_create(fifo_t * f, FIFO_SIZE_T item_size) +{ + f->item_size = item_size; + f->allocation = FIFO_MIN; + f->data = lsx_malloc(f->allocation); + fifo_clear(f); +} + +#endif diff --git a/app/src/main/cpp/sox/fir.c b/app/src/main/cpp/sox/fir.c new file mode 100644 index 0000000..fd33458 --- /dev/null +++ b/app/src/main/cpp/sox/fir.c @@ -0,0 +1,105 @@ +/* Effect: fir filter from coefs Copyright (c) 2009 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "dft_filter.h" + +typedef struct { + dft_filter_priv_t base; + char const * filename; + double * h; + int n; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + dft_filter_priv_t * b = &p->base; + double d; + char c; + + b->filter_ptr = &b->filter; + --argc, ++argv; + if (!argc) + p->filename = "-"; /* default to stdin */ + else if (argc == 1) + p->filename = argv[0], --argc; + else for (; argc && sscanf(*argv, "%lf%c", &d, &c) == 1; --argc, ++argv) { + p->n++; + p->h = lsx_realloc(p->h, p->n * sizeof(*p->h)); + p->h[p->n - 1] = d; + } + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + dft_filter_t * f = p->base.filter_ptr; + double d; + char c; + int i; + + if (!f->num_taps) { + if (!p->n && p->filename) { + FILE * file = lsx_open_input_file(effp, p->filename, sox_true); + if (!file) + return SOX_EOF; + while ((i = fscanf(file, " #%*[^\n]%c", &c)) >= 0) { + if (i >= 1) continue; /* found and skipped a comment */ + if ((i = fscanf(file, "%lf", &d)) > 0) { + /* found a coefficient value */ + p->n++; + p->h = lsx_realloc(p->h, p->n * sizeof(*p->h)); + p->h[p->n - 1] = d; + } else break; /* either EOF, or something went wrong + (read or syntax error) */ + } + if (!feof(file)) { + lsx_fail("error reading coefficient file"); + if (file != stdin) fclose(file); + return SOX_EOF; + } + if (file != stdin) fclose(file); + } + lsx_report("%i coefficients", p->n); + if (!p->n) + return SOX_EFF_NULL; + if (effp->global_info->plot != sox_plot_off) { + char title[100]; + sprintf(title, "SoX effect: fir (%d coefficients)", p->n); + lsx_plot_fir(p->h, p->n, effp->in_signal.rate, + effp->global_info->plot, title, -30., 30.); + free(p->h); + return SOX_EOF; + } + lsx_set_dft_filter(f, p->h, p->n, p->n >> 1); + } + return lsx_dft_filter_effect_fn()->start(effp); +} + +sox_effect_handler_t const * lsx_fir_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_dft_filter_effect_fn(); + handler.name = "fir"; + handler.usage = "[coef-file|coefs]"; + handler.getopts = create; + handler.start = start; + handler.priv_size = sizeof(priv_t); + return &handler; +} diff --git a/app/src/main/cpp/sox/firfit.c b/app/src/main/cpp/sox/firfit.c new file mode 100644 index 0000000..4d6b8ab --- /dev/null +++ b/app/src/main/cpp/sox/firfit.c @@ -0,0 +1,145 @@ +/* Effect: firfit filter Copyright (c) 2009 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This is W.I.P. hence marked SOX_EFF_ALPHA for now. + * Need to add other interpolation types e.g. linear, bspline, window types, + * and filter length, maybe phase response type too. + */ + +#include "sox_i.h" +#include "dft_filter.h" + +typedef struct { + dft_filter_priv_t base; + char const * filename; + struct {double f, gain;} * knots; + int num_knots, n; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *)effp->priv; + dft_filter_priv_t * b = &p->base; + b->filter_ptr = &b->filter; + --argc, ++argv; + if (argc == 1) + p->filename = argv[0], --argc; + p->n = 2047; + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static double * make_filter(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + double * log_freqs, * gains, * d, * work, * h; + sox_rate_t rate = effp->in_signal.rate; + int i, work_len; + + lsx_valloc(log_freqs , p->num_knots); + lsx_valloc(gains, p->num_knots); + lsx_valloc(d , p->num_knots); + for (i = 0; i < p->num_knots; ++i) { + log_freqs[i] = log(max(p->knots[i].f, 1)); + gains[i] = p->knots[i].gain; + } + lsx_prepare_spline3(log_freqs, gains, p->num_knots, HUGE_VAL, HUGE_VAL, d); + + for (work_len = 8192; work_len < rate / 2; work_len <<= 1); + work = lsx_calloc(work_len + 2, sizeof(*work)); + lsx_valloc(h, p->n); + + for (i = 0; i <= work_len; i += 2) { + double f = rate * 0.5 * i / work_len; + double spl1 = f < max(p->knots[0].f, 1)? gains[0] : + f > p->knots[p->num_knots - 1].f? gains[p->num_knots - 1] : + lsx_spline3(log_freqs, gains, d, p->num_knots, log(f)); + work[i] = dB_to_linear(spl1); + } + LSX_PACK(work, work_len); + lsx_safe_rdft(work_len, -1, work); + for (i = 0; i < p->n; ++i) + h[i] = work[(work_len - p->n / 2 + i) % work_len] * 2. / work_len; + lsx_apply_blackman_nutall(h, p->n); + + free(work); + return h; +} + +static sox_bool read_knots(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + FILE * file = lsx_open_input_file(effp, p->filename, sox_true); + sox_bool result = sox_false; + int num_converted = 1; + char c; + + if (file) { + lsx_valloc(p->knots, 1); + while (fscanf(file, " #%*[^\n]%c", &c) >= 0) { + num_converted = fscanf(file, "%lf %lf", + &p->knots[p->num_knots].f, &p->knots[p->num_knots].gain); + if (num_converted == 2) { + if (p->num_knots && p->knots[p->num_knots].f <= p->knots[p->num_knots - 1].f) { + lsx_fail("knot frequencies must be strictly increasing"); + break; + } + lsx_revalloc(p->knots, ++p->num_knots + 1); + } else if (num_converted != 0) + break; + } + lsx_report("%i knots", p->num_knots); + if (feof(file) && num_converted != 1) + result = sox_true; + else lsx_fail("error reading knot file `%s', line number %u", p->filename, 1 + p->num_knots); + if (file != stdin) + fclose(file); + } + return result; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + dft_filter_t * f = p->base.filter_ptr; + + if (!f->num_taps) { + double * h; + if (!p->num_knots && !read_knots(effp)) + return SOX_EOF; + h = make_filter(effp); + if (effp->global_info->plot != sox_plot_off) { + lsx_plot_fir(h, p->n, effp->in_signal.rate, + effp->global_info->plot, "SoX effect: firfit", -30., +30.); + return SOX_EOF; + } + lsx_set_dft_filter(f, h, p->n, p->n >> 1); + } + return lsx_dft_filter_effect_fn()->start(effp); +} + +sox_effect_handler_t const * lsx_firfit_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_dft_filter_effect_fn(); + handler.name = "firfit"; + handler.usage = "[knots-file]"; + handler.flags |= SOX_EFF_ALPHA; + handler.getopts = create; + handler.start = start; + handler.priv_size = sizeof(priv_t); + return &handler; +} diff --git a/app/src/main/cpp/sox/flac.c b/app/src/main/cpp/sox/flac.c new file mode 100644 index 0000000..4abcc58 --- /dev/null +++ b/app/src/main/cpp/sox/flac.c @@ -0,0 +1,606 @@ +/* libSoX file format: FLAC (c) 2006-7 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include +/* Next line for systems that don't define off_t when you #include + stdio.h; apparently OS/2 has this bug */ +#include + +#include + +#define MAX_COMPRESSION 8 + + +typedef struct { + /* Info: */ + unsigned bits_per_sample; + unsigned channels; + unsigned sample_rate; + uint64_t total_samples; + + /* Decode buffer: */ + sox_sample_t *req_buffer; /* this may be on the stack */ + size_t number_of_requested_samples; + sox_sample_t *leftover_buf; /* heap */ + unsigned number_of_leftover_samples; + + FLAC__StreamDecoder * decoder; + FLAC__bool eof; + sox_bool seek_pending; + uint64_t seek_offset; + + /* Encode buffer: */ + FLAC__int32 * decoded_samples; + unsigned number_of_samples; + + FLAC__StreamEncoder * encoder; + FLAC__StreamMetadata * metadata[2]; + unsigned num_metadata; +} priv_t; + + +static FLAC__StreamDecoderReadStatus decoder_read_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__byte buffer[], size_t* bytes, void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + if(*bytes > 0) { + *bytes = lsx_readbuf(ft, buffer, *bytes); + if(lsx_error(ft)) + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; + else if(*bytes == 0) + return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + else + return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; + } + else + return FLAC__STREAM_DECODER_READ_STATUS_ABORT; +} + +static FLAC__StreamDecoderSeekStatus decoder_seek_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64 absolute_byte_offset, void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + if(lsx_seeki(ft, (off_t)absolute_byte_offset, SEEK_SET) < 0) + return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +static FLAC__StreamDecoderTellStatus decoder_tell_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64* absolute_byte_offset, void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + off_t pos; + if((pos = lsx_tell(ft)) < 0) + return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__STREAM_DECODER_TELL_STATUS_OK; + } +} + +static FLAC__StreamDecoderLengthStatus decoder_length_callback(FLAC__StreamDecoder const* decoder UNUSED, FLAC__uint64* stream_length, void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + *stream_length = lsx_filelength(ft); + return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; +} + +static FLAC__bool decoder_eof_callback(FLAC__StreamDecoder const* decoder UNUSED, void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + return lsx_eof(ft) ? 1 : 0; +} + +static void decoder_metadata_callback(FLAC__StreamDecoder const * const flac, FLAC__StreamMetadata const * const metadata, void * const client_data) +{ + sox_format_t * ft = (sox_format_t *) client_data; + priv_t * p = (priv_t *)ft->priv; + + (void) flac; + + if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) { + p->bits_per_sample = metadata->data.stream_info.bits_per_sample; + p->channels = metadata->data.stream_info.channels; + p->sample_rate = metadata->data.stream_info.sample_rate; + p->total_samples = metadata->data.stream_info.total_samples; + } + else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { + const FLAC__StreamMetadata_VorbisComment *vc = &metadata->data.vorbis_comment; + size_t i; + + if (vc->num_comments == 0) + return; + + if (ft->oob.comments != NULL) { + lsx_warn("multiple Vorbis comment block ignored"); + return; + } + + for (i = 0; i < vc->num_comments; ++i) + if (vc->comments[i].entry) + sox_append_comment(&ft->oob.comments, (char const *) vc->comments[i].entry); + } +} + + + +static void decoder_error_callback(FLAC__StreamDecoder const * const flac, FLAC__StreamDecoderErrorStatus const status, void * const client_data) +{ + sox_format_t * ft = (sox_format_t *) client_data; + + (void) flac; + + lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamDecoderErrorStatusString[status]); +} + + + +static FLAC__StreamDecoderWriteStatus decoder_write_callback(FLAC__StreamDecoder const * const flac, FLAC__Frame const * const frame, FLAC__int32 const * const buffer[], void * const client_data) +{ + sox_format_t * ft = (sox_format_t *) client_data; + priv_t * p = (priv_t *)ft->priv; + sox_sample_t * dst = p->req_buffer; + unsigned channel; + unsigned nsamples = frame->header.blocksize; + unsigned sample = 0; + size_t actual = nsamples * p->channels; + + (void) flac; + + if (frame->header.bits_per_sample != p->bits_per_sample || frame->header.channels != p->channels || frame->header.sample_rate != p->sample_rate) { + lsx_fail_errno(ft, SOX_EINVAL, "FLAC ERROR: parameters differ between frame and header"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + if (dst == NULL) { + lsx_warn("FLAC ERROR: entered write callback without a buffer (SoX bug)"); + return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; + } + + /* FLAC may give us too much data, prepare the leftover buffer */ + if (actual > p->number_of_requested_samples) { + size_t to_stash = actual - p->number_of_requested_samples; + + p->leftover_buf = lsx_malloc(to_stash * sizeof(sox_sample_t)); + p->number_of_leftover_samples = to_stash; + nsamples = p->number_of_requested_samples / p->channels; + + p->req_buffer += p->number_of_requested_samples; + p->number_of_requested_samples = 0; + } else { + p->req_buffer += actual; + p->number_of_requested_samples -= actual; + } + +leftover_copy: + + for (; sample < nsamples; sample++) { + for (channel = 0; channel < p->channels; channel++) { + FLAC__int32 d = buffer[channel][sample]; + switch (p->bits_per_sample) { + case 8: *dst++ = SOX_SIGNED_8BIT_TO_SAMPLE(d,); break; + case 16: *dst++ = SOX_SIGNED_16BIT_TO_SAMPLE(d,); break; + case 24: *dst++ = SOX_SIGNED_24BIT_TO_SAMPLE(d,); break; + case 32: *dst++ = SOX_SIGNED_32BIT_TO_SAMPLE(d,); break; + } + } + } + + /* copy into the leftover buffer if we've prepared it */ + if (sample < frame->header.blocksize) { + nsamples = frame->header.blocksize; + dst = p->leftover_buf; + goto leftover_copy; + } + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + + + +static int start_read(sox_format_t * const ft) +{ + priv_t * p = (priv_t *)ft->priv; + lsx_debug("API version %u", FLAC_API_VERSION_CURRENT); + p->decoder = FLAC__stream_decoder_new(); + if (p->decoder == NULL) { + lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the decoder instance"); + return SOX_EOF; + } + + FLAC__stream_decoder_set_md5_checking(p->decoder, sox_true); + FLAC__stream_decoder_set_metadata_respond_all(p->decoder); + if (FLAC__stream_decoder_init_stream( + p->decoder, + decoder_read_callback, + ft->seekable ? decoder_seek_callback : NULL, + ft->seekable ? decoder_tell_callback : NULL, + ft->seekable ? decoder_length_callback : NULL, + ft->seekable ? decoder_eof_callback : NULL, + decoder_write_callback, + decoder_metadata_callback, + decoder_error_callback, + ft) != FLAC__STREAM_DECODER_INIT_STATUS_OK){ + lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR initialising decoder"); + return SOX_EOF; + } + + if (!FLAC__stream_decoder_process_until_end_of_metadata(p->decoder)) { + lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR whilst decoding metadata"); + return SOX_EOF; + } + + if (FLAC__stream_decoder_get_state(p->decoder) > FLAC__STREAM_DECODER_END_OF_STREAM) { + lsx_fail_errno(ft, SOX_EHDR, "FLAC ERROR during metadata decoding"); + return SOX_EOF; + } + + ft->encoding.encoding = SOX_ENCODING_FLAC; + ft->signal.rate = p->sample_rate; + ft->encoding.bits_per_sample = p->bits_per_sample; + ft->signal.channels = p->channels; + ft->signal.length = p->total_samples * p->channels; + return SOX_SUCCESS; +} + + +static size_t read_samples(sox_format_t * const ft, sox_sample_t * sampleBuffer, size_t const requested) +{ + priv_t * p = (priv_t *)ft->priv; + size_t prev_requested; + + if (p->seek_pending) { + p->seek_pending = sox_false; + + /* discard leftover decoded data */ + free(p->leftover_buf); + p->leftover_buf = NULL; + p->number_of_leftover_samples = 0; + + p->req_buffer = sampleBuffer; + p->number_of_requested_samples = requested; + + /* calls decoder_write_callback */ + if (!FLAC__stream_decoder_seek_absolute(p->decoder, (FLAC__uint64)(p->seek_offset / ft->signal.channels))) { + p->req_buffer = NULL; + return 0; + } + } else if (p->number_of_leftover_samples > 0) { + + /* small request, no need to decode more samples since we have leftovers */ + if (requested < p->number_of_leftover_samples) { + size_t req_bytes = requested * sizeof(sox_sample_t); + + memcpy(sampleBuffer, p->leftover_buf, req_bytes); + p->number_of_leftover_samples -= requested; + memmove(p->leftover_buf, (char *)p->leftover_buf + req_bytes, + (size_t)p->number_of_leftover_samples * sizeof(sox_sample_t)); + return requested; + } + + /* first, give them all of our leftover data: */ + memcpy(sampleBuffer, p->leftover_buf, + p->number_of_leftover_samples * sizeof(sox_sample_t)); + + p->req_buffer = sampleBuffer + p->number_of_leftover_samples; + p->number_of_requested_samples = requested - p->number_of_leftover_samples; + + free(p->leftover_buf); + p->leftover_buf = NULL; + p->number_of_leftover_samples = 0; + + /* continue invoking decoder below */ + } else { + p->req_buffer = sampleBuffer; + p->number_of_requested_samples = requested; + } + + /* invoke the decoder, calls decoder_write_callback */ + while ((prev_requested = p->number_of_requested_samples) && !p->eof) { + if (!FLAC__stream_decoder_process_single(p->decoder)) + break; /* error, but maybe got earlier in the loop, though */ + + /* number_of_requested_samples decrements as the decoder progresses */ + if (p->number_of_requested_samples == prev_requested) + p->eof = sox_true; + } + p->req_buffer = NULL; + + return requested - p->number_of_requested_samples; +} + + + +static int stop_read(sox_format_t * const ft) +{ + priv_t * p = (priv_t *)ft->priv; + if (!FLAC__stream_decoder_finish(p->decoder) && p->eof) + lsx_warn("decoder MD5 checksum mismatch."); + FLAC__stream_decoder_delete(p->decoder); + + free(p->leftover_buf); + p->leftover_buf = NULL; + p->number_of_leftover_samples = 0; + return SOX_SUCCESS; +} + + + +static FLAC__StreamEncoderWriteStatus flac_stream_encoder_write_callback(FLAC__StreamEncoder const * const flac, const FLAC__byte buffer[], size_t const bytes, unsigned const samples, unsigned const current_frame, void * const client_data) +{ + sox_format_t * const ft = (sox_format_t *) client_data; + (void) flac, (void) samples, (void) current_frame; + + return lsx_writebuf(ft, buffer, bytes) == bytes ? FLAC__STREAM_ENCODER_WRITE_STATUS_OK : FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; +} + + + +static void flac_stream_encoder_metadata_callback(FLAC__StreamEncoder const * encoder, FLAC__StreamMetadata const * metadata, void * client_data) +{ + (void) encoder, (void) metadata, (void) client_data; +} + + + +static FLAC__StreamEncoderSeekStatus flac_stream_encoder_seek_callback(FLAC__StreamEncoder const * encoder, FLAC__uint64 absolute_byte_offset, void * client_data) +{ + sox_format_t * const ft = (sox_format_t *) client_data; + (void) encoder; + if (!ft->seekable) + return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; + else if (lsx_seeki(ft, (off_t)absolute_byte_offset, SEEK_SET) != SOX_SUCCESS) + return FLAC__STREAM_ENCODER_SEEK_STATUS_ERROR; + else + return FLAC__STREAM_ENCODER_SEEK_STATUS_OK; +} + + + +static FLAC__StreamEncoderTellStatus flac_stream_encoder_tell_callback(FLAC__StreamEncoder const * encoder, FLAC__uint64 * absolute_byte_offset, void * client_data) +{ + sox_format_t * const ft = (sox_format_t *) client_data; + off_t pos; + (void) encoder; + if (!ft->seekable) + return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; + else if ((pos = lsx_tell(ft)) < 0) + return FLAC__STREAM_ENCODER_TELL_STATUS_ERROR; + else { + *absolute_byte_offset = (FLAC__uint64)pos; + return FLAC__STREAM_ENCODER_TELL_STATUS_OK; + } +} + + + +static int start_write(sox_format_t * const ft) +{ + priv_t * p = (priv_t *)ft->priv; + FLAC__StreamEncoderInitStatus status; + unsigned compression_level = MAX_COMPRESSION; /* Default to "best" */ + + if (ft->encoding.compression != HUGE_VAL) { + compression_level = ft->encoding.compression; + if (compression_level != ft->encoding.compression || + compression_level > MAX_COMPRESSION) { + lsx_fail_errno(ft, SOX_EINVAL, + "FLAC compression level must be a whole number from 0 to %i", + MAX_COMPRESSION); + return SOX_EOF; + } + } + + p->encoder = FLAC__stream_encoder_new(); + if (p->encoder == NULL) { + lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder instance"); + return SOX_EOF; + } + + p->bits_per_sample = ft->encoding.bits_per_sample; + ft->signal.precision = ft->encoding.bits_per_sample; + + lsx_report("encoding at %i bits per sample", p->bits_per_sample); + + FLAC__stream_encoder_set_channels(p->encoder, ft->signal.channels); + FLAC__stream_encoder_set_bits_per_sample(p->encoder, p->bits_per_sample); + FLAC__stream_encoder_set_sample_rate(p->encoder, (unsigned)(ft->signal.rate + .5)); + + { /* Check if rate is streamable: */ + static const unsigned streamable_rates[] = + {8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; + size_t i; + sox_bool streamable = sox_false; + for (i = 0; !streamable && i < array_length(streamable_rates); ++i) + streamable = (streamable_rates[i] == ft->signal.rate); + if (!streamable) { + lsx_report("non-standard rate; output may not be streamable"); + FLAC__stream_encoder_set_streamable_subset(p->encoder, sox_false); + } + } + +#if FLAC_API_VERSION_CURRENT >= 10 + FLAC__stream_encoder_set_compression_level(p->encoder, compression_level); +#else + { + static struct { + unsigned blocksize; + FLAC__bool do_exhaustive_model_search; + FLAC__bool do_mid_side_stereo; + FLAC__bool loose_mid_side_stereo; + unsigned max_lpc_order; + unsigned max_residual_partition_order; + unsigned min_residual_partition_order; + } const options[MAX_COMPRESSION + 1] = { + {1152, sox_false, sox_false, sox_false, 0, 2, 2}, + {1152, sox_false, sox_true, sox_true, 0, 2, 2}, + {1152, sox_false, sox_true, sox_false, 0, 3, 0}, + {4608, sox_false, sox_false, sox_false, 6, 3, 3}, + {4608, sox_false, sox_true, sox_true, 8, 3, 3}, + {4608, sox_false, sox_true, sox_false, 8, 3, 3}, + {4608, sox_false, sox_true, sox_false, 8, 4, 0}, + {4608, sox_true, sox_true, sox_false, 8, 6, 0}, + {4608, sox_true, sox_true, sox_false, 12, 6, 0}, + }; +#define SET_OPTION(x) do {\ + lsx_report(#x" = %i", options[compression_level].x); \ + FLAC__stream_encoder_set_##x(p->encoder, options[compression_level].x);\ +} while (0) + SET_OPTION(blocksize); + SET_OPTION(do_exhaustive_model_search); + SET_OPTION(max_lpc_order); + SET_OPTION(max_residual_partition_order); + SET_OPTION(min_residual_partition_order); + if (ft->signal.channels == 2) { + SET_OPTION(do_mid_side_stereo); + SET_OPTION(loose_mid_side_stereo); + } +#undef SET_OPTION + } +#endif + + if (ft->signal.length != 0) { + FLAC__stream_encoder_set_total_samples_estimate(p->encoder, (FLAC__uint64)(ft->signal.length / ft->signal.channels)); + + p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE); + if (p->metadata[p->num_metadata] == NULL) { + lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table template"); + return SOX_EOF; + } + { + if (!FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(p->metadata[p->num_metadata], (unsigned)(10 * ft->signal.rate + .5), (FLAC__uint64)(ft->signal.length/ft->signal.channels))) { + lsx_fail_errno(ft, SOX_ENOMEM, "FLAC ERROR creating the encoder seek table points"); + return SOX_EOF; + } + } + p->metadata[p->num_metadata]->is_last = sox_false; /* the encoder will set this for us */ + ++p->num_metadata; + } + + if (ft->oob.comments) { /* Make the comment structure */ + FLAC__StreamMetadata_VorbisComment_Entry entry; + int i; + + p->metadata[p->num_metadata] = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT); + for (i = 0; ft->oob.comments[i]; ++i) { + static const char prepend[] = "Comment="; + char * text = lsx_calloc(strlen(prepend) + strlen(ft->oob.comments[i]) + 1, sizeof(*text)); + /* Prepend `Comment=' if no field-name already in the comment */ + if (!strchr(ft->oob.comments[i], '=')) + strcpy(text, prepend); + entry.entry = (FLAC__byte *) strcat(text, ft->oob.comments[i]); + entry.length = strlen(text); + FLAC__metadata_object_vorbiscomment_append_comment(p->metadata[p->num_metadata], entry, /*copy= */ sox_true); + free(text); + } + ++p->num_metadata; + } + + if (p->num_metadata) + FLAC__stream_encoder_set_metadata(p->encoder, p->metadata, p->num_metadata); + + status = FLAC__stream_encoder_init_stream(p->encoder, flac_stream_encoder_write_callback, + flac_stream_encoder_seek_callback, flac_stream_encoder_tell_callback, flac_stream_encoder_metadata_callback, ft); + + if (status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) { + lsx_fail_errno(ft, SOX_EINVAL, "%s", FLAC__StreamEncoderInitStatusString[status]); + return SOX_EOF; + } + return SOX_SUCCESS; +} + + + +static size_t write_samples(sox_format_t * const ft, sox_sample_t const * const sampleBuffer, size_t const len) +{ + priv_t * p = (priv_t *)ft->priv; + unsigned i; + + /* allocate or grow buffer */ + if (p->number_of_samples < len) { + p->number_of_samples = len; + free(p->decoded_samples); + p->decoded_samples = lsx_malloc(p->number_of_samples * sizeof(FLAC__int32)); + } + + for (i = 0; i < len; ++i) { + SOX_SAMPLE_LOCALS; + long pcm = SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i], ft->clips); + p->decoded_samples[i] = pcm >> (32 - p->bits_per_sample); + switch (p->bits_per_sample) { + case 8: p->decoded_samples[i] = + SOX_SAMPLE_TO_SIGNED_8BIT(sampleBuffer[i], ft->clips); + break; + case 16: p->decoded_samples[i] = + SOX_SAMPLE_TO_SIGNED_16BIT(sampleBuffer[i], ft->clips); + break; + case 24: p->decoded_samples[i] = /* sign extension: */ + SOX_SAMPLE_TO_SIGNED_24BIT(sampleBuffer[i],ft->clips) << 8; + p->decoded_samples[i] >>= 8; + break; + case 32: p->decoded_samples[i] = + SOX_SAMPLE_TO_SIGNED_32BIT(sampleBuffer[i],ft->clips); + break; + } + } + FLAC__stream_encoder_process_interleaved(p->encoder, p->decoded_samples, (unsigned) len / ft->signal.channels); + return FLAC__stream_encoder_get_state(p->encoder) == FLAC__STREAM_ENCODER_OK ? len : 0; +} + + + +static int stop_write(sox_format_t * const ft) +{ + priv_t * p = (priv_t *)ft->priv; + FLAC__StreamEncoderState state = FLAC__stream_encoder_get_state(p->encoder); + unsigned i; + + FLAC__stream_encoder_finish(p->encoder); + FLAC__stream_encoder_delete(p->encoder); + for (i = 0; i < p->num_metadata; ++i) + FLAC__metadata_object_delete(p->metadata[i]); + free(p->decoded_samples); + if (state != FLAC__STREAM_ENCODER_OK) { + lsx_fail_errno(ft, SOX_EINVAL, "FLAC ERROR: failed to encode to end of stream"); + return SOX_EOF; + } + return SOX_SUCCESS; +} + + + +static int seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * p = (priv_t *)ft->priv; + p->seek_offset = offset; + p->seek_pending = sox_true; + return ft->mode == 'r' ? SOX_SUCCESS : SOX_EOF; +} + + + +LSX_FORMAT_HANDLER(flac) +{ + static char const * const names[] = {"flac", NULL}; + static unsigned const encodings[] = {SOX_ENCODING_FLAC, 8, 16, 24, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Free Lossless Audio CODEC compressed audio", names, 0, + start_read, read_samples, stop_read, + start_write, write_samples, stop_write, + seek, encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/flanger.c b/app/src/main/cpp/sox/flanger.c new file mode 100644 index 0000000..d75f1e6 --- /dev/null +++ b/app/src/main/cpp/sox/flanger.c @@ -0,0 +1,275 @@ +/* libSoX effect: Stereo Flanger (c) 2006 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* TODO: Slide in the delay at the start? */ + +#include "sox_i.h" +#include + +typedef enum {INTERP_LINEAR, INTERP_QUADRATIC} interp_t; + +#define MAX_CHANNELS 4 + +typedef struct { + /* Parameters */ + double delay_min; + double delay_depth; + double feedback_gain; + double delay_gain; + double speed; + lsx_wave_t wave_shape; + double channel_phase; + interp_t interpolation; + + /* Delay buffers */ + double * delay_bufs[MAX_CHANNELS]; + size_t delay_buf_length; + size_t delay_buf_pos; + double delay_last[MAX_CHANNELS]; + + /* Low Frequency Oscillator */ + float * lfo; + size_t lfo_length; + size_t lfo_pos; + + /* Balancing */ + double in_gain; +} priv_t; + + + +static lsx_enum_item const interp_enum[] = { + LSX_ENUM_ITEM(INTERP_,LINEAR) + LSX_ENUM_ITEM(INTERP_,QUADRATIC) + {0, 0}}; + + + +static int getopts(sox_effect_t * effp, int argc, char *argv[]) +{ + priv_t * p = (priv_t *) effp->priv; + --argc, ++argv; + + /* Set non-zero defaults: */ + p->delay_depth = 2; + p->delay_gain = 71; + p->speed = 0.5; + p->channel_phase= 25; + + do { /* break-able block */ + NUMERIC_PARAMETER(delay_min , 0 , 30 ) + NUMERIC_PARAMETER(delay_depth , 0 , 10 ) + NUMERIC_PARAMETER(feedback_gain,-95 , 95 ) + NUMERIC_PARAMETER(delay_gain , 0 , 100) + NUMERIC_PARAMETER(speed , 0.1, 10 ) + TEXTUAL_PARAMETER(wave_shape, lsx_get_wave_enum()) + NUMERIC_PARAMETER(channel_phase, 0 , 100) + TEXTUAL_PARAMETER(interpolation, interp_enum) + } while (0); + + if (argc != 0) + return lsx_usage(effp); + + lsx_report("parameters:\n" + "delay = %gms\n" + "depth = %gms\n" + "regen = %g%%\n" + "width = %g%%\n" + "speed = %gHz\n" + "shape = %s\n" + "phase = %g%%\n" + "interp= %s", + p->delay_min, + p->delay_depth, + p->feedback_gain, + p->delay_gain, + p->speed, + lsx_get_wave_enum()[p->wave_shape].text, + p->channel_phase, + interp_enum[p->interpolation].text); + + /* Scale to unity: */ + p->feedback_gain /= 100; + p->delay_gain /= 100; + p->channel_phase /= 100; + p->delay_min /= 1000; + p->delay_depth /= 1000; + + return SOX_SUCCESS; +} + + + +static int start(sox_effect_t * effp) +{ + priv_t * f = (priv_t *) effp->priv; + int c, channels = effp->in_signal.channels; + + if (channels > MAX_CHANNELS) { + lsx_fail("Can not operate with more than %i channels", MAX_CHANNELS); + return SOX_EOF; + } + + /* Balance output: */ + f->in_gain = 1 / (1 + f->delay_gain); + f->delay_gain /= 1 + f->delay_gain; + + /* Balance feedback loop: */ + f->delay_gain *= 1 - fabs(f->feedback_gain); + + lsx_debug("in_gain=%g feedback_gain=%g delay_gain=%g\n", + f->in_gain, f->feedback_gain, f->delay_gain); + + /* Create the delay buffers, one for each channel: */ + f->delay_buf_length = + (f->delay_min + f->delay_depth) * effp->in_signal.rate + 0.5; + ++f->delay_buf_length; /* Need 0 to n, i.e. n + 1. */ + ++f->delay_buf_length; /* Quadratic interpolator needs one more. */ + for (c = 0; c < channels; ++c) + f->delay_bufs[c] = lsx_calloc(f->delay_buf_length, sizeof(*f->delay_bufs[0])); + + /* Create the LFO lookup table: */ + f->lfo_length = effp->in_signal.rate / f->speed; + f->lfo = lsx_calloc(f->lfo_length, sizeof(*f->lfo)); + lsx_generate_wave_table( + f->wave_shape, + SOX_FLOAT, + f->lfo, + f->lfo_length, + floor(f->delay_min * effp->in_signal.rate + .5), + f->delay_buf_length - 2., + 3 * M_PI_2); /* Start the sweep at minimum delay (for mono at least) */ + + lsx_debug("delay_buf_length=%" PRIuPTR " lfo_length=%" PRIuPTR "\n", + f->delay_buf_length, f->lfo_length); + + return SOX_SUCCESS; +} + + + +static int flow(sox_effect_t * effp, sox_sample_t const * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * f = (priv_t *) effp->priv; + int c, channels = effp->in_signal.channels; + size_t len = (*isamp > *osamp ? *osamp : *isamp) / channels; + + *isamp = *osamp = len * channels; + + while (len--) { + f->delay_buf_pos = + (f->delay_buf_pos + f->delay_buf_length - 1) % f->delay_buf_length; + for (c = 0; c < channels; ++c) { + double delayed_0, delayed_1; + double delayed; + double in, out; + size_t channel_phase = c * f->lfo_length * f->channel_phase + .5; + double delay = f->lfo[(f->lfo_pos + channel_phase) % f->lfo_length]; + double frac_delay = modf(delay, &delay); + size_t int_delay = (size_t)delay; + + in = *ibuf++; + f->delay_bufs[c][f->delay_buf_pos] = in + f->delay_last[c] * f->feedback_gain; + + delayed_0 = f->delay_bufs[c] + [(f->delay_buf_pos + int_delay++) % f->delay_buf_length]; + delayed_1 = f->delay_bufs[c] + [(f->delay_buf_pos + int_delay++) % f->delay_buf_length]; + + if (f->interpolation == INTERP_LINEAR) + delayed = delayed_0 + (delayed_1 - delayed_0) * frac_delay; + else /* if (f->interpolation == INTERP_QUADRATIC) */ + { + double a, b; + double delayed_2 = f->delay_bufs[c] + [(f->delay_buf_pos + int_delay++) % f->delay_buf_length]; + delayed_2 -= delayed_0; + delayed_1 -= delayed_0; + a = delayed_2 *.5 - delayed_1; + b = delayed_1 * 2 - delayed_2 *.5; + delayed = delayed_0 + (a * frac_delay + b) * frac_delay; + } + + f->delay_last[c] = delayed; + out = in * f->in_gain + delayed * f->delay_gain; + *obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips); + } + f->lfo_pos = (f->lfo_pos + 1) % f->lfo_length; + } + + return SOX_SUCCESS; +} + + + +static int stop(sox_effect_t * effp) +{ + priv_t * f = (priv_t *) effp->priv; + int c, channels = effp->in_signal.channels; + + for (c = 0; c < channels; ++c) + free(f->delay_bufs[c]); + + free(f->lfo); + + memset(f, 0, sizeof(*f)); + + return SOX_SUCCESS; +} + + + +sox_effect_handler_t const * lsx_flanger_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "flanger", NULL, SOX_EFF_MCHAN, + getopts, start, flow, NULL, stop, NULL, sizeof(priv_t)}; + static char const * lines[] = { + "[delay depth regen width speed shape phase interp]", + " .", + " /|regen", + " / |", + " +--( |------------+", + " | \\ | | .", + " _V_ \\| _______ | |\\ width ___", + " | | ' | | | | \\ | |", + " +-->| + |---->| DELAY |--+-->| )----->| |", + " | |___| |_______| | / | |", + " | delay : depth |/ | |", + " In | : interp ' | | Out", + " --->+ __:__ | + |--->", + " | | |speed | |", + " | | ~ |shape | |", + " | |_____|phase | |", + " +------------------------------------->| |", + " |___|", + " RANGE DEFAULT DESCRIPTION", + "delay 0 30 0 base delay in milliseconds", + "depth 0 10 2 added swept delay in milliseconds", + "regen -95 +95 0 percentage regeneration (delayed signal feedback)", + "width 0 100 71 percentage of delayed signal mixed with original", + "speed 0.1 10 0.5 sweeps per second (Hz) ", + "shape -- sin swept wave shape: sine|triangle", + "phase 0 100 25 swept wave percentage phase-shift for multi-channel", + " (e.g. stereo) flange; 0 = 100 = same phase on each channel", + "interp -- lin delay-line interpolation: linear|quadratic" + }; + static char * usage; + handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); + return &handler; +} diff --git a/app/src/main/cpp/sox/formats.c b/app/src/main/cpp/sox/formats.c new file mode 100644 index 0000000..3fcf438 --- /dev/null +++ b/app/src/main/cpp/sox/formats.c @@ -0,0 +1,1351 @@ +/* Implements the public API for using libSoX file formats. + * All public functions & data are prefixed with sox_ . + * + * (c) 2005-8 Chris Bagwell and SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define _GNU_SOURCE +#include "sox_i.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_IO_H + #include +#endif + +#if HAVE_MAGIC + #include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#define PIPE_AUTO_DETECT_SIZE 256 /* Only as much as we can rewind a pipe */ +#define AUTO_DETECT_SIZE 4096 /* For seekable file, so no restriction */ + +static char const * auto_detect_format(sox_format_t * ft, char const * ext) +{ + char data[AUTO_DETECT_SIZE]; + size_t len = lsx_readbuf(ft, data, ft->seekable? sizeof(data) : PIPE_AUTO_DETECT_SIZE); + #define CHECK(type, p2, l2, d2, p1, l1, d1) if (len >= p1 + l1 && \ + !memcmp(data + p1, d1, (size_t)l1) && !memcmp(data + p2, d2, (size_t)l2)) return #type; + CHECK(voc , 0, 0, "" , 0, 20, "Creative Voice File\x1a") + CHECK(smp , 0, 0, "" , 0, 17, "SOUND SAMPLE DATA") + CHECK(wve , 0, 0, "" , 0, 15, "ALawSoundFile**") + CHECK(gsrt , 0, 0, "" , 16, 9, "ring.bin") + CHECK(amr-wb, 0, 0, "" , 0, 9, "#!AMR-WB\n") + CHECK(prc , 0, 0, "" , 0, 8, "\x37\x00\x00\x10\x6d\x00\x00\x10") + CHECK(sph , 0, 0, "" , 0, 7, "NIST_1A") + CHECK(amr-nb, 0, 0, "" , 0, 6, "#!AMR\n") + CHECK(txw , 0, 0, "" , 0, 6, "LM8953") + CHECK(sndt , 0, 0, "" , 0, 6, "SOUND\x1a") + CHECK(vorbis, 0, 4, "OggS" , 29, 6, "vorbis") + CHECK(opus , 0, 4, "OggS" , 28, 8, "OpusHead") + CHECK(speex , 0, 4, "OggS" , 28, 6, "Speex") + CHECK(hcom ,65, 4, "FSSD" , 128,4, "HCOM") + CHECK(wav , 0, 4, "RIFF" , 8, 4, "WAVE") + CHECK(wav , 0, 4, "RIFX" , 8, 4, "WAVE") + CHECK(wav , 0, 4, "RF64" , 8, 4, "WAVE") + CHECK(aiff , 0, 4, "FORM" , 8, 4, "AIFF") + CHECK(aifc , 0, 4, "FORM" , 8, 4, "AIFC") + CHECK(8svx , 0, 4, "FORM" , 8, 4, "8SVX") + CHECK(maud , 0, 4, "FORM" , 8, 4, "MAUD") + CHECK(xa , 0, 0, "" , 0, 4, "XA\0\0") + CHECK(xa , 0, 0, "" , 0, 4, "XAI\0") + CHECK(xa , 0, 0, "" , 0, 4, "XAJ\0") + CHECK(au , 0, 0, "" , 0, 4, ".snd") + CHECK(au , 0, 0, "" , 0, 4, "dns.") + CHECK(au , 0, 0, "" , 0, 4, "\0ds.") + CHECK(au , 0, 0, "" , 0, 4, ".sd\0") + CHECK(flac , 0, 0, "" , 0, 4, "fLaC") + CHECK(avr , 0, 0, "" , 0, 4, "2BIT") + CHECK(caf , 0, 0, "" , 0, 4, "caff") + CHECK(wv , 0, 0, "" , 0, 4, "wvpk") + CHECK(paf , 0, 0, "" , 0, 4, " paf") + CHECK(sf , 0, 0, "" , 0, 4, "\144\243\001\0") + CHECK(sf , 0, 0, "" , 0, 4, "\0\001\243\144") + CHECK(sf , 0, 0, "" , 0, 4, "\144\243\002\0") + CHECK(sf , 0, 0, "" , 0, 4, "\0\002\243\144") + CHECK(sf , 0, 0, "" , 0, 4, "\144\243\003\0") + CHECK(sf , 0, 0, "" , 0, 4, "\0\003\243\144") + CHECK(sf , 0, 0, "" , 0, 4, "\144\243\004\0") + CHECK(sox , 0, 0, "" , 0, 4, ".SoX") + CHECK(sox , 0, 0, "" , 0, 4, "XoS.") + + if (ext && !strcasecmp(ext, "snd")) + CHECK(sndr , 7, 1, "" , 0, 2, "\0") + #undef CHECK + +#if HAVE_MAGIC + if (sox_globals.use_magic) { + static magic_t magic; + char const * filetype = NULL; + if (!magic) { + magic = magic_open(MAGIC_MIME | MAGIC_SYMLINK); + if (magic) + magic_load(magic, NULL); + } + if (magic) + filetype = magic_buffer(magic, data, len); + if (filetype && strncmp(filetype, "application/octet-stream", (size_t)24) && + !lsx_strends(filetype, "/unknown") && + strncmp(filetype, "text/plain", (size_t)10) ) + return filetype; + else if (filetype) + lsx_debug("libmagic detected %s", filetype); + } +#endif + return NULL; +} + +static sox_encodings_info_t const s_sox_encodings_info[] = { + {sox_encodings_none , "n/a" , "Unknown or not applicable"}, + {sox_encodings_none , "Signed PCM" , "Signed Integer PCM"}, + {sox_encodings_none , "Unsigned PCM" , "Unsigned Integer PCM"}, + {sox_encodings_none , "F.P. PCM" , "Floating Point PCM"}, + {sox_encodings_none , "F.P. PCM" , "Floating Point (text) PCM"}, + {sox_encodings_none , "FLAC" , "FLAC"}, + {sox_encodings_none , "HCOM" , "HCOM"}, + {sox_encodings_none , "WavPack" , "WavPack"}, + {sox_encodings_none , "F.P. WavPack" , "Floating Point WavPack"}, + {sox_encodings_lossy1, "u-law" , "u-law"}, + {sox_encodings_lossy1, "A-law" , "A-law"}, + {sox_encodings_lossy1, "G.721 ADPCM" , "G.721 ADPCM"}, + {sox_encodings_lossy1, "G.723 ADPCM" , "G.723 ADPCM"}, + {sox_encodings_lossy1, "CL ADPCM (8)" , "CL ADPCM (from 8-bit)"}, + {sox_encodings_lossy1, "CL ADPCM (16)", "CL ADPCM (from 16-bit)"}, + {sox_encodings_lossy1, "MS ADPCM" , "MS ADPCM"}, + {sox_encodings_lossy1, "IMA ADPCM" , "IMA ADPCM"}, + {sox_encodings_lossy1, "OKI ADPCM" , "OKI ADPCM"}, + {sox_encodings_lossy1, "DPCM" , "DPCM"}, + {sox_encodings_none , "DWVW" , "DWVW"}, + {sox_encodings_none , "DWVWN" , "DWVWN"}, + {sox_encodings_lossy2, "GSM" , "GSM"}, + {sox_encodings_lossy2, "MPEG audio" , "MPEG audio (layer I, II or III)"}, + {sox_encodings_lossy2, "Vorbis" , "Vorbis"}, + {sox_encodings_lossy2, "AMR-WB" , "AMR-WB"}, + {sox_encodings_lossy2, "AMR-NB" , "AMR-NB"}, + {sox_encodings_lossy2, "CVSD" , "CVSD"}, + {sox_encodings_lossy2, "LPC10" , "LPC10"}, + {sox_encodings_lossy2, "Opus" , "Opus"}, +}; + +assert_static(array_length(s_sox_encodings_info) == SOX_ENCODINGS, + SIZE_MISMATCH_BETWEEN_sox_encoding_t_AND_sox_encodings_info); + +sox_encodings_info_t const * +sox_get_encodings_info(void) +{ + return s_sox_encodings_info; +} + +unsigned sox_precision(sox_encoding_t encoding, unsigned bits_per_sample) +{ + switch (encoding) { + case SOX_ENCODING_DWVW: return bits_per_sample; + case SOX_ENCODING_DWVWN: return !bits_per_sample? 16: 0; /* ? */ + case SOX_ENCODING_HCOM: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 1? bits_per_sample: 0; + case SOX_ENCODING_WAVPACK: + case SOX_ENCODING_FLAC: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 4? bits_per_sample: 0; + case SOX_ENCODING_SIGN2: return bits_per_sample <= 32? bits_per_sample : 0; + case SOX_ENCODING_UNSIGNED: return !(bits_per_sample & 7) && (bits_per_sample >> 3) - 1 < 4? bits_per_sample: 0; + + case SOX_ENCODING_ALAW: return bits_per_sample == 8? 13: 0; + case SOX_ENCODING_ULAW: return bits_per_sample == 8? 14: 0; + + case SOX_ENCODING_CL_ADPCM: return bits_per_sample? 8: 0; + case SOX_ENCODING_CL_ADPCM16: return bits_per_sample == 4? 13: 0; + case SOX_ENCODING_MS_ADPCM: return bits_per_sample == 4? 14: 0; + case SOX_ENCODING_IMA_ADPCM: return bits_per_sample == 4? 13: 0; + case SOX_ENCODING_OKI_ADPCM: return bits_per_sample == 4? 12: 0; + case SOX_ENCODING_G721: return bits_per_sample == 4? 12: 0; + case SOX_ENCODING_G723: return bits_per_sample == 3? 8: + bits_per_sample == 5? 14: 0; + case SOX_ENCODING_CVSD: return bits_per_sample == 1? 16: 0; + case SOX_ENCODING_DPCM: return bits_per_sample; /* ? */ + + case SOX_ENCODING_MP3: return 0; /* Accept the precision returned by the format. */ + + case SOX_ENCODING_GSM: + case SOX_ENCODING_VORBIS: + case SOX_ENCODING_OPUS: + case SOX_ENCODING_AMR_WB: + case SOX_ENCODING_AMR_NB: + case SOX_ENCODING_LPC10: return !bits_per_sample? 16: 0; + + case SOX_ENCODING_WAVPACKF: + case SOX_ENCODING_FLOAT: return bits_per_sample == 32 ? 25: bits_per_sample == 64 ? 54: 0; + case SOX_ENCODING_FLOAT_TEXT: return !bits_per_sample? 54: 0; + + case SOX_ENCODINGS: + case SOX_ENCODING_UNKNOWN: break; + } + return 0; +} + +void sox_init_encodinginfo(sox_encodinginfo_t * e) +{ + e->reverse_bytes = sox_option_default; + e->reverse_nibbles = sox_option_default; + e->reverse_bits = sox_option_default; + e->compression = HUGE_VAL; +} + +/*--------------------------------- Comments ---------------------------------*/ + +size_t sox_num_comments(sox_comments_t comments) +{ + size_t result = 0; + if (!comments) + return 0; + while (*comments++) + ++result; + return result; +} + +void sox_append_comment(sox_comments_t * comments, char const * comment) +{ + size_t n = sox_num_comments(*comments); + *comments = lsx_realloc(*comments, (n + 2) * sizeof(**comments)); + assert(comment); + (*comments)[n++] = lsx_strdup(comment); + (*comments)[n] = 0; +} + +void sox_append_comments(sox_comments_t * comments, char const * comment) +{ + char * end; + if (comment) { + while ((end = strchr(comment, '\n'))) { + size_t len = end - comment; + char * c = lsx_malloc((len + 1) * sizeof(*c)); + strncpy(c, comment, len); + c[len] = '\0'; + sox_append_comment(comments, c); + comment += len + 1; + free(c); + } + if (*comment) + sox_append_comment(comments, comment); + } +} + +sox_comments_t sox_copy_comments(sox_comments_t comments) +{ + sox_comments_t result = 0; + + if (comments) while (*comments) + sox_append_comment(&result, *comments++); + return result; +} + +void sox_delete_comments(sox_comments_t * comments) +{ + sox_comments_t p = *comments; + + if (p) while (*p) + free(*p++); + free(*comments); + *comments = 0; +} + +char * lsx_cat_comments(sox_comments_t comments) +{ + sox_comments_t p = comments; + size_t len = 0; + char * result; + + if (p) while (*p) + len += strlen(*p++) + 1; + + result = lsx_calloc(len? len : 1, sizeof(*result)); + + if ((p = comments) && *p) { + strcpy(result, *p); + while (*++p) + strcat(strcat(result, "\n"), *p); + } + return result; +} + +char const * sox_find_comment(sox_comments_t comments, char const * id) +{ + size_t len = strlen(id); + + if (comments) for (;*comments; ++comments) + if (!strncasecmp(*comments, id, len) && (*comments)[len] == '=') + return *comments + len + 1; + return NULL; +} + +static void set_endiannesses(sox_format_t * ft) +{ + if (ft->handler.flags & SOX_FILE_ENDIAN) { + sox_bool file_is_bigendian = !(ft->handler.flags & SOX_FILE_ENDBIG); + + if (ft->encoding.opposite_endian) { + ft->encoding.reverse_bytes = file_is_bigendian != MACHINE_IS_BIGENDIAN; + lsx_report("`%s': overriding file-type byte-order", ft->filename); + } else if (ft->encoding.reverse_bytes == sox_option_default) { + ft->encoding.reverse_bytes = file_is_bigendian == MACHINE_IS_BIGENDIAN; + } + } else { + if (ft->encoding.opposite_endian) { + ft->encoding.reverse_bytes = sox_option_yes; + lsx_report("`%s': overriding machine byte-order", ft->filename); + } else if (ft->encoding.reverse_bytes == sox_option_default) { + ft->encoding.reverse_bytes = sox_option_no; + } + } + + /* FIXME: Change reports to suitable warnings if trying + * to override something that can't be overridden. */ + + if (ft->encoding.reverse_bits == sox_option_default) + ft->encoding.reverse_bits = !!(ft->handler.flags & SOX_FILE_BIT_REV); + else if (ft->encoding.reverse_bits == !(ft->handler.flags & SOX_FILE_BIT_REV)) + lsx_report("`%s': overriding file-type bit-order", ft->filename); + + if (ft->encoding.reverse_nibbles == sox_option_default) + ft->encoding.reverse_nibbles = !!(ft->handler.flags & SOX_FILE_NIB_REV); + else + if (ft->encoding.reverse_nibbles == !(ft->handler.flags & SOX_FILE_NIB_REV)) + lsx_report("`%s': overriding file-type nibble-order", ft->filename); +} + +static sox_bool is_seekable(sox_format_t const * ft) +{ + assert(ft); + if (!ft->fp) + return sox_false; + + return !fseek(ft->fp, 0, SEEK_CUR); +} + +/* check that all settings have been given */ +static int sox_checkformat(sox_format_t * ft) +{ + ft->sox_errno = SOX_SUCCESS; + + if (ft->signal.rate <= 0) { + lsx_fail_errno(ft, SOX_EFMT, "sample rate zero or negative"); + return SOX_EOF; + } + if (!ft->signal.precision) { + lsx_fail_errno(ft,SOX_EFMT,"data encoding or sample size was not specified"); + return SOX_EOF; + } + return SOX_SUCCESS; +} + +static sox_bool is_url(char const * text) /* detects only wget-supported URLs */ +{ + return !( + strncasecmp(text, "http:" , (size_t)5) && + strncasecmp(text, "https:", (size_t)6) && + strncasecmp(text, "ftp:" , (size_t)4)); +} + +static int xfclose(FILE * file, lsx_io_type io_type) +{ + return +#ifdef HAVE_POPEN + io_type != lsx_io_file? pclose(file) : +#endif + fclose(file); +} + +static void incr_pipe_size(FILE *f) +{ +/* + * Linux 2.6.35 and later has the ability to expand the pipe buffer + * Try to get it as big as possible to avoid stalls when SoX itself + * is using big buffers + */ +#if defined(F_GETPIPE_SZ) && defined(F_SETPIPE_SZ) + static long max_pipe_size; + + /* read the maximum size of the pipe the first time this is called */ + if (max_pipe_size == 0) { + const char path[] = "/proc/sys/fs/pipe-max-size"; + int fd = open(path, O_RDONLY); + + max_pipe_size = -1; + if (fd >= 0) { + char buf[80]; + ssize_t r = read(fd, buf, sizeof(buf) - 1); + + if (r > 0) { + buf[r] = 0; + max_pipe_size = strtol(buf, NULL, 10); + + /* guard against obviously wrong values on messed up systems */ + if (max_pipe_size <= PIPE_BUF || max_pipe_size > INT_MAX) + max_pipe_size = -1; + } + close(fd); + } + } + + if (max_pipe_size > PIPE_BUF) { + int fd = fileno(f); + + if (fcntl(fd, F_SETPIPE_SZ, max_pipe_size) >= 0) + lsx_debug("got pipe %ld bytes\n", max_pipe_size); + else + lsx_warn("couldn't set pipe size to %ld bytes: %s\n", + max_pipe_size, strerror(errno)); + } +#endif /* do nothing for platforms without F_{GET,SET}PIPE_SZ */ +} + +static FILE * xfopen(char const * identifier, char const * mode, lsx_io_type * io_type) +{ + *io_type = lsx_io_file; + + if (*identifier == '|') { + FILE * f = NULL; +#ifdef HAVE_POPEN +#ifndef POPEN_MODE +#define POPEN_MODE "r" +#endif + f = popen(identifier + 1, POPEN_MODE); + *io_type = lsx_io_pipe; + incr_pipe_size(f); +#else + lsx_fail("this build of SoX cannot open pipes"); +#endif + return f; + } + else if (is_url(identifier)) { + FILE * f = NULL; +#ifdef HAVE_POPEN + char const * const command_format = "wget --no-check-certificate -q -O- \"%s\""; + char * command = lsx_malloc(strlen(command_format) + strlen(identifier)); + sprintf(command, command_format, identifier); + f = popen(command, POPEN_MODE); + incr_pipe_size(f); + free(command); + *io_type = lsx_io_url; +#else + lsx_fail("this build of SoX cannot open URLs"); +#endif + return f; + } + return fopen(identifier, mode); +} + +/* Hack to rewind pipes (a small amount). + * Works by resetting the FILE buffer pointer */ +static void UNUSED rewind_pipe(FILE * fp) +{ +/* _FSTDIO is for Torek stdio (i.e. most BSD-derived libc's) + * In theory, we no longer need to check _NEWLIB_VERSION or __APPLE__ */ +#if defined _FSTDIO || defined _NEWLIB_VERSION || defined __APPLE__ + fp->_p -= PIPE_AUTO_DETECT_SIZE; + fp->_r += PIPE_AUTO_DETECT_SIZE; +#elif defined __GLIBC__ + fp->_IO_read_ptr = fp->_IO_read_base; +#elif defined _MSC_VER && _MSC_VER >= 1900 + #define NO_REWIND_PIPE +#elif defined _MSC_VER || defined _WIN32 || defined _WIN64 || \ + defined _ISO_STDIO_ISO_H || defined __sgi + fp->_ptr = fp->_base; +#else + /* To fix this #error, either simply remove the #error line and live without + * file-type detection with pipes, or add support for your compiler in the + * lines above. Test with cat monkey.wav | ./sox --info - */ + #error FIX NEEDED HERE + #define NO_REWIND_PIPE + (void)fp; +#endif +} + +static sox_format_t * open_read( + char const * path, + void * buffer UNUSED, + size_t buffer_size UNUSED, + sox_signalinfo_t const * signal, + sox_encodinginfo_t const * encoding, + char const * filetype) +{ + sox_format_t * ft = lsx_calloc(1, sizeof(*ft)); + sox_format_handler_t const * handler; + char const * const io_types[] = {"file", "pipe", "file URL"}; + char const * type = ""; + size_t input_bufsiz = sox_globals.input_bufsiz? + sox_globals.input_bufsiz : sox_globals.bufsiz; + + if (filetype) { + if (!(handler = sox_find_format(filetype, sox_false))) { + lsx_fail("no handler for given file type `%s'", filetype); + goto error; + } + ft->handler = *handler; + } + + if (!(ft->handler.flags & SOX_FILE_NOSTDIO)) { + if (!strcmp(path, "-")) { /* Use stdin if the filename is "-" */ + if (sox_globals.stdin_in_use_by) { + lsx_fail("`-' (stdin) already in use by `%s'", sox_globals.stdin_in_use_by); + goto error; + } + sox_globals.stdin_in_use_by = "audio input"; + SET_BINARY_MODE(stdin); + ft->fp = stdin; + } + else { + ft->fp = +#ifdef HAVE_FMEMOPEN + buffer? fmemopen(buffer, buffer_size, "rb") : +#endif + xfopen(path, "rb", &ft->io_type); + type = io_types[ft->io_type]; + if (ft->fp == NULL) { + lsx_fail("can't open input %s `%s': %s", type, path, strerror(errno)); + goto error; + } + } + if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char) * input_bufsiz)) { + lsx_fail("Can't set read buffer"); + goto error; + } + ft->seekable = is_seekable(ft); + } + + if (!filetype) { + if (ft->seekable) { + filetype = auto_detect_format(ft, lsx_find_file_extension(path)); + lsx_rewind(ft); + } +#ifndef NO_REWIND_PIPE + else if (!(ft->handler.flags & SOX_FILE_NOSTDIO) && + input_bufsiz >= PIPE_AUTO_DETECT_SIZE) { + filetype = auto_detect_format(ft, lsx_find_file_extension(path)); + rewind_pipe(ft->fp); + ft->tell_off = 0; + } +#endif + + if (filetype) { + lsx_report("detected file format type `%s'", filetype); + if (!(handler = sox_find_format(filetype, sox_false))) { + lsx_fail("no handler for detected file type `%s'", filetype); + goto error; + } + } + else { + if (ft->io_type == lsx_io_pipe) { + filetype = "sox"; /* With successful pipe rewind, this isn't useful */ + lsx_report("assuming input pipe `%s' has file-type `sox'", path); + } + else if (!(filetype = lsx_find_file_extension(path))) { + lsx_fail("can't determine type of %s `%s'", type, path); + goto error; + } + if (!(handler = sox_find_format(filetype, sox_true))) { + lsx_fail("no handler for file extension `%s'", filetype); + goto error; + } + } + ft->handler = *handler; + if (ft->handler.flags & SOX_FILE_NOSTDIO) { + xfclose(ft->fp, ft->io_type); + ft->fp = NULL; + } + } + if (!ft->handler.startread && !ft->handler.read) { + lsx_fail("file type `%s' isn't readable", filetype); + goto error; + } + + ft->mode = 'r'; + ft->filetype = lsx_strdup(filetype); + ft->filename = lsx_strdup(path); + if (signal) + ft->signal = *signal; + + if (encoding) + ft->encoding = *encoding; + else sox_init_encodinginfo(&ft->encoding); + set_endiannesses(ft); + + if ((ft->handler.flags & SOX_FILE_DEVICE) && !(ft->handler.flags & SOX_FILE_PHONY)) + lsx_set_signal_defaults(ft); + + ft->priv = lsx_calloc(1, ft->handler.priv_size); + /* Read and write starters can change their formats. */ + if (ft->handler.startread && (*ft->handler.startread)(ft) != SOX_SUCCESS) { + lsx_fail("can't open input %s `%s': %s", type, ft->filename, ft->sox_errstr); + goto error; + } + + /* Fill in some defaults: */ + if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample)) + ft->signal.precision = sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample); + if (!(ft->handler.flags & SOX_FILE_PHONY) && !ft->signal.channels) + ft->signal.channels = 1; + + if (sox_checkformat(ft) != SOX_SUCCESS) { + lsx_fail("bad input format for %s `%s': %s", type, ft->filename, ft->sox_errstr); + goto error; + } + + if (signal) { + if (signal->rate && signal->rate != ft->signal.rate) + lsx_warn("can't set sample rate %g; using %g", signal->rate, ft->signal.rate); + if (signal->channels && signal->channels != ft->signal.channels) + lsx_warn("can't set %u channels; using %u", signal->channels, ft->signal.channels); + } + return ft; + +error: + if (ft->fp && ft->fp != stdin) + xfclose(ft->fp, ft->io_type); + free(ft->priv); + free(ft->filename); + free(ft->filetype); + free(ft); + return NULL; +} + +sox_format_t * sox_open_read( + char const * path, + sox_signalinfo_t const * signal, + sox_encodinginfo_t const * encoding, + char const * filetype) +{ + return open_read(path, NULL, (size_t)0, signal, encoding, filetype); +} + +sox_format_t * sox_open_mem_read( + void * buffer, + size_t buffer_size, + sox_signalinfo_t const * signal, + sox_encodinginfo_t const * encoding, + char const * filetype) +{ + return open_read("", buffer, buffer_size, signal,encoding,filetype); +} + +sox_bool sox_format_supports_encoding( + char const * path, + char const * filetype, + sox_encodinginfo_t const * encoding) +{ + #define enc_arg(T) (T)handler->write_formats[i++] + sox_bool is_file_extension = filetype == NULL; + sox_format_handler_t const * handler; + unsigned i = 0, s; + sox_encoding_t e; + + assert(path || filetype); + assert(encoding); + if (!filetype) + filetype = lsx_find_file_extension(path); + + if (!filetype || !(handler = sox_find_format(filetype, is_file_extension)) || + !handler->write_formats) + return sox_false; + while ((e = enc_arg(sox_encoding_t))) { + if (e == encoding->encoding) { + sox_bool has_bits; + for (has_bits = sox_false; (s = enc_arg(unsigned)); has_bits = sox_true) + if (s == encoding->bits_per_sample) + return sox_true; + if (!has_bits && !encoding->bits_per_sample) + return sox_true; + break; + } + while (enc_arg(unsigned)); + } + return sox_false; + #undef enc_arg +} + +static void set_output_format(sox_format_t * ft) +{ + sox_encoding_t e = SOX_ENCODING_UNKNOWN; + unsigned i, s; + unsigned const * encodings = ft->handler.write_formats; +#define enc_arg(T) (T)encodings[i++] + + if (ft->handler.write_rates){ + if (!ft->signal.rate) + ft->signal.rate = ft->handler.write_rates[0]; + else { + sox_rate_t r; + i = 0; + while ((r = ft->handler.write_rates[i++])) { + if (r == ft->signal.rate) + break; + } + if (r != ft->signal.rate) { + sox_rate_t given = ft->signal.rate, max = 0; + ft->signal.rate = HUGE_VAL; + i = 0; + while ((r = ft->handler.write_rates[i++])) { + if (r > given && r < ft->signal.rate) + ft->signal.rate = r; + else max = max(r, max); + } + if (ft->signal.rate == HUGE_VAL) + ft->signal.rate = max; + lsx_warn("%s can't encode at %gHz; using %gHz", ft->handler.names[0], given, ft->signal.rate); + } + } + } + else if (!ft->signal.rate) + ft->signal.rate = SOX_DEFAULT_RATE; + + if (ft->handler.flags & SOX_FILE_CHANS) { + if (ft->signal.channels == 1 && !(ft->handler.flags & SOX_FILE_MONO)) { + ft->signal.channels = (ft->handler.flags & SOX_FILE_STEREO)? 2 : 4; + lsx_warn("%s can't encode mono; setting channels to %u", ft->handler.names[0], ft->signal.channels); + } else + if (ft->signal.channels == 2 && !(ft->handler.flags & SOX_FILE_STEREO)) { + ft->signal.channels = (ft->handler.flags & SOX_FILE_QUAD)? 4 : 1; + lsx_warn("%s can't encode stereo; setting channels to %u", ft->handler.names[0], ft->signal.channels); + } else + if (ft->signal.channels == 4 && !(ft->handler.flags & SOX_FILE_QUAD)) { + ft->signal.channels = (ft->handler.flags & SOX_FILE_STEREO)? 2 : 1; + lsx_warn("%s can't encode quad; setting channels to %u", ft->handler.names[0], ft->signal.channels); + } + } else ft->signal.channels = max(ft->signal.channels, 1); + + if (!encodings) + return; + /* If an encoding has been given, check if it supported by this handler */ + if (ft->encoding.encoding) { + i = 0; + while ((e = enc_arg(sox_encoding_t))) { + if (e == ft->encoding.encoding) + break; + while (enc_arg(unsigned)); + } + if (e != ft->encoding.encoding) { + lsx_warn("%s can't encode %s", ft->handler.names[0], sox_encodings_info[ft->encoding.encoding].desc); + ft->encoding.encoding = 0; + } + else { + unsigned max_p = 0; + unsigned max_p_s = 0; + unsigned given_size = 0; + sox_bool found = sox_false; + if (ft->encoding.bits_per_sample) + given_size = ft->encoding.bits_per_sample; + ft->encoding.bits_per_sample = 65; + while ((s = enc_arg(unsigned))) { + if (s == given_size) + found = sox_true; + if (sox_precision(e, s) >= ft->signal.precision) { + if (s < ft->encoding.bits_per_sample) + ft->encoding.bits_per_sample = s; + } + else if (sox_precision(e, s) > max_p) { + max_p = sox_precision(e, s); + max_p_s = s; + } + } + if (ft->encoding.bits_per_sample == 65) + ft->encoding.bits_per_sample = max_p_s; + if (given_size) { + if (found) + ft->encoding.bits_per_sample = given_size; + else lsx_warn("%s can't encode %s to %u-bit", ft->handler.names[0], sox_encodings_info[ft->encoding.encoding].desc, given_size); + } + } + } + + /* If a size has been given, check if it supported by this handler */ + if (!ft->encoding.encoding && ft->encoding.bits_per_sample) { + i = 0; + s= 0; + while (s != ft->encoding.bits_per_sample && (e = enc_arg(sox_encoding_t))) + while ((s = enc_arg(unsigned)) && s != ft->encoding.bits_per_sample); + if (s != ft->encoding.bits_per_sample) { + lsx_warn("%s can't encode to %u-bit", ft->handler.names[0], ft->encoding.bits_per_sample); + ft->encoding.bits_per_sample = 0; + } + else ft->encoding.encoding = e; + } + + /* Find the smallest lossless encoding with precision >= signal.precision */ + if (!ft->encoding.encoding) { + ft->encoding.bits_per_sample = 65; + i = 0; + while ((e = enc_arg(sox_encoding_t))) + while ((s = enc_arg(unsigned))) + if (!(sox_encodings_info[e].flags & (sox_encodings_lossy1 | sox_encodings_lossy2)) && + sox_precision(e, s) >= ft->signal.precision && s < ft->encoding.bits_per_sample) { + ft->encoding.encoding = e; + ft->encoding.bits_per_sample = s; + } + } + + /* Find the smallest lossy encoding with precision >= signal precision, + * or, if none such, the highest precision encoding */ + if (!ft->encoding.encoding) { + unsigned max_p = 0; + sox_encoding_t max_p_e = 0; + unsigned max_p_s = 0; + i = 0; + while ((e = enc_arg(sox_encoding_t))) + do { + s = enc_arg(unsigned); + if (sox_precision(e, s) >= ft->signal.precision) { + if (s < ft->encoding.bits_per_sample) { + ft->encoding.encoding = e; + ft->encoding.bits_per_sample = s; + } + } + else if (sox_precision(e, s) > max_p) { + max_p = sox_precision(e, s); + max_p_e = e; + max_p_s = s; + } + } while (s); + if (!ft->encoding.encoding) { + ft->encoding.encoding = max_p_e; + ft->encoding.bits_per_sample = max_p_s; + } + } + ft->signal.precision = sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample); + #undef enc_arg +} + +sox_format_handler_t const * sox_write_handler( + char const * path, + char const * filetype, + char const * * filetype1) +{ + sox_format_handler_t const * handler; + if (filetype) { + if (!(handler = sox_find_format(filetype, sox_false))) { + if (filetype1) + lsx_fail("no handler for given file type `%s'", filetype); + return NULL; + } + } + else if (path) { + if (!(filetype = lsx_find_file_extension(path))) { + if (filetype1) + lsx_fail("can't determine type of `%s'", path); + return NULL; + } + if (!(handler = sox_find_format(filetype, sox_true))) { + if (filetype1) + lsx_fail("no handler for file extension `%s'", filetype); + return NULL; + } + } + else return NULL; + if (!handler->startwrite && !handler->write) { + if (filetype1) + lsx_fail("file type `%s' isn't writable", filetype); + return NULL; + } + if (filetype1) + *filetype1 = filetype; + return handler; +} + +static sox_format_t * open_write( + char const * path, + void * buffer UNUSED, + size_t buffer_size UNUSED, + char * * buffer_ptr UNUSED, + size_t * buffer_size_ptr UNUSED, + sox_signalinfo_t const * signal, + sox_encodinginfo_t const * encoding, + char const * filetype, + sox_oob_t const * oob, + sox_bool (*overwrite_permitted)(const char *filename)) +{ + sox_format_t * ft = lsx_calloc(sizeof(*ft), 1); + sox_format_handler_t const * handler; + + if (!path || !signal) { + lsx_fail("must specify file name and signal parameters to write file"); + goto error; + } + + if (!(handler = sox_write_handler(path, filetype, &filetype))) + goto error; + + ft->handler = *handler; + + if (!(ft->handler.flags & SOX_FILE_NOSTDIO)) { + if (!strcmp(path, "-")) { /* Use stdout if the filename is "-" */ + if (sox_globals.stdout_in_use_by) { + lsx_fail("`-' (stdout) already in use by `%s'", sox_globals.stdout_in_use_by); + goto error; + } + sox_globals.stdout_in_use_by = "audio output"; + SET_BINARY_MODE(stdout); + ft->fp = stdout; + } + else { + struct stat st; + if (!stat(path, &st) && (st.st_mode & S_IFMT) == S_IFREG && + (overwrite_permitted && !overwrite_permitted(path))) { + lsx_fail("permission to overwrite `%s' denied", path); + goto error; + } + ft->fp = +#ifdef HAVE_FMEMOPEN + buffer? fmemopen(buffer, buffer_size, "w+b") : + buffer_ptr? open_memstream(buffer_ptr, buffer_size_ptr) : +#endif + fopen(path, "w+b"); + if (ft->fp == NULL) { + lsx_fail("can't open output file `%s': %s", path, strerror(errno)); + goto error; + } + } + + /* stdout tends to be line-buffered. Override this */ + /* to be Full Buffering. */ + if (setvbuf (ft->fp, NULL, _IOFBF, sizeof(char) * sox_globals.bufsiz)) { + lsx_fail("Can't set write buffer"); + goto error; + } + ft->seekable = is_seekable(ft); + } + + ft->filetype = lsx_strdup(filetype); + ft->filename = lsx_strdup(path); + ft->mode = 'w'; + ft->signal = *signal; + + if (encoding) + ft->encoding = *encoding; + else sox_init_encodinginfo(&ft->encoding); + set_endiannesses(ft); + + if (oob) { + ft->oob = *oob; + /* deep copy: */ + ft->oob.comments = sox_copy_comments(oob->comments); + } + + set_output_format(ft); + + /* FIXME: doesn't cover the situation where + * codec changes audio length due to block alignment (e.g. 8svx, gsm): */ + if (signal->rate && signal->channels) + ft->signal.length = ft->signal.length * ft->signal.rate / signal->rate * + ft->signal.channels / signal->channels + .5; + + if ((ft->handler.flags & SOX_FILE_REWIND) && strcmp(ft->filetype, "sox") && !ft->signal.length && !ft->seekable) + lsx_warn("can't seek in output file `%s'; length in file header will be unspecified", ft->filename); + + ft->priv = lsx_calloc(1, ft->handler.priv_size); + /* Read and write starters can change their formats. */ + if (ft->handler.startwrite && (ft->handler.startwrite)(ft) != SOX_SUCCESS){ + lsx_fail("can't open output file `%s': %s", ft->filename, ft->sox_errstr); + goto error; + } + + if (sox_checkformat(ft) != SOX_SUCCESS) { + lsx_fail("bad format for output file `%s': %s", ft->filename, ft->sox_errstr); + goto error; + } + + if ((ft->handler.flags & SOX_FILE_DEVICE) && signal) { + if (signal->rate && signal->rate != ft->signal.rate) + lsx_report("can't set sample rate %g; using %g", signal->rate, ft->signal.rate); + if (signal->channels && signal->channels != ft->signal.channels) + lsx_report("can't set %u channels; using %u", signal->channels, ft->signal.channels); + } + return ft; + +error: + if (ft->fp && ft->fp != stdout) + xfclose(ft->fp, ft->io_type); + free(ft->priv); + free(ft->filename); + free(ft->filetype); + free(ft); + return NULL; +} + +sox_format_t * sox_open_write( + char const * path, + sox_signalinfo_t const * signal, + sox_encodinginfo_t const * encoding, + char const * filetype, + sox_oob_t const * oob, + sox_bool (*overwrite_permitted)(const char *filename)) +{ + return open_write(path, NULL, (size_t)0, NULL, NULL, signal, encoding, filetype, oob, overwrite_permitted); +} + +sox_format_t * sox_open_mem_write( + void * buffer, + size_t buffer_size, + sox_signalinfo_t const * signal, + sox_encodinginfo_t const * encoding, + char const * filetype, + sox_oob_t const * oob) +{ + return open_write("", buffer, buffer_size, NULL, NULL, signal, encoding, filetype, oob, NULL); +} + +sox_format_t * sox_open_memstream_write( + char * * buffer_ptr, + size_t * buffer_size_ptr, + sox_signalinfo_t const * signal, + sox_encodinginfo_t const * encoding, + char const * filetype, + sox_oob_t const * oob) +{ + return open_write("", NULL, (size_t)0, buffer_ptr, buffer_size_ptr, signal, encoding, filetype, oob, NULL); +} + +size_t sox_read(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + size_t actual; + if (ft->signal.length != SOX_UNSPEC) + len = min(len, ft->signal.length - ft->olength); + actual = ft->handler.read? (*ft->handler.read)(ft, buf, len) : 0; + actual = actual > len? 0 : actual; + ft->olength += actual; + return actual; +} + +size_t sox_write(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + size_t actual = ft->handler.write? (*ft->handler.write)(ft, buf, len) : 0; + ft->olength += actual; + return actual; +} + +int sox_close(sox_format_t * ft) +{ + int result = SOX_SUCCESS; + + if (ft->mode == 'r') + result = ft->handler.stopread? (*ft->handler.stopread)(ft) : SOX_SUCCESS; + else { + if (ft->handler.flags & SOX_FILE_REWIND) { + if (ft->olength != ft->signal.length && ft->seekable) { + result = lsx_seeki(ft, (off_t)0, 0); + if (result == SOX_SUCCESS) + result = ft->handler.stopwrite? (*ft->handler.stopwrite)(ft) + : ft->handler.startwrite?(*ft->handler.startwrite)(ft) : SOX_SUCCESS; + } + } + else result = ft->handler.stopwrite? (*ft->handler.stopwrite)(ft) : SOX_SUCCESS; + } + + if (ft->fp == stdin) { + sox_globals.stdin_in_use_by = NULL; + } else if (ft->fp == stdout) { + fflush(stdout); + sox_globals.stdout_in_use_by = NULL; + } else if (ft->fp) { + xfclose(ft->fp, ft->io_type); + } + + free(ft->priv); + free(ft->filename); + free(ft->filetype); + sox_delete_comments(&ft->oob.comments); + + free(ft); + return result; +} + +int sox_seek(sox_format_t * ft, sox_uint64_t offset, int whence) +{ + /* FIXME: Implement SOX_SEEK_CUR and SOX_SEEK_END. */ + if (whence != SOX_SEEK_SET) + return SOX_EOF; /* FIXME: return SOX_EINVAL */ + + /* If file is a seekable file and this handler supports seeking, + * then invoke handler's function. + */ + if (ft->seekable && ft->handler.seek) + return (*ft->handler.seek)(ft, offset); + return SOX_EOF; /* FIXME: return SOX_EBADF */ +} + +static int strcaseends(char const * str, char const * end) +{ + size_t str_len = strlen(str), end_len = strlen(end); + return str_len >= end_len && !strcasecmp(str + str_len - end_len, end); +} + +typedef enum {None, M3u, Pls} playlist_t; + +static playlist_t playlist_type(char const * filename) +{ + char * x, * p; + playlist_t result = None; + + if (*filename == '|') + return result; + if (strcaseends(filename, ".m3u")) + return M3u; + if (strcaseends(filename, ".pls")) + return Pls; + x = lsx_strdup(filename); + p = strrchr(x, '?'); + if (p) { + *p = '\0'; + result = playlist_type(x); + } + free(x); + return result; +} + +sox_bool sox_is_playlist(char const * filename) +{ + return playlist_type(filename) != None; +} + +int sox_parse_playlist(sox_playlist_callback_t callback, void * p, char const * const listname) +{ + sox_bool const is_pls = playlist_type(listname) == Pls; + int const comment_char = "#;"[is_pls]; + size_t text_length = 100; + char * text = lsx_malloc(text_length + 1); + char * dirname = lsx_strdup(listname); + char * slash_pos = LAST_SLASH(dirname); + lsx_io_type io_type; + FILE * file = xfopen(listname, "r", &io_type); + char * filename; + int c, result = SOX_SUCCESS; + + if (!slash_pos) + *dirname = '\0'; + else + *slash_pos = '\0'; + + if (file == NULL) { + lsx_fail("Can't open playlist file `%s': %s", listname, strerror(errno)); + result = SOX_EOF; + } + else { + do { + size_t i = 0; + size_t begin = 0, end = 0; + + while (isspace(c = getc(file))); + if (c == EOF) + break; + while (c != EOF && !strchr("\r\n", c) && c != comment_char) { + if (i == text_length) + text = lsx_realloc(text, (text_length <<= 1) + 1); + text[i++] = c; + if (!strchr(" \t\f", c)) + end = i; + c = getc(file); + } + if (ferror(file)) + break; + if (c == comment_char) { + do c = getc(file); + while (c != EOF && !strchr("\r\n", c)); + if (ferror(file)) + break; + } + text[end] = '\0'; + if (is_pls) { + char dummy; + if (!strncasecmp(text, "file", (size_t) 4) && sscanf(text + 4, "%*u=%c", &dummy) == 1) + begin = strchr(text + 5, '=') - text + 1; + else end = 0; + } + if (begin != end) { + char const * id = text + begin; + + if (!dirname[0] || is_url(id) || IS_ABSOLUTE(id)) + filename = lsx_strdup(id); + else { + filename = lsx_malloc(strlen(dirname) + strlen(id) + 2); + sprintf(filename, "%s/%s", dirname, id); + } + if (sox_is_playlist(filename)) + sox_parse_playlist(callback, p, filename); + else if (callback(p, filename)) + c = EOF; + free(filename); + } + } while (c != EOF); + + if (ferror(file)) { + lsx_fail("error reading playlist file `%s': %s", listname, strerror(errno)); + result = SOX_EOF; + } + if (xfclose(file, io_type) && io_type == lsx_io_url) { + lsx_fail("error reading playlist file URL `%s'", listname); + result = SOX_EOF; + } + } + free(text); + free(dirname); + return result; +} + +/*----------------------------- Formats library ------------------------------*/ + +enum { + #define FORMAT(f) f, + #include "formats.h" + #undef FORMAT + NSTATIC_FORMATS +}; + +static sox_bool plugins_initted = sox_false; + +#ifdef HAVE_LIBLTDL /* Plugin format handlers */ + #define MAX_DYNAMIC_FORMATS 42 + #define MAX_FORMATS (NSTATIC_FORMATS + MAX_DYNAMIC_FORMATS) + #define MAX_FORMATS_1 (MAX_FORMATS + 1) + #define MAX_NAME_LEN (size_t)1024 /* FIXME: Use vasprintf */ +#else + #define MAX_FORMATS_1 +#endif + +#define FORMAT(f) extern sox_format_handler_t const * lsx_##f##_format_fn(void); +#include "formats.h" +#undef FORMAT + +static sox_format_tab_t s_sox_format_fns[MAX_FORMATS_1] = { + #define FORMAT(f) {NULL, lsx_##f##_format_fn}, + #include "formats.h" + #undef FORMAT + {NULL, NULL} +}; + +const sox_format_tab_t * +sox_get_format_fns(void) +{ + return s_sox_format_fns; +} + +static unsigned nformats = NSTATIC_FORMATS; + +#ifdef HAVE_LIBLTDL /* Plugin format handlers */ + + static int init_format(const char *file, lt_ptr data) + { + lt_dlhandle lth = lt_dlopenext(file); + const char *end = file + strlen(file); + const char prefix[] = "sox_fmt_"; + char fnname[MAX_NAME_LEN]; + char *start = strstr(file, prefix); + + (void)data; + if (start && (start += sizeof(prefix) - 1) < end) { + int ret = snprintf(fnname, MAX_NAME_LEN, + "lsx_%.*s_format_fn", (int)(end - start), start); + if (ret > 0 && ret < (int)MAX_NAME_LEN) { + union {sox_format_fn_t fn; lt_ptr ptr;} ltptr; + ltptr.ptr = lt_dlsym(lth, fnname); + lsx_debug("opening format plugin `%s': library %p, entry point %p\n", + fnname, (void *)lth, ltptr.ptr); + if (ltptr.fn && (ltptr.fn()->sox_lib_version_code & ~255) == + (SOX_LIB_VERSION_CODE & ~255)) { /* compatible version check */ + if (nformats == MAX_FORMATS) { + lsx_warn("too many plugin formats"); + return -1; + } + s_sox_format_fns[nformats++].fn = ltptr.fn; + } + } + } + return 0; + } +#endif + +int sox_format_init(void) /* Find & load format handlers. */ +{ + if (plugins_initted) + return SOX_EOF; + + plugins_initted = sox_true; +#ifdef HAVE_LIBLTDL + { + int error = lt_dlinit(); + if (error) { + lsx_fail("lt_dlinit failed with %d error(s): %s", error, lt_dlerror()); + return SOX_EOF; + } + lt_dlforeachfile(PKGLIBDIR, init_format, NULL); + } +#endif + return SOX_SUCCESS; +} + +void sox_format_quit(void) /* Cleanup things. */ +{ +#ifdef HAVE_LIBLTDL + int ret; + if (plugins_initted && (ret = lt_dlexit()) != 0) + lsx_fail("lt_dlexit failed with %d error(s): %s", ret, lt_dlerror()); + plugins_initted = sox_false; + nformats = NSTATIC_FORMATS; +#endif +} + +/* Find a named format in the formats library. + * + * (c) 2005-9 Chris Bagwell and SoX contributors. + * Copyright 1991 Lance Norskog And Sundry Contributors. + * + * This source code is freely redistributable and may be used for any + * purpose. This copyright notice must be maintained. + * + * Lance Norskog, Sundry Contributors, Chris Bagwell and SoX contributors + * are not responsible for the consequences of using this software. + */ +sox_format_handler_t const * sox_find_format(char const * name0, sox_bool no_dev) +{ + size_t f, n; + + if (name0) { + char * name = lsx_strdup(name0); + char * pos = strchr(name, ';'); + if (pos) /* Use only the 1st clause of a mime string */ + *pos = '\0'; + for (f = 0; f < nformats; ++f) { + sox_format_handler_t const * handler = s_sox_format_fns[f].fn(); + + if (!(no_dev && (handler->flags & SOX_FILE_DEVICE))) + for (n = 0; handler->names[n]; ++n) + if (!strcasecmp(handler->names[n], name)) { + free(name); + return handler; /* Found it. */ + } + } + free(name); + } + if (sox_format_init() == SOX_SUCCESS) /* Try again with plugins */ + return sox_find_format(name0, no_dev); + return NULL; +} diff --git a/app/src/main/cpp/sox/formats.h b/app/src/main/cpp/sox/formats.h new file mode 100644 index 0000000..16712b8 --- /dev/null +++ b/app/src/main/cpp/sox/formats.h @@ -0,0 +1,130 @@ +/* libSoX static formats list (c) 2006-9 Chris Bagwell and SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/*-------------------------- Static format handlers --------------------------*/ + + FORMAT(aifc) + FORMAT(aiff) + FORMAT(al) + FORMAT(au) + FORMAT(avr) + FORMAT(cdr) + FORMAT(cvsd) + FORMAT(cvu) + FORMAT(dat) + FORMAT(dvms) + FORMAT(f4) + FORMAT(f8) + FORMAT(gsrt) + FORMAT(hcom) + FORMAT(htk) + FORMAT(ima) + FORMAT(la) + FORMAT(lu) + FORMAT(maud) + FORMAT(nul) + FORMAT(prc) + FORMAT(raw) + FORMAT(s1) + FORMAT(s2) + FORMAT(s3) + FORMAT(s4) + FORMAT(sf) + FORMAT(sln) + FORMAT(smp) + FORMAT(sounder) + FORMAT(soundtool) + FORMAT(sox) + FORMAT(sphere) + FORMAT(svx) + FORMAT(txw) + FORMAT(u1) + FORMAT(u2) + FORMAT(u3) + FORMAT(u4) + FORMAT(ul) + FORMAT(voc) + FORMAT(vox) + FORMAT(wav) + FORMAT(wve) + FORMAT(xa) + +/*--------------------- Plugin or static format handlers ---------------------*/ + +#if defined HAVE_ALSA && (defined STATIC_ALSA || !defined HAVE_LIBLTDL) + FORMAT(alsa) +#endif +#if defined HAVE_AMRNB && (defined STATIC_AMRNB || !defined HAVE_LIBLTDL) + FORMAT(amr_nb) +#endif +#if defined HAVE_AMRWB && (defined STATIC_AMRWB || !defined HAVE_LIBLTDL) + FORMAT(amr_wb) +#endif +#if defined HAVE_AO && (defined STATIC_AO || !defined HAVE_LIBLTDL) + FORMAT(ao) +#endif +#if defined HAVE_COREAUDIO && (defined STATIC_COREAUDIO || !defined HAVE_LIBLTDL) + FORMAT(coreaudio) +#endif +#if defined HAVE_FLAC && (defined STATIC_FLAC || !defined HAVE_LIBLTDL) + FORMAT(flac) +#endif +#if defined HAVE_GSM && (defined STATIC_GSM || !defined HAVE_LIBLTDL) + FORMAT(gsm) +#endif +#if defined HAVE_LPC10 && (defined STATIC_LPC10 || !defined HAVE_LIBLTDL) + FORMAT(lpc10) +#endif +#if defined HAVE_MP3 && (defined STATIC_MP3 || !defined HAVE_LIBLTDL) + FORMAT(mp3) +#endif +#if defined HAVE_OPUS && (defined STATIC_OPUS || !defined HAVE_LIBLTDL) + FORMAT(opus) +#endif +#if defined HAVE_OSS && (defined STATIC_OSS || !defined HAVE_LIBLTDL) + FORMAT(oss) +#endif +#if defined HAVE_PULSEAUDIO && (defined STATIC_PULSEAUDIO || !defined HAVE_LIBLTDL) + FORMAT(pulseaudio) +#endif +#if defined HAVE_WAVEAUDIO && (defined STATIC_WAVEAUDIO || !defined HAVE_LIBLTDL) + FORMAT(waveaudio) +#endif +#if defined HAVE_SNDIO && (defined STATIC_SNDIO || !defined HAVE_LIBLTDL) + FORMAT(sndio) +#endif +#if defined HAVE_SNDFILE && (defined STATIC_SNDFILE || !defined HAVE_LIBLTDL) + FORMAT(sndfile) + FORMAT(caf) + FORMAT(fap) + FORMAT(mat4) + FORMAT(mat5) + FORMAT(paf) + FORMAT(pvf) + FORMAT(sd2) + FORMAT(w64) + FORMAT(xi) +#endif +#if defined HAVE_SUNAUDIO && (defined STATIC_SUNAUDIO || !defined HAVE_LIBLTDL) + FORMAT(sunau) +#endif +#if defined HAVE_OGGVORBIS && (defined STATIC_OGGVORBIS || !defined HAVE_LIBLTDL) + FORMAT(vorbis) +#endif +#if defined HAVE_WAVPACK && (defined STATIC_WAVPACK || !defined HAVE_LIBLTDL) + FORMAT(wavpack) +#endif diff --git a/app/src/main/cpp/sox/formats_i.c b/app/src/main/cpp/sox/formats_i.c new file mode 100644 index 0000000..7048040 --- /dev/null +++ b/app/src/main/cpp/sox/formats_i.c @@ -0,0 +1,545 @@ +/* Implements a libSoX internal interface for use in implementing file formats. + * All public functions & data are prefixed with lsx_ . + * + * (c) 2005-8 Chris Bagwell and SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include +#include +#include + +void lsx_fail_errno(sox_format_t * ft, int sox_errno, const char *fmt, ...) +{ + va_list args; + + ft->sox_errno = sox_errno; + + va_start(args, fmt); +#ifdef HAVE_VSNPRINTF + vsnprintf(ft->sox_errstr, sizeof(ft->sox_errstr), fmt, args); +#else + vsprintf(ft->sox_errstr, fmt, args); +#endif + va_end(args); + ft->sox_errstr[255] = '\0'; +} + +void lsx_set_signal_defaults(sox_format_t * ft) +{ + if (!ft->signal.rate ) ft->signal.rate = SOX_DEFAULT_RATE; + if (!ft->signal.precision) ft->signal.precision = SOX_DEFAULT_PRECISION; + if (!ft->signal.channels ) ft->signal.channels = SOX_DEFAULT_CHANNELS; + + if (!ft->encoding.bits_per_sample) + ft->encoding.bits_per_sample = ft->signal.precision; + if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) + ft->encoding.encoding = SOX_ENCODING_SIGN2; +} + +int lsx_check_read_params(sox_format_t * ft, unsigned channels, + sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample, + uint64_t num_samples, sox_bool check_length) +{ + ft->signal.length = ft->signal.length == SOX_IGNORE_LENGTH? SOX_UNSPEC : num_samples; + + if (ft->seekable) + ft->data_start = lsx_tell(ft); + + if (channels && ft->signal.channels && ft->signal.channels != channels) + lsx_warn("`%s': overriding number of channels", ft->filename); + else ft->signal.channels = channels; + + if (rate && ft->signal.rate && ft->signal.rate != rate) + lsx_warn("`%s': overriding sample rate", ft->filename); + else ft->signal.rate = rate; + + if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding) + lsx_warn("`%s': overriding encoding type", ft->filename); + else ft->encoding.encoding = encoding; + + if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample) + lsx_warn("`%s': overriding encoding size", ft->filename); + ft->encoding.bits_per_sample = bits_per_sample; + + if (check_length && ft->encoding.bits_per_sample && lsx_filelength(ft)) { + uint64_t calculated_length = div_bits(lsx_filelength(ft) - ft->data_start, ft->encoding.bits_per_sample); + if (!ft->signal.length) + ft->signal.length = calculated_length; + else if (num_samples != calculated_length) + lsx_warn("`%s': file header gives the total number of samples as %" PRIu64 " but file length indicates the number is in fact %" PRIu64, ft->filename, num_samples, calculated_length); + } + + if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample)) + return SOX_SUCCESS; + lsx_fail_errno(ft, EINVAL, "invalid format for this file type"); + return SOX_EOF; +} + +/* Read in a buffer of data of length len bytes. + * Returns number of bytes read. + */ +size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len) +{ + size_t ret = fread(buf, (size_t) 1, len, (FILE*)ft->fp); + if (ret != len && ferror((FILE*)ft->fp)) + lsx_fail_errno(ft, errno, "lsx_readbuf"); + ft->tell_off += ret; + return ret; +} + +/* Skip input without seeking. */ +int lsx_skipbytes(sox_format_t * ft, size_t n) +{ + unsigned char trash; + + while (n--) + if (lsx_readb(ft, &trash) == SOX_EOF) + return (SOX_EOF); + + return (SOX_SUCCESS); +} + +/* Pad output. */ +int lsx_padbytes(sox_format_t * ft, size_t n) +{ + while (n--) + if (lsx_writeb(ft, '\0') == SOX_EOF) + return (SOX_EOF); + + return (SOX_SUCCESS); +} + +/* Write a buffer of data of length bytes. + * Returns number of bytes written. + */ +size_t lsx_writebuf(sox_format_t * ft, void const * buf, size_t len) +{ + size_t ret = fwrite(buf, (size_t) 1, len, (FILE*)ft->fp); + if (ret != len) { + lsx_fail_errno(ft, errno, "error writing output file"); + clearerr((FILE*)ft->fp); /* Allows us to seek back to write header */ + } + ft->tell_off += ret; + return ret; +} + +sox_uint64_t lsx_filelength(sox_format_t * ft) +{ + struct stat st; + int ret = ft->fp ? fstat(fileno((FILE*)ft->fp), &st) : 0; + + return (!ret && (st.st_mode & S_IFREG))? (uint64_t)st.st_size : 0; +} + +int lsx_flush(sox_format_t * ft) +{ + return fflush((FILE*)ft->fp); +} + +off_t lsx_tell(sox_format_t * ft) +{ + return ft->seekable? (off_t)ftello((FILE*)ft->fp) : (off_t)ft->tell_off; +} + +int lsx_eof(sox_format_t * ft) +{ + return feof((FILE*)ft->fp); +} + +int lsx_error(sox_format_t * ft) +{ + return ferror((FILE*)ft->fp); +} + +void lsx_rewind(sox_format_t * ft) +{ + rewind((FILE*)ft->fp); + ft->tell_off = 0; +} + +void lsx_clearerr(sox_format_t * ft) +{ + clearerr((FILE*)ft->fp); + ft->sox_errno = 0; +} + +int lsx_unreadb(sox_format_t * ft, unsigned b) +{ + return ungetc((int)b, ft->fp); +} + +/* Implements traditional fseek() behavior. Meant to abstract out + * file operations so that they could one day also work on memory + * buffers. + * + * N.B. Can only seek forwards on non-seekable streams! + */ +int lsx_seeki(sox_format_t * ft, off_t offset, int whence) +{ + if (ft->seekable == 0) { + /* If a stream peel off chars else EPERM */ + if (whence == SEEK_CUR) { + while (offset > 0 && !feof((FILE*)ft->fp)) { + getc((FILE*)ft->fp); + offset--; + ++ft->tell_off; + } + if (offset) + lsx_fail_errno(ft,SOX_EOF, "offset past EOF"); + else + ft->sox_errno = SOX_SUCCESS; + } else + lsx_fail_errno(ft,SOX_EPERM, "file not seekable"); + } else { + if (fseeko((FILE*)ft->fp, offset, whence) == -1) + lsx_fail_errno(ft,errno, "%s", strerror(errno)); + else + ft->sox_errno = SOX_SUCCESS; + } + return ft->sox_errno; +} + +int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample) +{ + double wide_sample = to_sample - (to_sample % ft->signal.channels); + double to_d = wide_sample * ft->encoding.bits_per_sample / 8; + off_t to = to_d; + return (to != to_d)? SOX_EOF : lsx_seeki(ft, (byte_offset + to), SEEK_SET); +} + +/* Read and write known datatypes in "machine format". Swap if indicated. + * They all return SOX_EOF on error and SOX_SUCCESS on success. + */ +/* Read n-char string (and possibly null-terminating). + * Stop reading and null-terminate string if either a 0 or \n is reached. + */ +int lsx_reads(sox_format_t * ft, char *c, size_t len) +{ + char *sc; + char in; + + sc = c; + do + { + if (lsx_readbuf(ft, &in, (size_t)1) != 1) + { + *sc = 0; + return (SOX_EOF); + } + if (in == 0 || in == '\n') + break; + + *sc = in; + sc++; + } while (sc - c < (ptrdiff_t)len); + *sc = 0; + return(SOX_SUCCESS); +} + +/* Write null-terminated string (without \0). */ +int lsx_writes(sox_format_t * ft, char const * c) +{ + if (lsx_writebuf(ft, c, strlen(c)) != strlen(c)) + return(SOX_EOF); + return(SOX_SUCCESS); +} + +/* return swapped 32-bit float */ +static void lsx_swapf(float * f) +{ + union { + uint32_t dw; + float f; + } u; + + u.f= *f; + u.dw= (u.dw>>24) | ((u.dw>>8)&0xff00) | ((u.dw<<8)&0xff0000) | (u.dw<<24); + *f = u.f; +} + +static void swap(void * data, size_t len) +{ + uint8_t * bytes = (uint8_t *)data; + size_t i; + + for (i = 0; i < len / 2; ++i) { + char tmp = bytes[i]; + bytes[i] = bytes[len - 1 - i]; + bytes[len - 1 - i] = tmp; + } +} + +static double lsx_swapdf(double data) +{ + swap(&data, sizeof(data)); + return data; +} + +static uint64_t lsx_swapqw(uint64_t data) +{ + swap(&data, sizeof(data)); + return data; +} + +/* Lookup table to reverse the bit order of a byte. ie MSB become LSB */ +static uint8_t const cswap[256] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, + 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4, + 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, + 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA, + 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, + 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1, + 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, + 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD, + 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, + 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7, + 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, + 0x3F, 0xBF, 0x7F, 0xFF +}; + +/* Utilities to byte-swap values, use libc optimized macros if possible */ +#define TWIDDLE_BYTE(ub, type) \ + do { \ + if (ft->encoding.reverse_bits) \ + ub = cswap[ub]; \ + if (ft->encoding.reverse_nibbles) \ + ub = ((ub & 15) << 4) | (ub >> 4); \ + } while (0); + +#define TWIDDLE_WORD(uw, type) \ + if (ft->encoding.reverse_bytes) \ + uw = lsx_swap ## type(uw); + +#define TWIDDLE_FLOAT(f, type) \ + if (ft->encoding.reverse_bytes) \ + lsx_swapf(&f); + +/* N.B. This macro doesn't work for unaligned types (e.g. 3-byte + types). */ +#define READ_FUNC(type, size, ctype, twiddle) \ + size_t lsx_read_ ## type ## _buf( \ + sox_format_t * ft, ctype *buf, size_t len) \ + { \ + size_t n, nread; \ + nread = lsx_readbuf(ft, buf, len * size) / size; \ + for (n = 0; n < nread; n++) \ + twiddle(buf[n], type); \ + return nread; \ + } + +/* Unpack a 3-byte value from a uint8_t * */ +#define sox_unpack3(p) (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? \ + ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16)) : \ + ((p)[2] | ((p)[1] << 8) | ((p)[0] << 16))) + +/* This (slower) macro works for unaligned types (e.g. 3-byte types) + that need to be unpacked. */ +#define READ_FUNC_UNPACK(type, size, ctype, twiddle) \ + size_t lsx_read_ ## type ## _buf( \ + sox_format_t * ft, ctype *buf, size_t len) \ + { \ + size_t n, nread; \ + uint8_t *data = lsx_malloc(size * len); \ + nread = lsx_readbuf(ft, data, len * size) / size; \ + for (n = 0; n < nread; n++) \ + buf[n] = sox_unpack ## size(data + n * size); \ + free(data); \ + return n; \ + } + +READ_FUNC(b, 1, uint8_t, TWIDDLE_BYTE) +READ_FUNC(w, 2, uint16_t, TWIDDLE_WORD) +READ_FUNC_UNPACK(3, 3, sox_uint24_t, TWIDDLE_WORD) +READ_FUNC(dw, 4, uint32_t, TWIDDLE_WORD) +READ_FUNC(qw, 8, uint64_t, TWIDDLE_WORD) +READ_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT) +READ_FUNC(df, sizeof(double), double, TWIDDLE_WORD) + +#define READ1_FUNC(type, ctype) \ +int lsx_read ## type(sox_format_t * ft, ctype * datum) { \ + if (lsx_read_ ## type ## _buf(ft, datum, (size_t)1) == 1) \ + return SOX_SUCCESS; \ + if (!lsx_error(ft)) \ + lsx_fail_errno(ft, errno, premature_eof); \ + return SOX_EOF; \ +} + +static char const premature_eof[] = "premature EOF"; + +READ1_FUNC(b, uint8_t) +READ1_FUNC(w, uint16_t) +READ1_FUNC(3, sox_uint24_t) +READ1_FUNC(dw, uint32_t) +READ1_FUNC(qw, uint64_t) +READ1_FUNC(f, float) +READ1_FUNC(df, double) + +int lsx_readchars(sox_format_t * ft, char * chars, size_t len) +{ + size_t ret = lsx_readbuf(ft, chars, len); + if (ret == len) + return SOX_SUCCESS; + if (!lsx_error(ft)) + lsx_fail_errno(ft, errno, premature_eof); + return SOX_EOF; +} + +int lsx_read_fields(sox_format_t *ft, uint32_t *len, const char *spec, ...) +{ + int err = SOX_SUCCESS; + va_list ap; + +#define do_read(type, f, n) do { \ + size_t nr; \ + if (*len < n * sizeof(type)) { \ + err = SOX_EOF; \ + goto end; \ + } \ + nr = lsx_read_##f##_buf(ft, va_arg(ap, type *), r); \ + if (nr != n) \ + err = SOX_EOF; \ + *len -= nr * sizeof(type); \ + } while (0) + + va_start(ap, spec); + + while (*spec) { + unsigned long r = 1; + char c = *spec; + + if (c >= '0' && c <= '9') { + char *next; + r = strtoul(spec, &next, 10); + spec = next; + c = *spec; + } else if (c == '*') { + r = va_arg(ap, int); + c = *++spec; + } + + switch (c) { + case 'b': do_read(uint8_t, b, r); break; + case 'h': do_read(uint16_t, w, r); break; + case 'i': do_read(uint32_t, dw, r); break; + case 'q': do_read(uint64_t, qw, r); break; + case 'x': err = lsx_skipbytes(ft, r); break; + + default: + lsx_fail("lsx_read_fields: invalid format character '%c'", c); + err = SOX_EOF; + break; + } + + if (err) + break; + + spec++; + } + +end: + va_end(ap); + +#undef do_read + + return err; +} + +/* N.B. This macro doesn't work for unaligned types (e.g. 3-byte + types). */ +#define WRITE_FUNC(type, size, ctype, twiddle) \ + size_t lsx_write_ ## type ## _buf( \ + sox_format_t * ft, ctype *buf, size_t len) \ + { \ + size_t n, nwritten; \ + for (n = 0; n < len; n++) \ + twiddle(buf[n], type); \ + nwritten = lsx_writebuf(ft, buf, len * size); \ + return nwritten / size; \ + } + +/* Pack a 3-byte value to a uint8_t * */ +#define sox_pack3(p, v) do {if (ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN)\ +{(p)[0] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[2] = (v >> 16) & 0xff;} else \ +{(p)[2] = v & 0xff; (p)[1] = (v >> 8) & 0xff; (p)[0] = (v >> 16) & 0xff;} \ +} while (0) + +/* This (slower) macro works for unaligned types (e.g. 3-byte types) + that need to be packed. */ +#define WRITE_FUNC_PACK(type, size, ctype, twiddle) \ + size_t lsx_write_ ## type ## _buf( \ + sox_format_t * ft, ctype *buf, size_t len) \ + { \ + size_t n, nwritten; \ + uint8_t *data = lsx_malloc(size * len); \ + for (n = 0; n < len; n++) \ + sox_pack ## size(data + n * size, buf[n]); \ + nwritten = lsx_writebuf(ft, data, len * size); \ + free(data); \ + return nwritten / size; \ + } + +WRITE_FUNC(b, 1, uint8_t, TWIDDLE_BYTE) +WRITE_FUNC(w, 2, uint16_t, TWIDDLE_WORD) +WRITE_FUNC_PACK(3, 3, sox_uint24_t, TWIDDLE_WORD) +WRITE_FUNC(dw, 4, uint32_t, TWIDDLE_WORD) +WRITE_FUNC(qw, 8, uint64_t, TWIDDLE_WORD) +WRITE_FUNC(f, sizeof(float), float, TWIDDLE_FLOAT) +WRITE_FUNC(df, sizeof(double), double, TWIDDLE_WORD) + +#define WRITE1U_FUNC(type, ctype) \ + int lsx_write ## type(sox_format_t * ft, unsigned d) \ + { ctype datum = (ctype)d; \ + return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \ + } + +#define WRITE1S_FUNC(type, ctype) \ + int lsx_writes ## type(sox_format_t * ft, signed d) \ + { ctype datum = (ctype)d; \ + return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \ + } + +#define WRITE1_FUNC(type, ctype) \ + int lsx_write ## type(sox_format_t * ft, ctype datum) \ + { \ + return lsx_write_ ## type ## _buf(ft, &datum, (size_t)1) == 1 ? SOX_SUCCESS : SOX_EOF; \ + } + +WRITE1U_FUNC(b, uint8_t) +WRITE1U_FUNC(w, uint16_t) +WRITE1U_FUNC(3, sox_uint24_t) +WRITE1U_FUNC(dw, uint32_t) +WRITE1_FUNC(qw, uint64_t) +WRITE1S_FUNC(b, uint8_t) +WRITE1S_FUNC(w, uint16_t) +WRITE1_FUNC(df, double) + +int lsx_writef(sox_format_t * ft, double datum) +{ + float f = datum; + return lsx_write_f_buf(ft, &f, (size_t) 1) == 1 ? SOX_SUCCESS : SOX_EOF; +} diff --git a/app/src/main/cpp/sox/g711.c b/app/src/main/cpp/sox/g711.c new file mode 100644 index 0000000..82ecf87 --- /dev/null +++ b/app/src/main/cpp/sox/g711.c @@ -0,0 +1,2421 @@ +/* libSoX G711.c - G711 u-law, A-law and linear PCM conversions. + * + * Copyright (C) 2001 Chris Bagwell + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + +#include "sox_i.h" +#include "g711.h" + +const int16_t lsx_alaw2linear16[256] = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, + -4736, -7552, -7296, -8064, -7808, -6528, -6272, + -7040, -6784, -2752, -2624, -3008, -2880, -2240, + -2112, -2496, -2368, -3776, -3648, -4032, -3904, + -3264, -3136, -3520, -3392, -22016, -20992, -24064, + -23040, -17920, -16896, -19968, -18944, -30208, -29184, + -32256, -31232, -26112, -25088, -28160, -27136, -11008, + -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, + -13568, -344, -328, -376, -360, -280, -264, + -312, -296, -472, -456, -504, -488, -408, + -392, -440, -424, -88, -72, -120, -104, + -24, -8, -56, -40, -216, -200, -248, + -232, -152, -136, -184, -168, -1376, -1312, + -1504, -1440, -1120, -1056, -1248, -1184, -1888, + -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, + -592, -944, -912, -1008, -976, -816, -784, + -880, -848, 5504, 5248, 6016, 5760, 4480, + 4224, 4992, 4736, 7552, 7296, 8064, 7808, + 6528, 6272, 7040, 6784, 2752, 2624, 3008, + 2880, 2240, 2112, 2496, 2368, 3776, 3648, + 4032, 3904, 3264, 3136, 3520, 3392, 22016, + 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, + 27136, 11008, 10496, 12032, 11520, 8960, 8448, + 9984, 9472, 15104, 14592, 16128, 15616, 13056, + 12544, 14080, 13568, 344, 328, 376, 360, + 280, 264, 312, 296, 472, 456, 504, + 488, 408, 392, 440, 424, 88, 72, + 120, 104, 24, 8, 56, 40, 216, + 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, + 1184, 1888, 1824, 2016, 1952, 1632, 1568, + 1760, 1696, 688, 656, 752, 720, 560, + 528, 624, 592, 944, 912, 1008, 976, + 816, 784, 880, 848 +}; + +const uint8_t lsx_13linear2alaw[0x2000] = { + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, + 0x6b, 0x6b, 0x6b, 0x6b, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, 0x68, + 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x6e, 0x6e, 0x6e, 0x6e, + 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, + 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, + 0x6d, 0x6d, 0x6d, 0x6d, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, + 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x60, 0x60, 0x60, 0x60, + 0x60, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, + 0x67, 0x67, 0x67, 0x67, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, + 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x7a, 0x7a, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7b, 0x7b, 0x78, 0x78, 0x78, 0x78, 0x79, 0x79, 0x79, 0x79, + 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7c, 0x7c, 0x7c, 0x7c, + 0x7d, 0x7d, 0x7d, 0x7d, 0x72, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x73, + 0x70, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x71, 0x76, 0x76, 0x76, 0x76, + 0x77, 0x77, 0x77, 0x77, 0x74, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x75, + 0x4a, 0x4a, 0x4b, 0x4b, 0x48, 0x48, 0x49, 0x49, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4c, 0x4c, 0x4d, 0x4d, 0x42, 0x42, 0x43, 0x43, 0x40, 0x40, 0x41, 0x41, + 0x46, 0x46, 0x47, 0x47, 0x44, 0x44, 0x45, 0x45, 0x5a, 0x5a, 0x5b, 0x5b, + 0x58, 0x58, 0x59, 0x59, 0x5e, 0x5e, 0x5f, 0x5f, 0x5c, 0x5c, 0x5d, 0x5d, + 0x52, 0x52, 0x53, 0x53, 0x50, 0x50, 0x51, 0x51, 0x56, 0x56, 0x57, 0x57, + 0x54, 0x54, 0x55, 0x55, 0xd5, 0xd5, 0xd4, 0xd4, 0xd7, 0xd7, 0xd6, 0xd6, + 0xd1, 0xd1, 0xd0, 0xd0, 0xd3, 0xd3, 0xd2, 0xd2, 0xdd, 0xdd, 0xdc, 0xdc, + 0xdf, 0xdf, 0xde, 0xde, 0xd9, 0xd9, 0xd8, 0xd8, 0xdb, 0xdb, 0xda, 0xda, + 0xc5, 0xc5, 0xc4, 0xc4, 0xc7, 0xc7, 0xc6, 0xc6, 0xc1, 0xc1, 0xc0, 0xc0, + 0xc3, 0xc3, 0xc2, 0xc2, 0xcd, 0xcd, 0xcc, 0xcc, 0xcf, 0xcf, 0xce, 0xce, + 0xc9, 0xc9, 0xc8, 0xc8, 0xcb, 0xcb, 0xca, 0xca, 0xf5, 0xf5, 0xf5, 0xf5, + 0xf4, 0xf4, 0xf4, 0xf4, 0xf7, 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf6, 0xf6, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, 0xf3, 0xf3, 0xf3, + 0xf2, 0xf2, 0xf2, 0xf2, 0xfd, 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xf9, 0xf9, 0xf9, 0xf9, + 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xfa, + 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, 0xe4, 0xe4, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe4, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, + 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, + 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, + 0xe2, 0xe2, 0xe2, 0xe2, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, 0xed, + 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xec, 0xef, 0xef, 0xef, 0xef, + 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, + 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, + 0xe8, 0xe8, 0xe8, 0xe8, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, 0xeb, + 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0xea, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa +}; + +const int16_t lsx_ulaw2linear16[256] = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, + -24956, -23932, -22908, -21884, -20860, -19836, -18812, + -17788, -16764, -15996, -15484, -14972, -14460, -13948, + -13436, -12924, -12412, -11900, -11388, -10876, -10364, + -9852, -9340, -8828, -8316, -7932, -7676, -7420, + -7164, -6908, -6652, -6396, -6140, -5884, -5628, + -5372, -5116, -4860, -4604, -4348, -4092, -3900, + -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, + -1980, -1884, -1820, -1756, -1692, -1628, -1564, + -1500, -1436, -1372, -1308, -1244, -1180, -1116, + -1052, -988, -924, -876, -844, -812, -780, + -748, -716, -684, -652, -620, -588, -556, + -524, -492, -460, -428, -396, -372, -356, + -340, -324, -308, -292, -276, -260, -244, + -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, + -8, 0, 32124, 31100, 30076, 29052, 28028, + 27004, 25980, 24956, 23932, 22908, 21884, 20860, + 19836, 18812, 17788, 16764, 15996, 15484, 14972, + 14460, 13948, 13436, 12924, 12412, 11900, 11388, + 10876, 10364, 9852, 9340, 8828, 8316, 7932, + 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, + 4092, 3900, 3772, 3644, 3516, 3388, 3260, + 3132, 3004, 2876, 2748, 2620, 2492, 2364, + 2236, 2108, 1980, 1884, 1820, 1756, 1692, + 1628, 1564, 1500, 1436, 1372, 1308, 1244, + 1180, 1116, 1052, 988, 924, 876, 844, + 812, 780, 748, 716, 684, 652, 620, + 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, + 260, 244, 228, 212, 196, 180, 164, + 148, 132, 120, 112, 104, 96, 88, + 80, 72, 64, 56, 48, 40, 32, + 24, 16, 8, 0 +}; + +const uint8_t lsx_14linear2ulaw[0x4000] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, + 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, + 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, + 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, + 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, + 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, + 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, + 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, + 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, + 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, + 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, + 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, + 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, + 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, + 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, + 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, + 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, 0x23, + 0x23, 0x23, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, 0x26, + 0x26, 0x26, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, + 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, + 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, + 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, + 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, + 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, 0x2c, + 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, + 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, + 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, + 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, + 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, + 0x35, 0x35, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, + 0x37, 0x37, 0x37, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, + 0x38, 0x38, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, + 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x39, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, + 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, + 0x3b, 0x3b, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, + 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, + 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, 0x3e, + 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, + 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x40, 0x40, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x40, 0x40, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x43, 0x43, + 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, 0x43, + 0x43, 0x43, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, + 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, + 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x45, 0x46, 0x46, + 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, 0x46, + 0x46, 0x46, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, + 0x47, 0x47, 0x47, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, + 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x49, 0x49, + 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, 0x49, + 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, + 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, + 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, 0x4c, + 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, + 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, + 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, + 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, + 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x51, 0x51, + 0x51, 0x51, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x52, 0x52, 0x52, + 0x52, 0x52, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x53, 0x54, 0x54, + 0x54, 0x54, 0x54, 0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, + 0x55, 0x55, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x56, 0x57, 0x57, + 0x57, 0x57, 0x57, 0x57, 0x57, 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, + 0x58, 0x58, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x59, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, 0x5b, + 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, + 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x60, 0x60, + 0x60, 0x60, 0x61, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x62, 0x63, 0x63, + 0x63, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x65, 0x66, 0x66, + 0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x68, 0x69, 0x69, + 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, + 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, + 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, + 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, + 0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0xff, 0xfe, 0xfe, 0xfd, + 0xfd, 0xfc, 0xfc, 0xfb, 0xfb, 0xfa, 0xfa, 0xf9, 0xf9, 0xf8, 0xf8, 0xf7, + 0xf7, 0xf6, 0xf6, 0xf5, 0xf5, 0xf4, 0xf4, 0xf3, 0xf3, 0xf2, 0xf2, 0xf1, + 0xf1, 0xf0, 0xf0, 0xef, 0xef, 0xef, 0xef, 0xee, 0xee, 0xee, 0xee, 0xed, + 0xed, 0xed, 0xed, 0xec, 0xec, 0xec, 0xec, 0xeb, 0xeb, 0xeb, 0xeb, 0xea, + 0xea, 0xea, 0xea, 0xe9, 0xe9, 0xe9, 0xe9, 0xe8, 0xe8, 0xe8, 0xe8, 0xe7, + 0xe7, 0xe7, 0xe7, 0xe6, 0xe6, 0xe6, 0xe6, 0xe5, 0xe5, 0xe5, 0xe5, 0xe4, + 0xe4, 0xe4, 0xe4, 0xe3, 0xe3, 0xe3, 0xe3, 0xe2, 0xe2, 0xe2, 0xe2, 0xe1, + 0xe1, 0xe1, 0xe1, 0xe0, 0xe0, 0xe0, 0xe0, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, + 0xdf, 0xdf, 0xdf, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xdd, + 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdc, 0xdc, 0xdc, 0xdc, 0xdc, + 0xdc, 0xdc, 0xdc, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xdb, 0xda, + 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xda, 0xd9, 0xd9, 0xd9, 0xd9, 0xd9, + 0xd9, 0xd9, 0xd9, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd8, 0xd7, + 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd7, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, + 0xd6, 0xd6, 0xd6, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd5, 0xd4, + 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd3, 0xd3, 0xd3, 0xd3, 0xd3, + 0xd3, 0xd3, 0xd3, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd2, 0xd1, + 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd1, 0xd0, 0xd0, 0xd0, 0xd0, 0xd0, + 0xd0, 0xd0, 0xd0, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, + 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xcf, 0xce, 0xce, 0xce, 0xce, 0xce, + 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, + 0xcd, 0xcd, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, + 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xcb, 0xca, + 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, 0xca, + 0xca, 0xca, 0xca, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, + 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc9, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, + 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc8, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, 0xc7, + 0xc7, 0xc7, 0xc7, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, + 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, + 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc5, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, 0xc4, + 0xc4, 0xc4, 0xc4, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, + 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc1, 0xc1, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, + 0xbf, 0xbf, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, + 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, + 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbd, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, 0xbc, + 0xbc, 0xbc, 0xbc, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, + 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, + 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xba, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, 0xb9, + 0xb9, 0xb9, 0xb9, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, + 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb8, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, + 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb7, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, 0xb6, + 0xb6, 0xb6, 0xb6, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, + 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb5, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, + 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb4, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, + 0xb3, 0xb3, 0xb3, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, + 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb2, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, + 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb1, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb0, + 0xb0, 0xb0, 0xb0, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, + 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xaf, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, + 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xae, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, 0xad, + 0xad, 0xad, 0xad, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, + 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, + 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xab, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xaa, 0xaa, 0xaa, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, + 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa9, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, + 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa8, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, 0xa7, + 0xa7, 0xa7, 0xa7, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, + 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, + 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa5, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, 0xa4, + 0xa4, 0xa4, 0xa4, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, + 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa3, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, + 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa2, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, 0xa1, + 0xa1, 0xa1, 0xa1, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, + 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0x9f, + 0x9f, 0x9f, 0x9f, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, + 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9e, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, + 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9d, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, 0x9c, + 0x9c, 0x9c, 0x9c, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, + 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9b, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, + 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, + 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, + 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x98, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, + 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, 0x96, + 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, + 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x95, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, + 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x94, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, 0x93, + 0x93, 0x93, 0x93, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, + 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x92, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, + 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x91, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, + 0x90, 0x90, 0x90, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, + 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8f, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, + 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8e, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, 0x8d, + 0x8d, 0x8d, 0x8d, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, + 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8c, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, + 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8b, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, 0x8a, + 0x8a, 0x8a, 0x8a, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, + 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x89, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, + 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, + 0x87, 0x87, 0x87, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, + 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x86, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, + 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x85, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, + 0x84, 0x84, 0x84, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, + 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, + 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, + 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80 +}; + +/* The following code was used to generate the lookup tables */ +#ifdef GENERATE_TABLES + +#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */ +#define QUANT_MASK (0xf) /* Quantization field mask. */ +#define NSEGS (8) /* Number of A-law segments. */ +#define SEG_SHIFT (4) /* Left shift for segment number. */ +#define SEG_MASK (0x70) /* Segment field mask. */ + +static const int16_t seg_aend[8] = {0x1F, 0x3F, 0x7F, 0xFF, + 0x1FF, 0x3FF, 0x7FF, 0xFFF}; +static const int16_t seg_uend[8] = {0x3F, 0x7F, 0xFF, 0x1FF, + 0x3FF, 0x7FF, 0xFFF, 0x1FFF}; + +static int16_t search( + int16_t val, + int16_t *table, + int size) +{ + int i; + + for (i = 0; i < size; i++) { + if (val <= *table++) + return (i); + } + return (size); +} + +/* + * linear2alaw() accepts an 13-bit signed integer and encodes it as A-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 13-bits. + * + * Linear Input Code Compressed Code + * ------------------------ --------------- + * 0000000wxyza 000wxyz + * 0000001wxyza 001wxyz + * 000001wxyzab 010wxyz + * 00001wxyzabc 011wxyz + * 0001wxyzabcd 100wxyz + * 001wxyzabcde 101wxyz + * 01wxyzabcdef 110wxyz + * 1wxyzabcdefg 111wxyz + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char sox_13linear2alaw( + int16_t pcm_val) /* 2's complement (13-bit range) */ +{ + int16_t mask; + short seg; + unsigned char aval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 3; */ + + if (pcm_val >= 0) { + mask = 0xD5; /* sign (7th) bit = 1 */ + } else { + mask = 0x55; /* sign bit = 0 */ + pcm_val = -pcm_val - 1; + } + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_aend, 8); + + /* Combine the sign, segment, and quantization bits. */ + + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + aval = (unsigned char) seg << SEG_SHIFT; + if (seg < 2) + aval |= (pcm_val >> 1) & QUANT_MASK; + else + aval |= (pcm_val >> seg) & QUANT_MASK; + return (aval ^ mask); + } +} + +/* + * alaw2linear() - Convert an A-law value to 16-bit signed linear PCM + * + */ +int16_t sox_alaw2linear16( + unsigned char a_val) +{ + int16_t t; + int16_t seg; + + a_val ^= 0x55; + + t = (a_val & QUANT_MASK) << 4; + seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT; + switch (seg) { + case 0: + t += 8; + break; + case 1: + t += 0x108; + break; + default: + t += 0x108; + t <<= seg - 1; + } + return ((a_val & SIGN_BIT) ? t : -t); +} + +#define BIAS (0x84) /* Bias for linear code. */ +#define CLIP 8159 + +/* + * linear2ulaw() accepts a 14-bit signed integer and encodes it as u-law data + * stored in a unsigned char. This function should only be called with + * the data shifted such that it only contains information in the lower + * 14-bits. + * + * In order to simplify the encoding process, the original linear magnitude + * is biased by adding 33 which shifts the encoding range from (0 - 8158) to + * (33 - 8191). The result can be seen in the following encoding table: + * + * Biased Linear Input Code Compressed Code + * ------------------------ --------------- + * 00000001wxyza 000wxyz + * 0000001wxyzab 001wxyz + * 000001wxyzabc 010wxyz + * 00001wxyzabcd 011wxyz + * 0001wxyzabcde 100wxyz + * 001wxyzabcdef 101wxyz + * 01wxyzabcdefg 110wxyz + * 1wxyzabcdefgh 111wxyz + * + * Each biased linear code has a leading 1 which identifies the segment + * number. The value of the segment number is equal to 7 minus the number + * of leading 0's. The quantization interval is directly available as the + * four bits wxyz. * The trailing bits (a - h) are ignored. + * + * Ordinarily the complement of the resulting code word is used for + * transmission, and so the code word is complemented before it is returned. + * + * For further information see John C. Bellamy's Digital Telephony, 1982, + * John Wiley & Sons, pps 98-111 and 472-476. + */ +unsigned char sox_14linear2ulaw( + int16_t pcm_val) /* 2's complement (14-bit range) */ +{ + int16_t mask; + int16_t seg; + unsigned char uval; + + /* Have calling software do it since its already doing a shift + * from 32-bits down to 16-bits. + */ + /* pcm_val = pcm_val >> 2; */ + + /* Get the sign and the magnitude of the value. */ + if (pcm_val < 0) { + pcm_val = -pcm_val; + mask = 0x7F; + } else { + mask = 0xFF; + } + if ( pcm_val > CLIP ) pcm_val = CLIP; /* clip the magnitude */ + pcm_val += (BIAS >> 2); + + /* Convert the scaled magnitude to segment number. */ + seg = search(pcm_val, seg_uend, 8); + + /* + * Combine the sign, segment, quantization bits; + * and complement the code word. + */ + if (seg >= 8) /* out of range, return maximum value. */ + return (unsigned char) (0x7F ^ mask); + else { + uval = (unsigned char) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF); + return (uval ^ mask); + } + +} + +/* + * ulaw2linear() - Convert a u-law value to 16-bit linear PCM + * + * First, a biased linear code is derived from the code word. An unbiased + * output can then be obtained by subtracting 33 from the biased code. + * + * Note that this function expects to be passed the complement of the + * original code word. This is in keeping with ISDN conventions. + */ +int16_t sox_ulaw2linear16( + unsigned char u_val) +{ + int16_t t; + + /* Complement to obtain normal u-law value. */ + u_val = ~u_val; + + /* + * Extract and bias the quantization bits. Then + * shift up by the segment number and subtract out the bias. + */ + t = ((u_val & QUANT_MASK) << 3) + BIAS; + t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT; + + return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS)); +} + +int main(void) +{ + int x, y, find2a = 0; + + y = 0; + printf("int16_t lsx_alaw2linear16[256] = {\n "); + for (x = 0; x < 256; x++) + { + printf("%8d,", sox_alaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t lsx_13linear2alaw[0x2000] = {\n "); + y = 0; + for (x = 0; x < 0x2000; x++) + { + printf(" 0x%02x,", sox_13linear2alaw((-0x1000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nint16_t lsx_ulaw2linear16[256] = {\n "); + y = 0; + for (x = 0; x < 256; x++) + { + printf("%8d,", sox_ulaw2linear16(x)); + y++; + if (y == 7) + { + y = 0; + printf("\n "); + } + } + + printf("\n};\n\nuint8_t lsx_14linear2ulaw[0x4000] = {\n "); + y = 0; + for (x = 0; x < 0x4000; x++) + { + printf(" 0x%02x,", sox_14linear2ulaw((-0x2000)+x)); + y++; + if (y == 12) + { + y = 0; + printf("\n "); + } + } + printf("\n};\n"); + +} +#endif diff --git a/app/src/main/cpp/sox/g711.h b/app/src/main/cpp/sox/g711.h new file mode 100644 index 0000000..06326e0 --- /dev/null +++ b/app/src/main/cpp/sox/g711.h @@ -0,0 +1,21 @@ +/* libSoX G711.h - include for G711 u-law and a-law conversion routines + * + * Copyright (C) 2001 Chris Bagwell + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + */ + +extern const uint8_t lsx_13linear2alaw[0x2000]; +extern const int16_t lsx_alaw2linear16[256]; +#define sox_13linear2alaw(sw) (lsx_13linear2alaw[((sw) + 0x1000)]) +#define sox_alaw2linear16(uc) (lsx_alaw2linear16[uc]) + +extern const uint8_t lsx_14linear2ulaw[0x4000]; +extern const int16_t lsx_ulaw2linear16[256]; +#define sox_14linear2ulaw(sw) (lsx_14linear2ulaw[((sw) + 0x2000)]) +#define sox_ulaw2linear16(uc) (lsx_ulaw2linear16[uc]) diff --git a/app/src/main/cpp/sox/g721.c b/app/src/main/cpp/sox/g721.c new file mode 100644 index 0000000..3a220b9 --- /dev/null +++ b/app/src/main/cpp/sox/g721.c @@ -0,0 +1,167 @@ +/* This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g721.c + * + * Description: + * + * g721_encoder(), g721_decoder() + * + * These routines comprise an implementation of the CCITT G.721 ADPCM + * coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which + * take advantage of work station attributes, such as hardware 2's + * complement arithmetic and large memory. Specifically, certain time + * consuming operations such as multiplications are replaced + * with lookup tables and software 2's complement operations are + * replaced with hardware 2's complement. + * + * The deviation from the bit level specification (lookup tables) + * preserves the bit level performance specifications. + * + * As outlined in the G.721 Recommendation, the algorithm is broken + * down into modules. Each section of code below is preceded by + * the name of the module which it is implementing. + * + */ + +#include "sox_i.h" +#include "g72x.h" +#include "g711.h" + +static const short qtab_721[7] = {-124, 80, 178, 246, 300, 349, 400}; +/* + * Maps G.721 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static const short _dqlntab[16] = {-2048, 4, 135, 213, 273, 323, 373, 425, + 425, 373, 323, 273, 213, 135, 4, -2048}; + +/* Maps G.721 code word to log of scale factor multiplier. */ +static const short _witab[16] = {-12, 18, 41, 64, 112, 198, 355, 1122, + 1122, 355, 198, 112, 64, 41, 18, -12}; +/* + * Maps G.721 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static const short _fitab[16] = {0, 0, 0, 0x200, 0x200, 0x200, 0x600, 0xE00, + 0xE00, 0x600, 0x200, 0x200, 0x200, 0, 0, 0}; + +/* + * g721_encoder() + * + * Encodes the input vale of linear PCM, A-law or u-law data sl and returns + * the resulting code. -1 is returned for unknown input coding value. + */ +int g721_encoder(int sl, int in_coding, struct g72x_state *state_ptr) +{ + short sezi, se, sez; /* ACCUM */ + short d; /* SUBTA */ + short sr; /* ADDB */ + short y; /* MIX */ + short dqsez; /* ADDC */ + short dq, i; + + switch (in_coding) { /* linearize input sample to 14-bit PCM */ + case AUDIO_ENCODING_ALAW: + sl = sox_alaw2linear16(sl) >> 2; + break; + case AUDIO_ENCODING_ULAW: + sl = sox_ulaw2linear16(sl) >> 2; + break; + case AUDIO_ENCODING_LINEAR: + sl >>= 2; /* 14-bit dynamic range */ + break; + default: + return (-1); + } + + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + se = (sezi + predictor_pole(state_ptr)) >> 1; /* estimated signal */ + + d = sl - se; /* estimation difference */ + + /* quantize the prediction difference */ + y = step_size(state_ptr); /* quantizer step size */ + i = quantize(d, y, qtab_721, 7); /* i = ADPCM code */ + + dq = reconstruct(i & 8, _dqlntab[i], y); /* quantized est diff */ + + sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconst. signal */ + + dqsez = sr + sez - se; /* pole prediction diff. */ + + update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); + + return (i); +} + +/* + * g721_decoder() + * + * Description: + * + * Decodes a 4-bit code of G.721 encoded data of i and + * returns the resulting linear PCM, A-law or u-law value. + * return -1 for unknown out_coding value. + */ +int g721_decoder(int i, int out_coding, struct g72x_state *state_ptr) +{ + short sezi, sei, sez, se; /* ACCUM */ + short y; /* MIX */ + short sr; /* ADDB */ + short dq; + short dqsez; + + i &= 0x0f; /* mask to get proper bits */ + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + y = step_size(state_ptr); /* dynamic quantizer step size */ + + dq = reconstruct(i & 0x08, _dqlntab[i], y); /* quantized diff. */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : se + dq; /* reconst. signal */ + + dqsez = sr - se + sez; /* pole prediction diff. */ + + update(4, y, _witab[i] << 5, _fitab[i], dq, sr, dqsez, state_ptr); + + switch (out_coding) { + case AUDIO_ENCODING_ALAW: + return (tandem_adjust_alaw(sr, se, y, i, 8, qtab_721)); + case AUDIO_ENCODING_ULAW: + return (tandem_adjust_ulaw(sr, se, y, i, 8, qtab_721)); + case AUDIO_ENCODING_LINEAR: + return (sr << 2); /* sr was 14-bit dynamic range */ + default: + return (-1); + } +} diff --git a/app/src/main/cpp/sox/g723_24.c b/app/src/main/cpp/sox/g723_24.c new file mode 100644 index 0000000..164093d --- /dev/null +++ b/app/src/main/cpp/sox/g723_24.c @@ -0,0 +1,151 @@ +/* This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g723_24.c + * + * Description: + * + * g723_24_encoder(), g723_24_decoder() + * + * These routines comprise an implementation of the CCITT G.723 24 Kbps + * ADPCM coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which take advantage + * of workstation attributes, such as hardware 2's complement arithmetic. + * + */ +#include "sox_i.h" +#include "g711.h" +#include "g72x.h" + +/* + * Maps G.723_24 code word to reconstructed scale factor normalized log + * magnitude values. + */ +static const short _dqlntab[8] = {-2048, 135, 273, 373, 373, 273, 135, -2048}; + +/* Maps G.723_24 code word to log of scale factor multiplier. */ +static const short _witab[8] = {-128, 960, 4384, 18624, 18624, 4384, 960, -128}; + +/* + * Maps G.723_24 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static const short _fitab[8] = {0, 0x200, 0x400, 0xE00, 0xE00, 0x400, 0x200, 0}; + +static const short qtab_723_24[3] = {8, 218, 331}; + +/* + * g723_24_encoder() + * + * Encodes a linear PCM, A-law or u-law input sample and returns its 3-bit code. + * Returns -1 if invalid input coding value. + */ +int g723_24_encoder(int sl, int in_coding, struct g72x_state *state_ptr) +{ + short sei, sezi, se, sez; /* ACCUM */ + short d; /* SUBTA */ + short y; /* MIX */ + short sr; /* ADDB */ + short dqsez; /* ADDC */ + short dq, i; + + switch (in_coding) { /* linearize input sample to 14-bit PCM */ + case AUDIO_ENCODING_ALAW: + sl = sox_alaw2linear16(sl) >> 2; + break; + case AUDIO_ENCODING_ULAW: + sl = sox_ulaw2linear16(sl) >> 2; + break; + case AUDIO_ENCODING_LINEAR: + sl >>= 2; /* sl of 14-bit dynamic range */ + break; + default: + return (-1); + } + + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + d = sl - se; /* d = estimation diff. */ + + /* quantize prediction difference d */ + y = step_size(state_ptr); /* quantizer step size */ + i = quantize(d, y, qtab_723_24, 3); /* i = ADPCM code */ + dq = reconstruct(i & 4, _dqlntab[i], y); /* quantized diff. */ + + sr = (dq < 0) ? se - (dq & 0x3FFF) : se + dq; /* reconstructed signal */ + + dqsez = sr + sez - se; /* pole prediction diff. */ + + update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + return (i); +} + +/* + * g723_24_decoder() + * + * Decodes a 3-bit CCITT G.723_24 ADPCM code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + * -1 is returned if the output coding is unknown. + */ +int g723_24_decoder(int i, int out_coding, struct g72x_state *state_ptr) +{ + short sezi, sei, sez, se; /* ACCUM */ + short y; /* MIX */ + short sr; /* ADDB */ + short dq; + short dqsez; + + i &= 0x07; /* mask to get proper bits */ + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + y = step_size(state_ptr); /* adaptive quantizer step size */ + dq = reconstruct(i & 0x04, _dqlntab[i], y); /* unquantize pred diff */ + + sr = (dq < 0) ? (se - (dq & 0x3FFF)) : (se + dq); /* reconst. signal */ + + dqsez = sr - se + sez; /* pole prediction diff. */ + + update(3, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + switch (out_coding) { + case AUDIO_ENCODING_ALAW: + return (tandem_adjust_alaw(sr, se, y, i, 4, qtab_723_24)); + case AUDIO_ENCODING_ULAW: + return (tandem_adjust_ulaw(sr, se, y, i, 4, qtab_723_24)); + case AUDIO_ENCODING_LINEAR: + return (sr << 2); /* sr was of 14-bit dynamic range */ + default: + return (-1); + } +} diff --git a/app/src/main/cpp/sox/g723_40.c b/app/src/main/cpp/sox/g723_40.c new file mode 100644 index 0000000..b54ff80 --- /dev/null +++ b/app/src/main/cpp/sox/g723_40.c @@ -0,0 +1,171 @@ +/* This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g723_40.c + * + * Description: + * + * g723_40_encoder(), g723_40_decoder() + * + * These routines comprise an implementation of the CCITT G.723 40Kbps + * ADPCM coding algorithm. Essentially, this implementation is identical to + * the bit level description except for a few deviations which + * take advantage of workstation attributes, such as hardware 2's + * complement arithmetic. + * + * The deviation from the bit level specification (lookup tables), + * preserves the bit level performance specifications. + * + * As outlined in the G.723 Recommendation, the algorithm is broken + * down into modules. Each section of code below is preceded by + * the name of the module which it is implementing. + * + */ +#include "sox_i.h" +#include "g711.h" +#include "g72x.h" + +/* + * Maps G.723_40 code word to ructeconstructed scale factor normalized log + * magnitude values. + */ +static const short _dqlntab[32] = {-2048, -66, 28, 104, 169, 224, 274, 318, + 358, 395, 429, 459, 488, 514, 539, 566, + 566, 539, 514, 488, 459, 429, 395, 358, + 318, 274, 224, 169, 104, 28, -66, -2048}; + +/* Maps G.723_40 code word to log of scale factor multiplier. */ +static const short _witab[32] = {448, 448, 768, 1248, 1280, 1312, 1856, 3200, + 4512, 5728, 7008, 8960, 11456, 14080, 16928, 22272, + 22272, 16928, 14080, 11456, 8960, 7008, 5728, 4512, + 3200, 1856, 1312, 1280, 1248, 768, 448, 448}; + +/* + * Maps G.723_40 code words to a set of values whose long and short + * term averages are computed and then compared to give an indication + * how stationary (steady state) the signal is. + */ +static const short _fitab[32] = {0, 0, 0, 0, 0, 0x200, 0x200, 0x200, + 0x200, 0x200, 0x400, 0x600, 0x800, 0xA00, 0xC00, 0xC00, + 0xC00, 0xC00, 0xA00, 0x800, 0x600, 0x400, 0x200, 0x200, + 0x200, 0x200, 0x200, 0, 0, 0, 0, 0}; + +static const short qtab_723_40[15] = {-122, -16, 68, 139, 198, 250, 298, 339, + 378, 413, 445, 475, 502, 528, 553}; + +/* + * g723_40_encoder() + * + * Encodes a 16-bit linear PCM, A-law or u-law input sample and retuens + * the resulting 5-bit CCITT G.723 40Kbps code. + * Returns -1 if the input coding value is invalid. + */ +int g723_40_encoder(int sl, int in_coding, struct g72x_state *state_ptr) +{ + short sei, sezi, se, sez; /* ACCUM */ + short d; /* SUBTA */ + short y; /* MIX */ + short sr; /* ADDB */ + short dqsez; /* ADDC */ + short dq, i; + + switch (in_coding) { /* linearize input sample to 14-bit PCM */ + case AUDIO_ENCODING_ALAW: + sl = sox_alaw2linear16(sl) >> 2; + break; + case AUDIO_ENCODING_ULAW: + sl = sox_ulaw2linear16(sl) >> 2; + break; + case AUDIO_ENCODING_LINEAR: + sl >>= 2; /* sl of 14-bit dynamic range */ + break; + default: + return (-1); + } + + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + d = sl - se; /* d = estimation difference */ + + /* quantize prediction difference */ + y = step_size(state_ptr); /* adaptive quantizer step size */ + i = quantize(d, y, qtab_723_40, 15); /* i = ADPCM code */ + + dq = reconstruct(i & 0x10, _dqlntab[i], y); /* quantized diff */ + + sr = (dq < 0) ? se - (dq & 0x7FFF) : se + dq; /* reconstructed signal */ + + dqsez = sr + sez - se; /* dqsez = pole prediction diff. */ + + update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + return (i); +} + +/* + * g723_40_decoder() + * + * Decodes a 5-bit CCITT G.723 40Kbps code and returns + * the resulting 16-bit linear PCM, A-law or u-law sample value. + * -1 is returned if the output coding is unknown. + */ +int g723_40_decoder(int i, int out_coding, struct g72x_state *state_ptr) +{ + short sezi, sei, sez, se; /* ACCUM */ + short y; /* MIX */ + short sr; /* ADDB */ + short dq; + short dqsez; + + i &= 0x1f; /* mask to get proper bits */ + sezi = predictor_zero(state_ptr); + sez = sezi >> 1; + sei = sezi + predictor_pole(state_ptr); + se = sei >> 1; /* se = estimated signal */ + + y = step_size(state_ptr); /* adaptive quantizer step size */ + dq = reconstruct(i & 0x10, _dqlntab[i], y); /* estimation diff. */ + + sr = (dq < 0) ? (se - (dq & 0x7FFF)) : (se + dq); /* reconst. signal */ + + dqsez = sr - se + sez; /* pole prediction diff. */ + + update(5, y, _witab[i], _fitab[i], dq, sr, dqsez, state_ptr); + + switch (out_coding) { + case AUDIO_ENCODING_ALAW: + return (tandem_adjust_alaw(sr, se, y, i, 0x10, qtab_723_40)); + case AUDIO_ENCODING_ULAW: + return (tandem_adjust_ulaw(sr, se, y, i, 0x10, qtab_723_40)); + case AUDIO_ENCODING_LINEAR: + return (sr << 2); /* sr was of 14-bit dynamic range */ + default: + return (-1); + } +} diff --git a/app/src/main/cpp/sox/g72x.c b/app/src/main/cpp/sox/g72x.c new file mode 100644 index 0000000..3bf9a4b --- /dev/null +++ b/app/src/main/cpp/sox/g72x.c @@ -0,0 +1,575 @@ +/* Common routines for G.721 and G.723 conversions. + * + * (c) SoX Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * + * This code is based on code from Sun, which came with the following + * copyright notice: + * ----------------------------------------------------------------------- + * This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + * ----------------------------------------------------------------------- + */ + +#include "sox_i.h" +#include "g711.h" +#include "g72x.h" + +static const char LogTable256[] = +{ + 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +}; + +static inline int log2plus1(int val) +{ + /* From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLogLookup */ + unsigned int v = (unsigned int)val; /* 32-bit word to find the log of */ + unsigned r; /* r will be lg(v) */ + register unsigned int t, tt; /* temporaries */ + + if ((tt = v >> 16)) + { + r = (t = tt >> 8) ? 24 + LogTable256[t] : 16 + LogTable256[tt]; + } + else + { + r = (t = v >> 8) ? 8 + LogTable256[t] : LogTable256[v]; + } + + return r + 1; +} + +/* + * quan() + * + * quantizes the input val against the table of size short integers. + * It returns i if table[i - 1] <= val < table[i]. + * + * Using linear search for simple coding. + */ +static int quan(int val, short const *table, int size) +{ + int i; + + for (i = 0; i < size; i++) + if (val < *table++) + break; + return (i); +} + +/* + * fmult() + * + * returns the integer product of the 14-bit integer "an" and + * "floating point" representation (4-bit exponent, 6-bit mantessa) "srn". + */ +static int fmult(int an, int srn) +{ + short anmag, anexp, anmant; + short wanexp, wanmant; + short retval; + + anmag = (an > 0) ? an : ((-an) & 0x1FFF); + anexp = log2plus1(anmag) - 6; + anmant = (anmag == 0) ? 32 : + (anexp >= 0) ? anmag >> anexp : anmag << -anexp; + wanexp = anexp + ((srn >> 6) & 0xF) - 13; + + wanmant = (anmant * (srn & 077) + 0x30) >> 4; + retval = (wanexp >= 0) ? ((wanmant << wanexp) & 0x7FFF) : + (wanmant >> -wanexp); + + return (((an ^ srn) < 0) ? -retval : retval); +} + +/* + * g72x_init_state() + * + * This routine initializes and/or resets the g72x_state structure + * pointed to by 'state_ptr'. + * All the initial state values are specified in the CCITT G.721 document. + */ +void g72x_init_state(struct g72x_state *state_ptr) +{ + int cnta; + + state_ptr->yl = 34816; + state_ptr->yu = 544; + state_ptr->dms = 0; + state_ptr->dml = 0; + state_ptr->ap = 0; + for (cnta = 0; cnta < 2; cnta++) { + state_ptr->a[cnta] = 0; + state_ptr->pk[cnta] = 0; + state_ptr->sr[cnta] = 32; + } + for (cnta = 0; cnta < 6; cnta++) { + state_ptr->b[cnta] = 0; + state_ptr->dq[cnta] = 32; + } + state_ptr->td = 0; +} + +/* + * predictor_zero() + * + * computes the estimated signal from 6-zero predictor. + * + */ +int predictor_zero(struct g72x_state *state_ptr) +{ + int i; + int sezi; + + sezi = fmult(state_ptr->b[0] >> 2, state_ptr->dq[0]); + for (i = 1; i < 6; i++) /* ACCUM */ + sezi += fmult(state_ptr->b[i] >> 2, state_ptr->dq[i]); + return (sezi); +} +/* + * predictor_pole() + * + * computes the estimated signal from 2-pole predictor. + * + */ +int predictor_pole(struct g72x_state *state_ptr) +{ + return (fmult(state_ptr->a[1] >> 2, state_ptr->sr[1]) + + fmult(state_ptr->a[0] >> 2, state_ptr->sr[0])); +} +/* + * step_size() + * + * computes the quantization step size of the adaptive quantizer. + * + */ +int step_size(struct g72x_state *state_ptr) +{ + int y; + int dif; + int al; + + if (state_ptr->ap >= 256) + return (state_ptr->yu); + else { + y = state_ptr->yl >> 6; + dif = state_ptr->yu - y; + al = state_ptr->ap >> 2; + if (dif > 0) + y += (dif * al) >> 6; + else if (dif < 0) + y += (dif * al + 0x3F) >> 6; + return (y); + } +} + +/* + * quantize() + * + * Given a raw sample, 'd', of the difference signal and a + * quantization step size scale factor, 'y', this routine returns the + * ADPCM codeword to which that sample gets quantized. The step + * size scale factor division operation is done in the log base 2 domain + * as a subtraction. + */ +int quantize(int d, int y, short const *table, int size) +{ + short dqm; /* Magnitude of 'd' */ + short exp; /* Integer part of base 2 log of 'd' */ + short mant; /* Fractional part of base 2 log */ + short dl; /* Log of magnitude of 'd' */ + short dln; /* Step size scale factor normalized log */ + int i; + + /* + * LOG + * + * Compute base 2 log of 'd', and store in 'dl'. + */ + dqm = abs(d); + exp = log2plus1(dqm >> 1); + mant = ((dqm << 7) >> exp) & 0x7F; /* Fractional portion. */ + dl = (exp << 7) + mant; + + /* + * SUBTB + * + * "Divide" by step size multiplier. + */ + dln = dl - (y >> 2); + + /* + * QUAN + * + * Obtain codword i for 'd'. + */ + i = quan(dln, table, size); + if (d < 0) /* take 1's complement of i */ + return ((size << 1) + 1 - i); + else if (i == 0) /* take 1's complement of 0 */ + return ((size << 1) + 1); /* new in 1988 */ + else + return (i); +} +/* + * reconstruct() + * + * Returns reconstructed difference signal 'dq' obtained from + * codeword 'i' and quantization step size scale factor 'y'. + * Multiplication is performed in log base 2 domain as addition. + */ +int reconstruct(int sign, int dqln, int y) +{ + short dql; /* Log of 'dq' magnitude */ + short dex; /* Integer part of log */ + short dqt; + short dq; /* Reconstructed difference signal sample */ + + dql = dqln + (y >> 2); /* ADDA */ + + if (dql < 0) { + return ((sign) ? -0x8000 : 0); + } else { /* ANTILOG */ + dex = (dql >> 7) & 15; + dqt = 128 + (dql & 127); + dq = (dqt << 7) >> (14 - dex); + return ((sign) ? (dq - 0x8000) : dq); + } +} + + +/* + * update() + * + * updates the state variables for each output code + */ +void update(int code_size, int y, int wi, int fi, int dq, int sr, + int dqsez, struct g72x_state *state_ptr) +{ + int cnt; + short mag, exp; /* Adaptive predictor, FLOAT A */ + short a2p=0; /* LIMC */ + short a1ul; /* UPA1 */ + short pks1; /* UPA2 */ + short fa1; + char tr; /* tone/transition detector */ + short ylint, thr2, dqthr; + short ylfrac, thr1; + short pk0; + + pk0 = (dqsez < 0) ? 1 : 0; /* needed in updating predictor poles */ + + mag = dq & 0x7FFF; /* prediction difference magnitude */ + /* TRANS */ + ylint = state_ptr->yl >> 15; /* exponent part of yl */ + ylfrac = (state_ptr->yl >> 10) & 0x1F; /* fractional part of yl */ + thr1 = (32 + ylfrac) << ylint; /* threshold */ + thr2 = (ylint > 9) ? 31 << 10 : thr1; /* limit thr2 to 31 << 10 */ + dqthr = (thr2 + (thr2 >> 1)) >> 1; /* dqthr = 0.75 * thr2 */ + if (state_ptr->td == 0) /* signal supposed voice */ + tr = 0; + else if (mag <= dqthr) /* supposed data, but small mag */ + tr = 0; /* treated as voice */ + else /* signal is data (modem) */ + tr = 1; + + /* + * Quantizer scale factor adaptation. + */ + + /* FUNCTW & FILTD & DELAY */ + /* update non-steady state step size multiplier */ + state_ptr->yu = y + ((wi - y) >> 5); + + /* LIMB */ + if (state_ptr->yu < 544) /* 544 <= yu <= 5120 */ + state_ptr->yu = 544; + else if (state_ptr->yu > 5120) + state_ptr->yu = 5120; + + /* FILTE & DELAY */ + /* update steady state step size multiplier */ + state_ptr->yl += state_ptr->yu + ((-state_ptr->yl) >> 6); + + /* + * Adaptive predictor coefficients. + */ + if (tr == 1) { /* reset a's and b's for modem signal */ + state_ptr->a[0] = 0; + state_ptr->a[1] = 0; + state_ptr->b[0] = 0; + state_ptr->b[1] = 0; + state_ptr->b[2] = 0; + state_ptr->b[3] = 0; + state_ptr->b[4] = 0; + state_ptr->b[5] = 0; + } else { /* update a's and b's */ + pks1 = pk0 ^ state_ptr->pk[0]; /* UPA2 */ + + /* update predictor pole a[1] */ + a2p = state_ptr->a[1] - (state_ptr->a[1] >> 7); + if (dqsez != 0) { + fa1 = (pks1) ? state_ptr->a[0] : -state_ptr->a[0]; + if (fa1 < -8191) /* a2p = function of fa1 */ + a2p -= 0x100; + else if (fa1 > 8191) + a2p += 0xFF; + else + a2p += fa1 >> 5; + + if (pk0 ^ state_ptr->pk[1]) + { + /* LIMC */ + if (a2p <= -12160) + a2p = -12288; + else if (a2p >= 12416) + a2p = 12288; + else + a2p -= 0x80; + } + else if (a2p <= -12416) + a2p = -12288; + else if (a2p >= 12160) + a2p = 12288; + else + a2p += 0x80; + } + + /* Possible bug: a2p not initialized if dqsez == 0) */ + /* TRIGB & DELAY */ + state_ptr->a[1] = a2p; + + /* UPA1 */ + /* update predictor pole a[0] */ + state_ptr->a[0] -= state_ptr->a[0] >> 8; + if (dqsez != 0) + { + if (pks1 == 0) + state_ptr->a[0] += 192; + else + state_ptr->a[0] -= 192; + } + /* LIMD */ + a1ul = 15360 - a2p; + if (state_ptr->a[0] < -a1ul) + state_ptr->a[0] = -a1ul; + else if (state_ptr->a[0] > a1ul) + state_ptr->a[0] = a1ul; + + /* UPB : update predictor zeros b[6] */ + for (cnt = 0; cnt < 6; cnt++) { + if (code_size == 5) /* for 40Kbps G.723 */ + state_ptr->b[cnt] -= state_ptr->b[cnt] >> 9; + else /* for G.721 and 24Kbps G.723 */ + state_ptr->b[cnt] -= state_ptr->b[cnt] >> 8; + if (dq & 0x7FFF) { /* XOR */ + if ((dq ^ state_ptr->dq[cnt]) >= 0) + state_ptr->b[cnt] += 128; + else + state_ptr->b[cnt] -= 128; + } + } + } + + for (cnt = 5; cnt > 0; cnt--) + state_ptr->dq[cnt] = state_ptr->dq[cnt-1]; + /* FLOAT A : convert dq[0] to 4-bit exp, 6-bit mantissa f.p. */ + if (mag == 0) { + state_ptr->dq[0] = (dq >= 0) ? 0x20 : (short)(unsigned short)0xFC20; + } else { + exp = log2plus1(mag); + state_ptr->dq[0] = (dq >= 0) ? + (exp << 6) + ((mag << 6) >> exp) : + (exp << 6) + ((mag << 6) >> exp) - 0x400; + } + + state_ptr->sr[1] = state_ptr->sr[0]; + /* FLOAT B : convert sr to 4-bit exp., 6-bit mantissa f.p. */ + if (sr == 0) { + state_ptr->sr[0] = 0x20; + } else if (sr > 0) { + exp = log2plus1(sr); + state_ptr->sr[0] = (exp << 6) + ((sr << 6) >> exp); + } else if (sr > -32768) { + mag = -sr; + exp = log2plus1(mag); + state_ptr->sr[0] = (exp << 6) + ((mag << 6) >> exp) - 0x400; + } else + state_ptr->sr[0] = (short)(unsigned short)0xFC20; + + /* DELAY A */ + state_ptr->pk[1] = state_ptr->pk[0]; + state_ptr->pk[0] = pk0; + + /* TONE */ + if (tr == 1) /* this sample has been treated as data */ + state_ptr->td = 0; /* next one will be treated as voice */ + else if (a2p < -11776) /* small sample-to-sample correlation */ + state_ptr->td = 1; /* signal may be data */ + else /* signal is voice */ + state_ptr->td = 0; + + /* + * Adaptation speed control. + */ + state_ptr->dms += (fi - state_ptr->dms) >> 5; /* FILTA */ + state_ptr->dml += (((fi << 2) - state_ptr->dml) >> 7); /* FILTB */ + + if (tr == 1) + state_ptr->ap = 256; + else if (y < 1536) /* SUBTC */ + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else if (state_ptr->td == 1) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else if (abs((state_ptr->dms << 2) - state_ptr->dml) >= + (state_ptr->dml >> 3)) + state_ptr->ap += (0x200 - state_ptr->ap) >> 4; + else + state_ptr->ap += (-state_ptr->ap) >> 4; +} + +/* + * tandem_adjust(sr, se, y, i, sign) + * + * At the end of ADPCM decoding, it simulates an encoder which may be receiving + * the output of this decoder as a tandem process. If the output of the + * simulated encoder differs from the input to this decoder, the decoder output + * is adjusted by one level of A-law or u-law codes. + * + * Input: + * sr decoder output linear PCM sample, + * se predictor estimate sample, + * y quantizer step size, + * i decoder input code, + * sign sign bit of code i + * + * Return: + * adjusted A-law or u-law compressed sample. + */ +int tandem_adjust_alaw(int sr, int se, int y, int i, int sign, short const *qtab) +{ + unsigned char sp; /* A-law compressed 8-bit code */ + short dx; /* prediction error */ + char id; /* quantized prediction error */ + int sd; /* adjusted A-law decoded sample value */ + int im; /* biased magnitude of i */ + int imx; /* biased magnitude of id */ + + if (sr <= -32768) + sr = -1; + sp = sox_13linear2alaw(((sr >> 1) << 3));/* short to A-law compression */ + dx = (sox_alaw2linear16(sp) >> 2) - se; /* 16-bit prediction error */ + id = quantize(dx, y, qtab, sign - 1); + + if (id == i) { /* no adjustment on sp */ + return (sp); + } else { /* sp adjustment needed */ + /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ + im = i ^ sign; /* 2's complement to biased unsigned */ + imx = id ^ sign; + + if (imx > im) { /* sp adjusted to next lower value */ + if (sp & 0x80) { + sd = (sp == 0xD5) ? 0x55 : + ((sp ^ 0x55) - 1) ^ 0x55; + } else { + sd = (sp == 0x2A) ? 0x2A : + ((sp ^ 0x55) + 1) ^ 0x55; + } + } else { /* sp adjusted to next higher value */ + if (sp & 0x80) + sd = (sp == 0xAA) ? 0xAA : + ((sp ^ 0x55) + 1) ^ 0x55; + else + sd = (sp == 0x55) ? 0xD5 : + ((sp ^ 0x55) - 1) ^ 0x55; + } + return (sd); + } +} + +int tandem_adjust_ulaw(int sr, int se, int y, int i, int sign, short const *qtab) +{ + unsigned char sp; /* u-law compressed 8-bit code */ + short dx; /* prediction error */ + char id; /* quantized prediction error */ + int sd; /* adjusted u-law decoded sample value */ + int im; /* biased magnitude of i */ + int imx; /* biased magnitude of id */ + + if (sr <= -32768) + sr = 0; + sp = sox_14linear2ulaw((sr << 2));/* short to u-law compression */ + dx = (sox_ulaw2linear16(sp) >> 2) - se; /* 16-bit prediction error */ + id = quantize(dx, y, qtab, sign - 1); + if (id == i) { + return (sp); + } else { + /* ADPCM codes : 8, 9, ... F, 0, 1, ... , 6, 7 */ + im = i ^ sign; /* 2's complement to biased unsigned */ + imx = id ^ sign; + if (imx > im) { /* sp adjusted to next lower value */ + if (sp & 0x80) + sd = (sp == 0xFF) ? 0x7E : sp + 1; + else + sd = (sp == 0) ? 0 : sp - 1; + + } else { /* sp adjusted to next higher value */ + if (sp & 0x80) + sd = (sp == 0x80) ? 0x80 : sp - 1; + else + sd = (sp == 0x7F) ? 0xFE : sp + 1; + } + return (sd); + } +} diff --git a/app/src/main/cpp/sox/g72x.h b/app/src/main/cpp/sox/g72x.h new file mode 100644 index 0000000..7e8d5f2 --- /dev/null +++ b/app/src/main/cpp/sox/g72x.h @@ -0,0 +1,157 @@ +/* This source code is a product of Sun Microsystems, Inc. and is provided + * for unrestricted use. Users may copy or modify this source code without + * charge. + * + * SUN SOURCE CODE IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING + * THE WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun source code is provided with no support and without any obligation on + * the part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS SOFTWARE + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +/* + * g72x.h + * + * Header file for CCITT conversion routines. + * + */ +#ifndef _G72X_H +#define _G72X_H + +/* aliases */ +#define g721_decoder lsx_g721_decoder +#define g721_encoder lsx_g721_encoder +#define g723_24_decoder lsx_g723_24_decoder +#define g723_24_encoder lsx_g723_24_encoder +#define g723_40_decoder lsx_g723_40_decoder +#define g723_40_encoder lsx_g723_40_encoder +#define g72x_init_state lsx_g72x_init_state +#define predictor_pole lsx_g72x_predictor_pole +#define predictor_zero lsx_g72x_predictor_zero +#define quantize lsx_g72x_quantize +#define reconstruct lsx_g72x_reconstruct +#define step_size lsx_g72x_step_size +#define tandem_adjust_alaw lsx_g72x_tandem_adjust_alaw +#define tandem_adjust_ulaw lsx_g72x_tandem_adjust_ulaw +#define update lsx_g72x_update + +#define AUDIO_ENCODING_ULAW (1) /* ISDN u-law */ +#define AUDIO_ENCODING_ALAW (2) /* ISDN A-law */ +#define AUDIO_ENCODING_LINEAR (3) /* PCM 2's-complement (0-center) */ + +/* + * The following is the definition of the state structure + * used by the G.721/G.723 encoder and decoder to preserve their internal + * state between successive calls. The meanings of the majority + * of the state structure fields are explained in detail in the + * CCITT Recommendation G.721. The field names are essentially indentical + * to variable names in the bit level description of the coding algorithm + * included in this Recommendation. + */ +struct g72x_state { + long yl; /* Locked or steady state step size multiplier. */ + short yu; /* Unlocked or non-steady state step size multiplier. */ + short dms; /* Short term energy estimate. */ + short dml; /* Long term energy estimate. */ + short ap; /* Linear weighting coefficient of 'yl' and 'yu'. */ + + short a[2]; /* Coefficients of pole portion of prediction filter. */ + short b[6]; /* Coefficients of zero portion of prediction filter. */ + short pk[2]; /* + * Signs of previous two samples of a partially + * reconstructed signal. + */ + short dq[6]; /* + * Previous 6 samples of the quantized difference + * signal represented in an internal floating point + * format. + */ + short sr[2]; /* + * Previous 2 samples of the quantized difference + * signal represented in an internal floating point + * format. + */ + char td; /* delayed tone detect, new in 1988 version */ +}; + +/* External function definitions. */ + +extern void g72x_init_state(struct g72x_state *); +extern int g721_encoder( + int sample, + int in_coding, + struct g72x_state *state_ptr); +extern int g721_decoder( + int code, + int out_coding, + struct g72x_state *state_ptr); +extern int g723_16_encoder( + int sample, + int in_coding, + struct g72x_state *state_ptr); +extern int g723_16_decoder( + int code, + int out_coding, + struct g72x_state *state_ptr); +extern int g723_24_encoder( + int sample, + int in_coding, + struct g72x_state *state_ptr); +extern int g723_24_decoder( + int code, + int out_coding, + struct g72x_state *state_ptr); +extern int g723_40_encoder( + int sample, + int in_coding, + struct g72x_state *state_ptr); +extern int g723_40_decoder( + int code, + int out_coding, + struct g72x_state *state_ptr); + +int predictor_zero(struct g72x_state *state_ptr); +int predictor_pole(struct g72x_state *state_ptr); +int step_size(struct g72x_state *state_ptr); +int quantize(int d, + int y, + short const *table, + int size); +int reconstruct(int sign, + int dqln, + int y); +void update(int code_size, + int y, + int wi, + int fi, + int dq, + int sr, + int dqsez, + struct g72x_state *state_ptr); +int tandem_adjust_alaw(int sr, + int se, + int y, + int i, + int sign, + short const *qtab); +int tandem_adjust_ulaw(int sr, + int se, + int y, + int i, + int sign, + short const *qtab); +#endif /* !_G72X_H */ diff --git a/app/src/main/cpp/sox/gain.c b/app/src/main/cpp/sox/gain.c new file mode 100644 index 0000000..6975a07 --- /dev/null +++ b/app/src/main/cpp/sox/gain.c @@ -0,0 +1,276 @@ +/* libSoX effect: gain/norm/etc. (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define LSX_EFF_ALIAS +#include "sox_i.h" +#include +#include + +typedef struct { + sox_bool do_equalise, do_balance, do_balance_no_clip, do_limiter; + sox_bool do_restore, make_headroom, do_normalise, do_scan; + double fixed_gain; /* Valid only in channel 0 */ + + double mult, reclaim, rms, limiter; + off_t num_samples; + sox_sample_t min, max; + FILE * tmp_file; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + char const * q; + for (--argc, ++argv; argc && **argv == '-' && argv[0][1] && + !isdigit((unsigned char)argv[0][1]) && argv[0][1] != '.'; --argc, ++argv) + for (q = &argv[0][1]; *q; ++q) switch (*q) { + case 'n': p->do_scan = p->do_normalise = sox_true; break; + case 'e': p->do_scan = p->do_equalise = sox_true; break; + case 'B': p->do_scan = p->do_balance = sox_true; break; + case 'b': p->do_scan = p->do_balance_no_clip = sox_true; break; + case 'r': p->do_scan = p->do_restore = sox_true; break; + case 'h': p->make_headroom = sox_true; break; + case 'l': p->do_limiter = sox_true; break; + default: lsx_fail("invalid option `-%c'", *q); return lsx_usage(effp); + } + if ((p->do_equalise + p->do_balance + p->do_balance_no_clip + p->do_restore)/ sox_true > 1) { + lsx_fail("only one of -e, -B, -b, -r may be given"); + return SOX_EOF; + } + if (p->do_normalise && p->do_restore) { + lsx_fail("only one of -n, -r may be given"); + return SOX_EOF; + } + if (p->do_limiter && p->make_headroom) { + lsx_fail("only one of -l, -h may be given"); + return SOX_EOF; + } + do {NUMERIC_PARAMETER(fixed_gain, -HUGE_VAL, HUGE_VAL)} while (0); + p->fixed_gain = dB_to_linear(p->fixed_gain); + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + + if (effp->flow == 0) { + if (p->do_restore) { + if (!effp->in_signal.mult || *effp->in_signal.mult >= 1) { + lsx_fail("can't reclaim headroom"); + return SOX_EOF; + } + p->reclaim = 1 / *effp->in_signal.mult; + } + effp->out_signal.mult = p->make_headroom? &p->fixed_gain : NULL; + if (!p->do_equalise && !p->do_balance && !p->do_balance_no_clip) + effp->flows = 1; /* essentially a conditional SOX_EFF_MCHAN */ + } + p->mult = 0; + p->max = 1; + p->min = -1; + if (p->do_scan) { + p->tmp_file = lsx_tmpfile(); + if (p->tmp_file == NULL) { + lsx_fail("can't create temporary file: %s", strerror(errno)); + return SOX_EOF; + } + } + if (p->do_limiter) + p->limiter = (1 - 1 / p->fixed_gain) * (1. / SOX_SAMPLE_MAX); + else if (p->fixed_gain == floor(p->fixed_gain) && !p->do_scan) + effp->out_signal.precision = effp->in_signal.precision; + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len; + + if (p->do_scan) { + if (fwrite(ibuf, sizeof(*ibuf), *isamp, p->tmp_file) != *isamp) { + lsx_fail("error writing temporary file: %s", strerror(errno)); + return SOX_EOF; + } + if (p->do_balance && !p->do_normalise) + for (len = *isamp; len; --len, ++ibuf) { + double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips); + p->rms += sqr(d); + ++p->num_samples; + } + else if (p->do_balance || p->do_balance_no_clip) + for (len = *isamp; len; --len, ++ibuf) { + double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf, effp->clips); + p->rms += sqr(d); + ++p->num_samples; + p->max = max(p->max, *ibuf); + p->min = min(p->min, *ibuf); + } + else for (len = *isamp; len; --len, ++ibuf) { + p->max = max(p->max, *ibuf); + p->min = min(p->min, *ibuf); + } + *osamp = 0; /* samples not output until drain */ + } + else { + double mult = ((priv_t *)(effp - effp->flow)->priv)->fixed_gain; + len = *isamp = *osamp = min(*isamp, *osamp); + if (!p->do_limiter) for (; len; --len, ++ibuf) + *obuf++ = SOX_ROUND_CLIP_COUNT(*ibuf * mult, effp->clips); + else for (; len; --len, ++ibuf) { + double d = *ibuf * mult; + *obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 : + d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0; + } + } + return SOX_SUCCESS; +} + +static void start_drain(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + double max = SOX_SAMPLE_MAX, max_peak = 0, max_rms = 0; + size_t i; + + if (p->do_balance || p->do_balance_no_clip) { + for (i = 0; i < effp->flows; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + max_rms = max(max_rms, sqrt(q->rms / q->num_samples)); + rewind(q->tmp_file); + } + for (i = 0; i < effp->flows; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + double this_rms = sqrt(q->rms / q->num_samples); + double this_peak = max(q->max / max, q->min / (double)SOX_SAMPLE_MIN); + q->mult = this_rms != 0? max_rms / this_rms : 1; + max_peak = max(max_peak, q->mult * this_peak); + q->mult *= p->fixed_gain; + } + if (p->do_normalise || (p->do_balance_no_clip && max_peak > 1)) + for (i = 0; i < effp->flows; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + q->mult /= max_peak; + } + } else if (p->do_equalise && !p->do_normalise) { + for (i = 0; i < effp->flows; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + double this_peak = max(q->max / max, q->min / (double)SOX_SAMPLE_MIN); + max_peak = max(max_peak, this_peak); + q->mult = p->fixed_gain / this_peak; + rewind(q->tmp_file); + } + for (i = 0; i < effp->flows; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + q->mult *= max_peak; + } + } else { + p->mult = min(max / p->max, (double)SOX_SAMPLE_MIN / p->min); + if (p->do_restore) { + if (p->reclaim > p->mult) + lsx_report("%.3gdB not reclaimed", linear_to_dB(p->reclaim / p->mult)); + else p->mult = p->reclaim; + } + p->mult *= p->fixed_gain; + rewind(p->tmp_file); + } +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len; + int result = SOX_SUCCESS; + + *osamp -= *osamp % effp->in_signal.channels; + + if (p->do_scan) { + if (!p->mult) + start_drain(effp); + len = fread(obuf, sizeof(*obuf), *osamp, p->tmp_file); + if (len != *osamp && !feof(p->tmp_file)) { + lsx_fail("error reading temporary file: %s", strerror(errno)); + result = SOX_EOF; + } + if (!p->do_limiter) for (*osamp = len; len; --len, ++obuf) + *obuf = SOX_ROUND_CLIP_COUNT(*obuf * p->mult, effp->clips); + else for (*osamp = len; len; --len) { + double d = *obuf * p->mult; + *obuf++ = d < 0 ? 1 / (1 / d - p->limiter) - .5 : + d > 0 ? 1 / (1 / d + p->limiter) + .5 : 0; + } + } + else *osamp = 0; + return result; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + if (p->do_scan) + fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */ + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_gain_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "gain", NULL, SOX_EFF_GAIN, + create, start, flow, drain, stop, NULL, sizeof(priv_t)}; + static char const * lines[] = { + "[-e|-b|-B|-r] [-n] [-l|-h] [gain-dB]", + "-e\t Equalise channels: peak to that with max peak;", + "-B\t Balance channels: rms to that with max rms; no clip protection", + "-b\t Balance channels: rms to that with max rms; clip protection", + "\t Note -Bn = -bn", + "-r\t Reclaim headroom (as much as possible without clipping); see -h", + "-n\t Norm file to 0dBfs(output precision); gain-dB, if present, usually <0", + "-l\t Use simple limiter", + "-h\t Apply attenuation for headroom for subsequent effects; gain-dB, if", + "\t present, is subject to reclaim by a subsequent gain -r", + "gain-dB\t Apply gain in dB", + }; + static char * usage; + handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); + return &handler; +} + +/*------------------ emulation of the old `normalise' effect -----------------*/ + +static int norm_getopts(sox_effect_t * effp, int argc, char * * argv) +{ + char * argv2[3]; + int argc2 = 2; + + argv2[0] = argv[0], --argc, ++argv; + argv2[1] = "-n"; + if (argc) + argv2[argc2++] = *argv, --argc, ++argv; + return argc? lsx_usage(effp) : + lsx_gain_effect_fn()->getopts(effp, argc2, argv2); +} + +sox_effect_handler_t const * lsx_norm_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_gain_effect_fn(); + handler.name = "norm"; + handler.usage = "[level]"; + handler.getopts = norm_getopts; + return &handler; +} diff --git a/app/src/main/cpp/sox/getopt.c b/app/src/main/cpp/sox/getopt.c new file mode 100644 index 0000000..92ab0bb --- /dev/null +++ b/app/src/main/cpp/sox/getopt.c @@ -0,0 +1,349 @@ +/* lsx_getopt for SoX + * + * (c) 2011 Doug Cook and SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox.h" +#include +#include +#include + +void +lsx_getopt_init( + LSX_PARAM_IN int argc, /* Number of arguments in argv */ + LSX_PARAM_IN_COUNT(argc) char * const * argv, /* Array of arguments */ + LSX_PARAM_IN_Z char const * shortopts, /* Short option characters */ + LSX_PARAM_IN_OPT lsx_option_t const * longopts, /* Array of long option descriptors */ + LSX_PARAM_IN lsx_getopt_flags_t flags, /* Flags for longonly and opterr */ + LSX_PARAM_IN int first, /* First argument to check (usually 1) */ + LSX_PARAM_OUT lsx_getopt_t * state) /* State object to initialize */ +{ + assert(argc >= 0); + assert(argv != NULL); + assert(shortopts); + assert(first >= 0); + assert(first <= argc); + assert(state); + if (state) + { + if (argc < 0 || + !argv || + !shortopts || + first < 0 || + first > argc) + { + memset(state, 0, sizeof(*state)); + } + else + { + state->argc = argc; + state->argv = argv; + state->shortopts = + (shortopts[0] == '+' || shortopts[0] == '-') /* Requesting GNU special behavior? */ + ? shortopts + 1 /* Ignore request. */ + : shortopts; /* No special behavior requested. */ + state->longopts = longopts; + state->flags = flags; + state->curpos = NULL; + state->ind = first; + state->opt = '?'; + state->arg = NULL; + state->lngind = -1; + } + } +} + +static void CheckCurPosEnd( + LSX_PARAM_INOUT lsx_getopt_t * state) +{ + if (!state->curpos[0]) + { + state->curpos = NULL; + state->ind++; + } +} + +int +lsx_getopt( + LSX_PARAM_INOUT lsx_getopt_t * state) +{ + int oerr; + assert(state); + if (!state) + { + lsx_fail("lsx_getopt called with state=NULL"); + return -1; + } + + assert(state->argc >= 0); + assert(state->argv != NULL); + assert(state->shortopts); + assert(state->ind >= 0); + assert(state->ind <= state->argc + 1); + + oerr = 0 != (state->flags & lsx_getopt_flag_opterr); + state->opt = 0; + state->arg = NULL; + state->lngind = -1; + + if (state->argc < 0 || + !state->argv || + !state->shortopts || + state->ind < 0) + { /* programmer error */ + lsx_fail("lsx_getopt called with invalid information"); + state->curpos = NULL; + return -1; + } + else if ( + state->argc <= state->ind || + !state->argv[state->ind] || + state->argv[state->ind][0] != '-' || + state->argv[state->ind][1] == '\0') + { /* return no more options */ + state->curpos = NULL; + return -1; + } + else if (state->argv[state->ind][1] == '-' && state->argv[state->ind][2] == '\0') + { /* skip "--", return no more options. */ + state->curpos = NULL; + state->ind++; + return -1; + } + else + { /* Look for the next option */ + char const * current = state->argv[state->ind]; + char const * param = current + 1; + + if (state->curpos == NULL || + state->curpos <= param || + param + strlen(param) <= state->curpos) + { /* Start parsing a new parameter - check for a long option */ + state->curpos = NULL; + + if (state->longopts && + (param[0] == '-' || (state->flags & lsx_getopt_flag_longonly))) + { + size_t nameLen; + int doubleDash = param[0] == '-'; + if (doubleDash) + { + param++; + } + + for (nameLen = 0; param[nameLen] && param[nameLen] != '='; nameLen++) + {} + + /* For single-dash, you have to specify at least two letters in the name. */ + if (doubleDash || nameLen >= 2) + { + lsx_option_t const * pCur; + lsx_option_t const * pMatch = NULL; + int matches = 0; + + for (pCur = state->longopts; pCur->name; pCur++) + { + if (0 == strncmp(pCur->name, param, nameLen)) + { /* Prefix match. */ + matches++; + pMatch = pCur; + if (nameLen == strlen(pCur->name)) + { /* Exact match - no ambiguity, stop search. */ + matches = 1; + break; + } + } + } + + if (matches == 1) + { /* Matched. */ + state->ind++; + + if (param[nameLen]) + { /* --name=value */ + if (pMatch->has_arg) + { /* Required or optional arg - done. */ + state->arg = param + nameLen + 1; + } + else + { /* No arg expected. */ + if (oerr) + { + lsx_warn("`%s' did not expect an argument from `%s'", + pMatch->name, + current); + } + return '?'; + } + } + else if (pMatch->has_arg == lsx_option_arg_required) + { /* Arg required. */ + state->arg = state->argv[state->ind]; + state->ind++; + if (state->ind > state->argc) + { + if (oerr) + { + lsx_warn("`%s' requires an argument from `%s'", + pMatch->name, + current); + } + return state->shortopts[0] == ':' ? ':' : '?'; /* Missing required value. */ + } + } + + state->lngind = pMatch - state->longopts; + if (pMatch->flag) + { + *pMatch->flag = pMatch->val; + return 0; + } + else + { + return pMatch->val; + } + } + else if (matches == 0 && doubleDash) + { /* No match */ + if (oerr) + { + lsx_warn("parameter not recognized from `%s'", current); + } + state->ind++; + return '?'; + } + else if (matches > 1) + { /* Ambiguous. */ + if (oerr) + { + lsx_warn("parameter `%s' is ambiguous:", current); + for (pCur = state->longopts; pCur->name; pCur++) + { + if (0 == strncmp(pCur->name, param, nameLen)) + { + lsx_warn("parameter `%s' could be `--%s'", current, pCur->name); + } + } + } + state->ind++; + return '?'; + } + } + } + + state->curpos = param; + } + + state->opt = state->curpos[0]; + if (state->opt == ':') + { /* ':' is never a valid short option character */ + if (oerr) + { + lsx_warn("option `%c' not recognized", state->opt); + } + state->curpos++; + CheckCurPosEnd(state); + return '?'; /* unrecognized option */ + } + else + { /* Short option needs to be matched from option list */ + char const * pShortopt = strchr(state->shortopts, state->opt); + state->curpos++; + + if (!pShortopt) + { /* unrecognized option */ + if (oerr) + { + lsx_warn("option `%c' not recognized", state->opt); + } + CheckCurPosEnd(state); + return '?'; + } + else if (pShortopt[1] == ':' && state->curpos[0]) + { /* Return the rest of the parameter as the option's value */ + state->arg = state->curpos; + state->curpos = NULL; + state->ind++; + return state->opt; + } + else if (pShortopt[1] == ':' && pShortopt[2] != ':') + { /* Option requires a value */ + state->curpos = NULL; + state->ind++; + state->arg = state->argv[state->ind]; + state->ind++; + if (state->ind <= state->argc) + { /* A value was present, so we're good. */ + return state->opt; + } + else + { /* Missing required value. */ + if (oerr) + { + lsx_warn("option `%c' requires an argument", + state->opt); + } + return state->shortopts[0] == ':' ? ':' : '?'; + } + } + else + { /* Option without a value. */ + CheckCurPosEnd(state); + return state->opt; + } + } + } +} + +#ifdef TEST_GETOPT + +#include + +int main(int argc, char const * argv[]) +{ + static int help = 0; + static lsx_option_t longopts[] = + { + {"a11", 0, 0, 101}, + {"a12", 0, 0, 102}, + {"a122", 0, 0, 103}, + {"rarg", 1, 0, 104}, + {"oarg", 2, 0, 105}, + {"help", 0, &help, 106}, + {0} + }; + + int ch; + lsx_getopt_t state; + lsx_getopt_init(argc, argv, "abc:d:v::0123456789", longopts, sox_true, 1, &state); + + while (-1 != (ch = lsx_getopt(&state))) + { + printf( + "H=%d ch=%d, ind=%d opt=%d lng=%d arg=%s\n", + help, + ch, + state.ind, + state.opt, + state.lngind, + state.arg ? state.arg : "NULL"); + } + + return 0; +} + +#endif /* TEST_GETOPT */ diff --git a/app/src/main/cpp/sox/gsm.c b/app/src/main/cpp/sox/gsm.c new file mode 100644 index 0000000..0277d0c --- /dev/null +++ b/app/src/main/cpp/sox/gsm.c @@ -0,0 +1,247 @@ +/* Copyright 1991, 1992, 1993 Guido van Rossum And Sundry Contributors. + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Guido van Rossum And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +/* + * GSM 06.10 courtesy Communications and Operating Systems Research Group, + * Technische Universitaet Berlin + * + * Source code and more information on this format can be obtained from + * http://www.quut.com/gsm/ + * + * Written 26 Jan 1995 by Andrew Pam + * Portions Copyright (c) 1995 Serious Cybernetics + * + * July 19, 1998 - Chris Bagwell (cbagwell@sprynet.com) + * Added GSM support to SOX from patches floating around with the help + * of Dima Barsky (ess2db@ee.surrey.ac.uk). + * + * Nov. 26, 1999 - Stan Brooks (stabro@megsinet.com) + * Rewritten to support multiple channels + */ + +#include "sox_i.h" + +#ifdef HAVE_GSM_GSM_H +#include +#else +#include +#endif + +#include + +#define MAXCHANS 16 + +/* sizeof(gsm_frame) */ +#define FRAMESIZE (size_t)33 +/* samples per gsm_frame */ +#define BLOCKSIZE 160 + +/* Private data */ +typedef struct { + unsigned channels; + gsm_signal *samples; + gsm_signal *samplePtr; + gsm_signal *sampleTop; + gsm_byte *frames; + gsm handle[MAXCHANS]; +} priv_t; + +static int gsmstart_rw(sox_format_t * ft, int w) +{ + priv_t *p = (priv_t *) ft->priv; + unsigned ch; + + ft->encoding.encoding = SOX_ENCODING_GSM; + if (!ft->signal.rate) + ft->signal.rate = 8000; + + if (ft->signal.channels == 0) + ft->signal.channels = 1; + + p->channels = ft->signal.channels; + if (p->channels > MAXCHANS || p->channels <= 0) + { + lsx_fail_errno(ft,SOX_EFMT,"gsm: channels(%d) must be in 1-16", ft->signal.channels); + return(SOX_EOF); + } + + for (ch=0; chchannels; ch++) { + p->handle[ch] = gsm_create(); + if (!p->handle[ch]) + { + lsx_fail_errno(ft,errno,"unable to create GSM stream"); + return (SOX_EOF); + } + } + p->frames = lsx_malloc(p->channels*FRAMESIZE); + p->samples = lsx_malloc(BLOCKSIZE * (p->channels+1) * sizeof(gsm_signal)); + p->sampleTop = p->samples + BLOCKSIZE*p->channels; + p->samplePtr = (w)? p->samples : p->sampleTop; + return (SOX_SUCCESS); +} + +static int sox_gsmstartread(sox_format_t * ft) +{ + return gsmstart_rw(ft,0); +} + +static int sox_gsmstartwrite(sox_format_t * ft) +{ + return gsmstart_rw(ft,1); +} + +/* + * Read up to len samples from file. + * Convert to signed longs. + * Place in buf[]. + * Return number of samples read. + */ + +static size_t sox_gsmread(sox_format_t * ft, sox_sample_t *buf, size_t samp) +{ + size_t done = 0, r; + int ch, chans; + gsm_signal *gbuff; + priv_t *p = (priv_t *) ft->priv; + + chans = p->channels; + + while (done < samp) + { + while (p->samplePtr < p->sampleTop && done < samp) + buf[done++] = + SOX_SIGNED_16BIT_TO_SAMPLE(*(p->samplePtr)++,); + + if (done>=samp) break; + + r = lsx_readbuf(ft, p->frames, p->channels * FRAMESIZE); + if (r != p->channels * FRAMESIZE) + break; + + p->samplePtr = p->samples; + for (ch=0; chsampleTop; + if (gsm_decode(p->handle[ch], p->frames + ch*FRAMESIZE, gbuff) < 0) + { + lsx_fail_errno(ft,errno,"error during GSM decode"); + return (0); + } + + gsp = p->samples + ch; + for (i=0; ipriv; + + chans = p->channels; + + /* zero-fill samples as needed */ + while (p->samplePtr < p->sampleTop) + *(p->samplePtr)++ = 0; + + gbuff = p->sampleTop; + for (ch=0; chsamples + ch; + for (i=0; ihandle[ch], gbuff, p->frames); + r = lsx_writebuf(ft, p->frames, FRAMESIZE); + if (r != FRAMESIZE) + { + lsx_fail_errno(ft,errno,"write error"); + return(SOX_EOF); + } + } + p->samplePtr = p->samples; + + return (SOX_SUCCESS); +} + +static size_t sox_gsmwrite(sox_format_t * ft, const sox_sample_t *buf, size_t samp) +{ + size_t done = 0; + priv_t *p = (priv_t *) ft->priv; + + while (done < samp) + { + SOX_SAMPLE_LOCALS; + while ((p->samplePtr < p->sampleTop) && (done < samp)) + *(p->samplePtr)++ = + SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++], ft->clips); + + if (p->samplePtr == p->sampleTop) + { + if(gsmflush(ft)) + { + return 0; + } + } + } + + return done; +} + +static int sox_gsmstopread(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + unsigned ch; + + for (ch=0; chchannels; ch++) + gsm_destroy(p->handle[ch]); + + free(p->samples); + free(p->frames); + return (SOX_SUCCESS); +} + +static int sox_gsmstopwrite(sox_format_t * ft) +{ + int rc; + priv_t *p = (priv_t *) ft->priv; + + if (p->samplePtr > p->samples) + { + rc = gsmflush(ft); + if (rc) + return rc; + } + + return sox_gsmstopread(ft); /* destroy handles and free buffers */ +} + +LSX_FORMAT_HANDLER(gsm) +{ + static char const * const names[] = {"gsm", NULL}; + static sox_rate_t const write_rates[] = {8000, 0}; + static unsigned const write_encodings[] = {SOX_ENCODING_GSM, 0, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "GSM 06.10 (full-rate) lossy speech compression", names, 0, + sox_gsmstartread, sox_gsmread, sox_gsmstopread, + sox_gsmstartwrite, sox_gsmwrite, sox_gsmstopwrite, + NULL, write_encodings, write_rates, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/gsrt.c b/app/src/main/cpp/sox/gsrt.c new file mode 100644 index 0000000..6f4900e --- /dev/null +++ b/app/src/main/cpp/sox/gsrt.c @@ -0,0 +1,207 @@ +/* libSoX file format: Grandstream ring tone (c) 2009 robs@users.sourceforge.net + * + * See https://web.archive.org/web/20101128121923/http://grandstream.com/ringtone.html + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +#define VERSION_ 0x1000000 +#define MAX_FILE_SIZE 0x10000 +#define HEADER_SIZE (size_t)512 +#define PADDING_SIZE (size_t)478 + +static char const id[16] = "ring.bin"; + +typedef struct { + char const * string; + int ft_encoding; + unsigned bits_per_sample; + sox_encoding_t sox_encoding; +} table_t; + +static table_t const table[] = { + {NULL, 0, 8, SOX_ENCODING_ULAW}, + {"G726", 2, 0, SOX_ENCODING_UNKNOWN}, + {NULL, 3, 0, SOX_ENCODING_GSM}, + {NULL, 4, 0, SOX_ENCODING_G723}, + {NULL, 8, 8, SOX_ENCODING_ALAW}, + {"G722", 9, 0, SOX_ENCODING_UNKNOWN}, + {"G728", 15, 2, SOX_ENCODING_UNKNOWN}, + {"iLBC", 98, 0, SOX_ENCODING_UNKNOWN}, +}; + +static int ft_enc(unsigned bits_per_sample, sox_encoding_t encoding) +{ + size_t i; + for (i = 0; i < array_length(table); ++i) { + table_t const * t = &table[i]; + if (t->sox_encoding == encoding && t->bits_per_sample == bits_per_sample) + return t->ft_encoding; + } + return -1; /* Should never get here. */ +} + +static sox_encoding_t sox_enc(int ft_encoding, unsigned * bits_per_sample) +{ + size_t i; + for (i = 0; i < array_length(table); ++i) { + table_t const * t = &table[i]; + if (t->ft_encoding == ft_encoding) { + *bits_per_sample = t->bits_per_sample; + if (t->sox_encoding == SOX_ENCODING_UNKNOWN) + lsx_report("unsupported encoding: %s", t->string); + return t->sox_encoding; + } + } + *bits_per_sample = 0; + return SOX_ENCODING_UNKNOWN; +} + +static int start_read(sox_format_t * ft) +{ + off_t num_samples; + char read_id[array_length(id)]; + uint32_t file_size; + int16_t ft_encoding; + sox_encoding_t encoding; + unsigned bits_per_sample; + + lsx_readdw(ft, &file_size); + num_samples = file_size? file_size * 2 - HEADER_SIZE : SOX_UNSPEC; + + if (file_size >= 2 && ft->seekable) { + int i, checksum = (file_size >> 16) + file_size; + for (i = file_size - 2; i; --i) { + int16_t int16; + lsx_readsw(ft, &int16); + checksum += int16; + } + if (lsx_seeki(ft, (off_t)sizeof(file_size), SEEK_SET) != 0) + return SOX_EOF; + if (checksum & 0xffff) + lsx_warn("invalid checksum in input file %s", ft->filename); + } + + lsx_skipbytes(ft, (size_t)(2 + 4 + 6)); /* Checksum, version, time stamp. */ + + lsx_readchars(ft, read_id, sizeof(read_id)); + if (memcmp(read_id, id, strlen(id))) { + lsx_fail_errno(ft, SOX_EHDR, "gsrt: invalid file name in header"); + return SOX_EOF; + } + + lsx_readsw(ft, &ft_encoding); + encoding = sox_enc(ft_encoding, &bits_per_sample); + if (encoding != SOX_ENCODING_ALAW && + encoding != SOX_ENCODING_ULAW) + ft->handler.read = NULL; + + lsx_skipbytes(ft, PADDING_SIZE); + + return lsx_check_read_params(ft, 1, 8000., encoding, + bits_per_sample, (uint64_t)num_samples, sox_true); +} + +static int start_write(sox_format_t * ft) +{ + int i, encoding = ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding); + time_t now = sox_globals.repeatable? 0 : time(NULL); + struct tm const * t = sox_globals.repeatable? gmtime(&now) : localtime(&now); + + int checksum = (VERSION_ >> 16) + VERSION_; + checksum += t->tm_year + 1900; + checksum += ((t->tm_mon + 1) << 8) + t->tm_mday; + checksum += (t->tm_hour << 8) + t->tm_min; + for (i = sizeof(id) - 2; i >= 0; i -= 2) + checksum += (id[i] << 8) + id[i + 1]; + checksum += encoding; + + return lsx_writedw(ft, 0) + || lsx_writesw(ft, -checksum) + || lsx_writedw(ft, VERSION_) + || lsx_writesw(ft, t->tm_year + 1900) + || lsx_writesb(ft, t->tm_mon + 1) + || lsx_writesb(ft, t->tm_mday) + || lsx_writesb(ft, t->tm_hour) + || lsx_writesb(ft, t->tm_min) + || lsx_writechars(ft, id, sizeof(id)) + || lsx_writesw(ft, encoding) + || lsx_padbytes(ft, PADDING_SIZE) ? SOX_EOF : SOX_SUCCESS; +} + +static size_t write_samples( + sox_format_t * ft, sox_sample_t const * buf, size_t nsamp) +{ + size_t n = min(nsamp, MAX_FILE_SIZE - (size_t)ft->tell_off); + if (n != nsamp) + lsx_warn("audio truncated"); + return lsx_rawwrite(ft, buf, n); +} + +static int stop_write(sox_format_t * ft) +{ + long num_samples = ft->tell_off - HEADER_SIZE; + + if (num_samples & 1) { + sox_sample_t pad = 0; + lsx_rawwrite(ft, &pad, 1); + } + + if (ft->seekable) { + unsigned i, file_size = ft->tell_off >> 1; + int16_t int16; + int checksum; + if (!lsx_seeki(ft, (off_t)sizeof(uint32_t), SEEK_SET)) { + lsx_readsw(ft, &int16); + checksum = (file_size >> 16) + file_size - int16; + if (!lsx_seeki(ft, (off_t)HEADER_SIZE, SEEK_SET)) { + for (i = (num_samples + 1) >> 1; i; --i) { + lsx_readsw(ft, &int16); + checksum += int16; + } + if (!lsx_seeki(ft, (off_t)0, SEEK_SET)) { + lsx_writedw(ft, file_size); + lsx_writesw(ft, -checksum); + return SOX_SUCCESS; + } + } + } + } + lsx_warn("can't seek in output file `%s'; " + "length in file header will be unspecified", ft->filename); + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(gsrt) +{ + static char const *const names[] = { "gsrt", NULL }; + static sox_rate_t const write_rates[] = { 8000, 0 }; + static unsigned const write_encodings[] = { + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_ULAW, 8, 0, + 0 + }; + static sox_format_handler_t const handler = { + SOX_LIB_VERSION_CODE, "Grandstream ring tone", + names, SOX_FILE_BIG_END | SOX_FILE_MONO, + start_read, lsx_rawread, NULL, + start_write, write_samples, stop_write, + lsx_rawseek, write_encodings, write_rates, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/hcom.c b/app/src/main/cpp/sox/hcom.c new file mode 100644 index 0000000..594c870 --- /dev/null +++ b/app/src/main/cpp/sox/hcom.c @@ -0,0 +1,502 @@ +/* libSoX Macintosh HCOM format. + * These are really FSSD type files with Huffman compression, + * in MacBinary format. + * TODO: make the MacBinary format optional (so that .data files + * are also acceptable). (How to do this on output?) + * + * September 25, 1991 + * Copyright 1991 Guido van Rossum And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Guido van Rossum And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * April 28, 1998 - Chris Bagwell (cbagwell@sprynet.com) + * + * Rearranged some functions so that they are declared before they are + * used, clearing up some compiler warnings. Because these functions + * passed floats, it helped some dumb compilers pass stuff on the + * stack correctly. + * + */ + +#include "sox_i.h" +#include +#include +#include +#include + +/* FIXME: eliminate these 2 functions */ + +static void put32_be(unsigned char **p, int32_t val) +{ + *(*p)++ = (val >> 24) & 0xff; + *(*p)++ = (val >> 16) & 0xff; + *(*p)++ = (val >> 8) & 0xff; + *(*p)++ = val & 0xff; +} + +static void put16_be(unsigned char **p, int val) +{ + *(*p)++ = (val >> 8) & 0xff; + *(*p)++ = val & 0xff; +} + +/* Dictionary entry for Huffman (de)compression */ +typedef struct { + long frequ; + short dict_leftson; + short dict_rightson; +} dictent; + +typedef struct { + /* Static data from the header */ + dictent *dictionary; + int32_t checksum; + int deltacompression; + /* Engine state */ + long huffcount; + long cksum; + int dictentry; + int nrbits; + uint32_t current; + short sample; + /* Dictionary */ + dictent *de; + int32_t new_checksum; + int nbits; + int32_t curword; + + /* Private data used by writer */ + unsigned char *data; /* Buffer allocated with lsx_malloc */ + size_t size; /* Size of allocated buffer */ + size_t pos; /* Where next byte goes */ +} priv_t; + +static int dictvalid(int n, int size, int left, int right) +{ + if (n > 0 && left < 0) + return 1; + + return (unsigned)left < size && (unsigned)right < size; +} + +static int startread(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + int i; + char buf[5]; + uint32_t datasize, rsrcsize; + uint32_t huffcount, checksum, compresstype, divisor; + unsigned short dictsize; + int rc; + + + /* Skip first 65 bytes of header */ + rc = lsx_skipbytes(ft, (size_t) 65); + if (rc) + return rc; + + /* Check the file type (bytes 65-68) */ + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FSSD", (size_t)4) != 0) + { + lsx_fail_errno(ft,SOX_EHDR,"Mac header type is not FSSD"); + return (SOX_EOF); + } + + /* Skip to byte 83 */ + rc = lsx_skipbytes(ft, (size_t) 83-69); + if (rc) + return rc; + + /* Get essential numbers from the header */ + lsx_readdw(ft, &datasize); /* bytes 83-86 */ + lsx_readdw(ft, &rsrcsize); /* bytes 87-90 */ + + /* Skip the rest of the header (total 128 bytes) */ + rc = lsx_skipbytes(ft, (size_t) 128-91); + if (rc != 0) + return rc; + + /* The data fork must contain a "HCOM" header */ + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "HCOM", (size_t)4) != 0) + { + lsx_fail_errno(ft,SOX_EHDR,"Mac data fork is not HCOM"); + return (SOX_EOF); + } + + /* Then follow various parameters */ + lsx_readdw(ft, &huffcount); + lsx_readdw(ft, &checksum); + lsx_readdw(ft, &compresstype); + if (compresstype > 1) + { + lsx_fail_errno(ft,SOX_EHDR,"Bad compression type in HCOM header"); + return (SOX_EOF); + } + lsx_readdw(ft, &divisor); + if (divisor == 0 || divisor > 4) + { + lsx_fail_errno(ft,SOX_EHDR,"Bad sampling rate divisor in HCOM header"); + return (SOX_EOF); + } + lsx_readw(ft, &dictsize); + + /* Translate to sox parameters */ + ft->encoding.encoding = SOX_ENCODING_HCOM; + ft->encoding.bits_per_sample = 8; + ft->signal.rate = 22050 / divisor; + ft->signal.channels = 1; + ft->signal.length = huffcount; + + /* Allocate memory for the dictionary */ + p->dictionary = lsx_malloc(511 * sizeof(dictent)); + + /* Read dictionary */ + for(i = 0; i < dictsize; i++) { + lsx_readsw(ft, &(p->dictionary[i].dict_leftson)); + lsx_readsw(ft, &(p->dictionary[i].dict_rightson)); + lsx_debug("%d %d", + p->dictionary[i].dict_leftson, + p->dictionary[i].dict_rightson); + if (!dictvalid(i, dictsize, p->dictionary[i].dict_leftson, + p->dictionary[i].dict_rightson)) { + lsx_fail_errno(ft, SOX_EHDR, "Invalid dictionary"); + return SOX_EOF; + } + } + rc = lsx_skipbytes(ft, (size_t) 1); /* skip pad byte */ + if (rc) + return rc; + + /* Initialized the decompression engine */ + p->checksum = checksum; + p->deltacompression = compresstype; + if (!p->deltacompression) + lsx_debug("HCOM data using value compression"); + p->huffcount = huffcount; + p->cksum = 0; + p->dictentry = 0; + p->nrbits = -1; /* Special case to get first byte */ + + return (SOX_SUCCESS); +} + +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + register priv_t *p = (priv_t *) ft->priv; + int done = 0; + unsigned char sample_rate; + + if (p->nrbits < 0) { + /* The first byte is special */ + if (p->huffcount == 0) + return 0; /* Don't know if this can happen... */ + if (lsx_readb(ft, &sample_rate) == SOX_EOF) + { + return (0); + } + p->sample = sample_rate; + *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(p->sample,); + p->huffcount--; + p->nrbits = 0; + done++; + len--; + if (len == 0) + return done; + } + + while (p->huffcount > 0) { + if(p->nrbits == 0) { + lsx_readdw(ft, &(p->current)); + if (lsx_eof(ft)) + { + lsx_fail_errno(ft,SOX_EOF,"unexpected EOF in HCOM data"); + return (0); + } + p->cksum += p->current; + p->nrbits = 32; + } + if(p->current & 0x80000000) { + p->dictentry = + p->dictionary[p->dictentry].dict_rightson; + } else { + p->dictentry = + p->dictionary[p->dictentry].dict_leftson; + } + p->current = p->current << 1; + p->nrbits--; + if(p->dictionary[p->dictentry].dict_leftson < 0) { + short datum; + datum = p->dictionary[p->dictentry].dict_rightson; + if (!p->deltacompression) + p->sample = 0; + p->sample = (p->sample + datum) & 0xff; + p->huffcount--; + *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(p->sample,); + p->dictentry = 0; + done++; + len--; + if (len == 0) + break; + } + } + + return done; +} + +static int stopread(sox_format_t * ft) +{ + register priv_t *p = (priv_t *) ft->priv; + + if (p->huffcount != 0) + { + lsx_fail_errno(ft,SOX_EFMT,"not all HCOM data read"); + return (SOX_EOF); + } + if(p->cksum != p->checksum) + { + lsx_fail_errno(ft,SOX_EFMT,"checksum error in HCOM data"); + return (SOX_EOF); + } + free(p->dictionary); + p->dictionary = NULL; + return (SOX_SUCCESS); +} + +#define BUFINCR (10*BUFSIZ) + +static int startwrite(sox_format_t * ft) +{ + priv_t * p = (priv_t *) ft->priv; + + p->size = BUFINCR; + p->pos = 0; + p->data = lsx_malloc(p->size); + return SOX_SUCCESS; +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t *p = (priv_t *) ft->priv; + sox_sample_t datum; + size_t i; + + if (len == 0) + return 0; + + if (p->pos == INT32_MAX) + return SOX_EOF; + + if (p->pos + len > INT32_MAX) { + lsx_warn("maximum file size exceeded"); + len = INT32_MAX - p->pos; + } + + if (p->pos + len > p->size) { + p->size = ((p->pos + len) / BUFINCR + 1) * BUFINCR; + p->data = lsx_realloc(p->data, p->size); + } + + for (i = 0; i < len; i++) { + SOX_SAMPLE_LOCALS; + datum = *buf++; + p->data[p->pos++] = SOX_SAMPLE_TO_UNSIGNED_8BIT(datum, ft->clips); + } + + return len; +} + +static void makecodes(int e, int c, int s, int b, dictent newdict[511], long codes[256], long codesize[256]) +{ + assert(b); /* Prevent stack overflow */ + if (newdict[e].dict_leftson < 0) { + codes[newdict[e].dict_rightson] = c; + codesize[newdict[e].dict_rightson] = s; + } else { + makecodes(newdict[e].dict_leftson, c, s + 1, b << 1, newdict, codes, codesize); + makecodes(newdict[e].dict_rightson, c + b, s + 1, b << 1, newdict, codes, codesize); + } +} + +static void putcode(sox_format_t * ft, long codes[256], long codesize[256], unsigned c, unsigned char **df) +{ + priv_t *p = (priv_t *) ft->priv; + long code, size; + int i; + + code = codes[c]; + size = codesize[c]; + for(i = 0; i < size; i++) { + p->curword <<= 1; + if (code & 1) + p->curword += 1; + p->nbits++; + if (p->nbits == 32) { + put32_be(df, p->curword); + p->new_checksum += p->curword; + p->nbits = 0; + p->curword = 0; + } + code >>= 1; + } +} + +static void compress(sox_format_t * ft, unsigned char **df, int32_t *dl) +{ + priv_t *p = (priv_t *) ft->priv; + int samplerate; + unsigned char *datafork = *df; + unsigned char *ddf, *dfp; + short dictsize; + int frequtable[256]; + long codes[256], codesize[256]; + dictent newdict[511]; + int i, sample, j, k, d, l, frequcount; + int64_t csize; + + sample = *datafork; + memset(frequtable, 0, sizeof(frequtable)); + memset(codes, 0, sizeof(codes)); + memset(codesize, 0, sizeof(codesize)); + memset(newdict, 0, sizeof(newdict)); + + for (i = 1; i < *dl; i++) { + d = (datafork[i] - (sample & 0xff)) & 0xff; /* creates absolute entries LMS */ + sample = datafork[i]; + datafork[i] = d; + assert(d >= 0 && d <= 255); /* check our table is accessed correctly */ + frequtable[d]++; + } + p->de = newdict; + for (i = 0; i < 256; i++) + if (frequtable[i] != 0) { + p->de->frequ = -frequtable[i]; + p->de->dict_leftson = -1; + p->de->dict_rightson = i; + p->de++; + } + frequcount = p->de - newdict; + for (i = 0; i < frequcount; i++) { + for (j = i + 1; j < frequcount; j++) { + if (newdict[i].frequ > newdict[j].frequ) { + k = newdict[i].frequ; + newdict[i].frequ = newdict[j].frequ; + newdict[j].frequ = k; + k = newdict[i].dict_leftson; + newdict[i].dict_leftson = newdict[j].dict_leftson; + newdict[j].dict_leftson = k; + k = newdict[i].dict_rightson; + newdict[i].dict_rightson = newdict[j].dict_rightson; + newdict[j].dict_rightson = k; + } + } + } + while (frequcount > 1) { + j = frequcount - 1; + p->de->frequ = newdict[j - 1].frequ; + p->de->dict_leftson = newdict[j - 1].dict_leftson; + p->de->dict_rightson = newdict[j - 1].dict_rightson; + l = newdict[j - 1].frequ + newdict[j].frequ; + for (i = j - 2; i >= 0 && l < newdict[i].frequ; i--) + newdict[i + 1] = newdict[i]; + i = i + 1; + newdict[i].frequ = l; + newdict[i].dict_leftson = j; + newdict[i].dict_rightson = p->de - newdict; + p->de++; + frequcount--; + } + dictsize = p->de - newdict; + makecodes(0, 0, 0, 1, newdict, codes, codesize); + csize = 0; + for (i = 0; i < 256; i++) + csize += frequtable[i] * codesize[i]; + l = (((csize + 31) >> 5) << 2) + 24 + dictsize * 4; + lsx_debug(" Original size: %6d bytes", *dl); + lsx_debug("Compressed size: %6d bytes", l); + datafork = lsx_malloc((size_t)l); + ddf = datafork + 22; + for(i = 0; i < dictsize; i++) { + put16_be(&ddf, newdict[i].dict_leftson); + put16_be(&ddf, newdict[i].dict_rightson); + } + *ddf++ = 0; + *ddf++ = *(*df)++; + p->new_checksum = 0; + p->nbits = 0; + p->curword = 0; + for (i = 1; i < *dl; i++) + putcode(ft, codes, codesize, *(*df)++, &ddf); + if (p->nbits != 0) { + codes[0] = 0; + codesize[0] = 32 - p->nbits; + putcode(ft, codes, codesize, 0, &ddf); + } + memcpy(datafork, "HCOM", (size_t)4); + dfp = datafork + 4; + put32_be(&dfp, *dl); + put32_be(&dfp, p->new_checksum); + put32_be(&dfp, 1); + samplerate = 22050 / ft->signal.rate + .5; + put32_be(&dfp, samplerate); + put16_be(&dfp, dictsize); + *df = datafork; /* reassign passed pointer to new datafork */ + *dl = l; /* and its compressed length */ +} + +/* End of hcom utility routines */ + +static int stopwrite(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + unsigned char *compressed_data = p->data; + int32_t compressed_len = p->pos; + int rc = SOX_SUCCESS; + + /* Compress it all at once */ + if (compressed_len) { + compress(ft, &compressed_data, &compressed_len); + free(p->data); + } + + /* Write the header */ + lsx_writebuf(ft, "\000\001A", (size_t) 3); /* Dummy file name "A" */ + lsx_padbytes(ft, (size_t) 65-3); + lsx_writes(ft, "FSSD"); + lsx_padbytes(ft, (size_t) 83-69); + lsx_writedw(ft, (unsigned) compressed_len); /* compressed_data size */ + lsx_writedw(ft, 0); /* rsrc size */ + lsx_padbytes(ft, (size_t) 128 - 91); + if (lsx_error(ft)) { + lsx_fail_errno(ft, errno, "write error in HCOM header"); + rc = SOX_EOF; + } else if (lsx_writebuf(ft, compressed_data, compressed_len) != compressed_len) { + /* Write the compressed_data fork */ + lsx_fail_errno(ft, errno, "can't write compressed HCOM data"); + rc = SOX_EOF; + } + free(compressed_data); + + if (rc == SOX_SUCCESS) + /* Pad the compressed_data fork to a multiple of 128 bytes */ + lsx_padbytes(ft, 128u - (compressed_len % 128)); + + return rc; +} + +LSX_FORMAT_HANDLER(hcom) +{ + static char const * const names[] = {"hcom", NULL}; + static sox_rate_t const write_rates[] = {22050,22050/2,22050/3,22050/4.,0}; + static unsigned const write_encodings[] = { + SOX_ENCODING_HCOM, 8, 0, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Mac FSSD files with Huffman compression", + names, SOX_FILE_BIG_END|SOX_FILE_MONO, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + NULL, write_encodings, write_rates, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/hilbert.c b/app/src/main/cpp/sox/hilbert.c new file mode 100644 index 0000000..ae289f2 --- /dev/null +++ b/app/src/main/cpp/sox/hilbert.c @@ -0,0 +1,102 @@ +/* libSoX effect: Hilbert transform filter + * + * First version of this effect written 11/2011 by Ulrich Klauer, using maths + * from "Understanding digital signal processing" by Richard G. Lyons. + * + * Copyright 2011 Chris Bagwell and SoX Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "dft_filter.h" + +typedef struct { + dft_filter_priv_t base; + double *h; + int taps; +} priv_t; + +static int getopts(sox_effect_t *effp, int argc, char **argv) +{ + lsx_getopt_t optstate; + int c; + priv_t *p = (priv_t*)effp->priv; + dft_filter_priv_t *b = &p->base; + + b->filter_ptr = &b->filter; + + lsx_getopt_init(argc, argv, "+n:", NULL, lsx_getopt_flag_none, 1, &optstate); + + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + GETOPT_NUMERIC(optstate, 'n', taps, 3, 32767) + default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); + } + if (p->taps && p->taps%2 == 0) { + lsx_fail("only filters with an odd number of taps are supported"); + return SOX_EOF; + } + return optstate.ind != argc ? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t *effp) +{ + priv_t *p = (priv_t*)effp->priv; + dft_filter_t *f = p->base.filter_ptr; + + if (!f->num_taps) { + int i; + if (!p->taps) { + p->taps = effp->in_signal.rate/76.5 + 2; + p->taps += 1 - (p->taps%2); + /* results in a cutoff frequency of about 75 Hz with a Blackman window */ + lsx_debug("choosing number of taps = %d (override with -n)", p->taps); + } + lsx_valloc(p->h, p->taps); + for (i = 0; i < p->taps; i++) { + int k = -(p->taps/2) + i; + if (k%2 == 0) { + p->h[i] = 0.0; + } else { + double pk = M_PI * k; + p->h[i] = (1 - cos(pk))/pk; + } + } + lsx_apply_blackman(p->h, p->taps, .16); + + if (effp->global_info->plot != sox_plot_off) { + char title[100]; + sprintf(title, "SoX effect: hilbert (%d taps)", p->taps); + lsx_plot_fir(p->h, p->taps, effp->in_signal.rate, + effp->global_info->plot, title, -20., 5.); + free(p->h); + return SOX_EOF; + } + lsx_set_dft_filter(f, p->h, p->taps, p->taps/2); + } + return lsx_dft_filter_effect_fn()->start(effp); +} + +sox_effect_handler_t const *lsx_hilbert_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_dft_filter_effect_fn(); + handler.name = "hilbert"; + handler.usage = "[-n taps]"; + handler.getopts = getopts; + handler.start = start; + handler.priv_size = sizeof(priv_t); + return &handler; +} diff --git a/app/src/main/cpp/sox/htk.c b/app/src/main/cpp/sox/htk.c new file mode 100644 index 0000000..6390616 --- /dev/null +++ b/app/src/main/cpp/sox/htk.c @@ -0,0 +1,80 @@ +/* libSoX file format: HTK (c) 2008 robs@users.sourceforge.net + * + * See http://labrosa.ee.columbia.edu/doc/HTKBook21/HTKBook.html + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef enum { + Waveform, Lpc, Lprefc, Lpcepstra, Lpdelcep, Irefc, + Mfcc, Fbank, Melspec, User, Discrete, Unknown} kind_t; +static char const * const str[] = { + "Sampled waveform", "Linear prediction filter", "Linear prediction", + "LPC cepstral", "LPC cepstra plus delta", "LPC reflection coef in", + "Mel-frequency cepstral", "Log mel-filter bank", "Linear mel-filter bank", + "User defined sample", "Vector quantised data", "Unknown"}; + +static int start_read(sox_format_t * ft) +{ + uint32_t period_100ns, num_samples; + uint16_t bytes_per_sample, parmKind; + + if (lsx_readdw(ft, &num_samples ) || + lsx_readdw(ft, &period_100ns ) || + lsx_readw (ft, &bytes_per_sample) || + lsx_readw (ft, &parmKind )) return SOX_EOF; + if (parmKind != Waveform) { + int n = min(parmKind & 077, Unknown); + lsx_fail_errno(ft, SOX_EFMT, "unsupported HTK type `%s' (0%o)", str[n], parmKind); + return SOX_EOF; + } + return lsx_check_read_params(ft, 1, 1e7 / period_100ns, SOX_ENCODING_SIGN2, + (unsigned)bytes_per_sample << 3, (uint64_t)num_samples, sox_true); +} + +static int write_header(sox_format_t * ft) +{ + double period_100ns = 1e7 / ft->signal.rate; + uint64_t len = ft->olength? ft->olength:ft->signal.length; + + if (len > UINT_MAX) + { + lsx_warn("length greater than 32 bits - cannot fit actual length in header"); + len = UINT_MAX; + } + if (!ft->olength && floor(period_100ns) != period_100ns) + lsx_warn("rounding sample period %f (x 100ns) to nearest integer", period_100ns); + return lsx_writedw(ft, (unsigned)len) + || lsx_writedw(ft, (unsigned)(period_100ns + .5)) + || lsx_writew(ft, ft->encoding.bits_per_sample >> 3) + || lsx_writew(ft, Waveform) ? SOX_EOF : SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(htk) +{ + static char const * const names[] = {"htk", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0}; + static sox_format_handler_t handler = { + SOX_LIB_VERSION_CODE, + "PCM format used for Hidden Markov Model speech processing", + names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_REWIND, + start_read, lsx_rawread, NULL, + write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/id3.c b/app/src/main/cpp/sox/id3.c new file mode 100644 index 0000000..9cfb81c --- /dev/null +++ b/app/src/main/cpp/sox/id3.c @@ -0,0 +1,227 @@ +/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "id3.h" + +#ifdef HAVE_ID3TAG + +#include + +static char const * id3tagmap[][2] = +{ + {"TIT2", "Title"}, + {"TPE1", "Artist"}, + {"TALB", "Album"}, + {"TCOM", "Composer"}, + {"TRCK", "Tracknumber"}, + {"TDRC", "Year"}, + {"TCON", "Genre"}, + {"COMM", "Comment"}, + {"TPOS", "Discnumber"}, + {NULL, NULL} +}; + +static id3_utf8_t * utf8_id3tag_findframe( + struct id3_tag * tag, const char * const frameid, unsigned index) +{ + struct id3_frame const * frame = id3_tag_findframe(tag, frameid, index); + if (frame) { + unsigned nfields = frame->nfields; + + while (nfields--) { + union id3_field const *field = id3_frame_field(frame, nfields); + int ftype = id3_field_type(field); + const id3_ucs4_t *ucs4 = NULL; + unsigned nstrings; + + switch (ftype) { + case ID3_FIELD_TYPE_STRING: + ucs4 = id3_field_getstring(field); + break; + + case ID3_FIELD_TYPE_STRINGFULL: + ucs4 = id3_field_getfullstring(field); + break; + + case ID3_FIELD_TYPE_STRINGLIST: + nstrings = id3_field_getnstrings(field); + while (nstrings--) { + ucs4 = id3_field_getstrings(field, nstrings); + if (ucs4) + break; + } + break; + } + + if (ucs4) + return id3_ucs4_utf8duplicate(ucs4); /* Must call free() on this */ + } + } + return NULL; +} + +struct tag_info_node +{ + struct tag_info_node * next; + off_t start; + off_t end; +}; + +struct tag_info { + sox_format_t * ft; + struct tag_info_node * head; + struct id3_tag * tag; +}; + +static int add_tag(struct tag_info * info) +{ + struct tag_info_node * current; + off_t start, end; + id3_byte_t query[ID3_TAG_QUERYSIZE]; + id3_byte_t * buffer; + long size; + int result = 0; + + /* Ensure we're at the start of a valid tag and get its size. */ + if (ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) || + !(size = id3_tag_query(query, ID3_TAG_QUERYSIZE))) { + return 0; + } + if (size < 0) { + if (0 != lsx_seeki(info->ft, size, SEEK_CUR) || + ID3_TAG_QUERYSIZE != lsx_readbuf(info->ft, query, ID3_TAG_QUERYSIZE) || + (size = id3_tag_query(query, ID3_TAG_QUERYSIZE)) <= 0) { + return 0; + } + } + + /* Don't read a tag more than once. */ + start = lsx_tell(info->ft); + end = start + size; + for (current = info->head; current; current = current->next) { + if (start == current->start && end == current->end) { + return 1; + } else if (start < current->end && current->start < end) { + return 0; + } + } + + buffer = lsx_malloc((size_t)size); + if (!buffer) { + return 0; + } + memcpy(buffer, query, ID3_TAG_QUERYSIZE); + if ((unsigned long)size - ID3_TAG_QUERYSIZE == + lsx_readbuf(info->ft, buffer + ID3_TAG_QUERYSIZE, (size_t)size - ID3_TAG_QUERYSIZE)) { + struct id3_tag * tag = id3_tag_parse(buffer, (size_t)size); + if (tag) { + current = lsx_malloc(sizeof(struct tag_info_node)); + if (current) { + current->next = info->head; + current->start = start; + current->end = end; + info->head = current; + if (info->tag && (info->tag->extendedflags & ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE)) { + struct id3_frame * frame; + unsigned i; + for (i = 0; (frame = id3_tag_findframe(tag, NULL, i)); i++) { + id3_tag_attachframe(info->tag, frame); + } + id3_tag_delete(tag); + } else { + if (info->tag) { + id3_tag_delete(info->tag); + } + info->tag = tag; + } + } + } + } + free(buffer); + return result; +} + +void lsx_id3_read_tag(sox_format_t * ft, sox_bool search) +{ + struct tag_info info; + id3_utf8_t * utf8; + int i; + int has_id3v1 = 0; + + info.ft = ft; + info.head = NULL; + info.tag = NULL; + + /* + We look for: + ID3v1 at end (EOF - 128). + ID3v2 at start. + ID3v2 at end (but before ID3v1 from end if there was one). + */ + + if (search) { + if (0 == lsx_seeki(ft, -128, SEEK_END)) { + has_id3v1 = + add_tag(&info) && + 1 == ID3_TAG_VERSION_MAJOR(id3_tag_version(info.tag)); + } + if (0 == lsx_seeki(ft, 0, SEEK_SET)) { + add_tag(&info); + } + if (0 == lsx_seeki(ft, has_id3v1 ? -138 : -10, SEEK_END)) { + add_tag(&info); + } + } else { + add_tag(&info); + } + + if (info.tag && info.tag->frames) { + for (i = 0; id3tagmap[i][0]; ++i) { + if ((utf8 = utf8_id3tag_findframe(info.tag, id3tagmap[i][0], 0))) { + char * comment = lsx_malloc(strlen(id3tagmap[i][1]) + 1 + strlen((char *)utf8) + 1); + sprintf(comment, "%s=%s", id3tagmap[i][1], utf8); + sox_append_comment(&ft->oob.comments, comment); + free(comment); + free(utf8); + } + } + if ((utf8 = utf8_id3tag_findframe(info.tag, "TLEN", 0))) { + unsigned long tlen = strtoul((char *)utf8, NULL, 10); + if (tlen > 0 && tlen < ULONG_MAX) { + ft->signal.length= tlen; /* In ms; convert to samples later */ + lsx_debug("got exact duration from ID3 TLEN"); + } + free(utf8); + } + } + while (info.head) { + struct tag_info_node * head = info.head; + info.head = head->next; + free(head); + } + if (info.tag) { + id3_tag_delete(info.tag); + } +} + +#else + +/* Stub for format modules */ +void lsx_id3_read_tag(sox_format_t *ft, sox_bool search) { } + +#endif diff --git a/app/src/main/cpp/sox/id3.h b/app/src/main/cpp/sox/id3.h new file mode 100644 index 0000000..842e4d0 --- /dev/null +++ b/app/src/main/cpp/sox/id3.h @@ -0,0 +1,25 @@ +/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef SOX_ID3_H +#define SOX_ID3_H + +#include "sox_i.h" + +void lsx_id3_read_tag(sox_format_t *ft, sox_bool search); + +#endif diff --git a/app/src/main/cpp/sox/ima-fmt.c b/app/src/main/cpp/sox/ima-fmt.c new file mode 100644 index 0000000..a241bf1 --- /dev/null +++ b/app/src/main/cpp/sox/ima-fmt.c @@ -0,0 +1,33 @@ +/* libSoX format: raw IMA ADPCM (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "adpcms.h" +#include "vox.h" + +LSX_FORMAT_HANDLER(ima) +{ + static char const * const names[] = {"ima", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_IMA_ADPCM, 4, 0, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Raw IMA ADPCM", names, SOX_FILE_MONO, + lsx_ima_start, lsx_vox_read, lsx_vox_stopread, + lsx_ima_start, lsx_vox_write, lsx_vox_stopwrite, + lsx_rawseek, write_encodings, NULL, sizeof(adpcm_io_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/ima_rw.c b/app/src/main/cpp/sox/ima_rw.c new file mode 100644 index 0000000..360758e --- /dev/null +++ b/app/src/main/cpp/sox/ima_rw.c @@ -0,0 +1,365 @@ +/* libSoX ima_rw.c -- codex utilities for WAV_FORMAT_IMA_ADPCM + * Copyright (C) 1999 Stanley J. Brooks + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "sox_i.h" +#include "ima_rw.h" + +#include +#include +#include +/* + * + * Lookup tables for IMA ADPCM format + * + */ +#define ISSTMAX 88 + +static const int imaStepSizeTable[ISSTMAX + 1] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, + 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, + 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, + 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, + 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, + 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, + 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, + 27086, 29794, 32767 +}; + +#define imaStateAdjust(c) (((c)<4)? -1:(2*(c)-6)) +/* +0 - +3, decrease step size */ +/* +4 - +7, increase step size */ +/* -0 - -3, decrease step size */ +/* -4 - -7, increase step size */ + +static unsigned char imaStateAdjustTable[ISSTMAX+1][8]; + +void lsx_ima_init_table(void) +{ + int i,j,k; + for (i=0; i<=ISSTMAX; i++) { + for (j=0; j<8; j++) { + k = i + imaStateAdjust(j); + if (k<0) k=0; + else if (k>ISSTMAX) k=ISSTMAX; + imaStateAdjustTable[i][j] = k; + } + } +} + +static void ImaExpandS( + unsigned ch, /* channel number to decode, REQUIRE 0 <= ch < chans */ + unsigned chans, /* total channels */ + const unsigned char *ibuff,/* input buffer[blockAlign] */ + SAMPL *obuff, /* obuff[n] will be output samples */ + int n, /* samples to decode PER channel, REQUIRE n % 8 == 1 */ + unsigned o_inc /* index difference between successive output samples */ +) +{ + const unsigned char *ip; + int i_inc; + SAMPL *op; + int i, val, state; + + ip = ibuff + 4*ch; /* input pointer to 4-byte block state-initializer */ + i_inc = 4*(chans-1); /* amount by which to incr ip after each 4-byte read */ + val = (short)(ip[0] + (ip[1]<<8)); /* need cast for sign-extend */ + state = ip[2]; + if (state > ISSTMAX) { + lsx_warn("IMA_ADPCM block ch%d initial-state (%d) out of range", ch, state); + state = 0; + } + /* specs say to ignore ip[3] , but write it as 0 */ + ip += 4+i_inc; + + op = obuff; + *op = val; /* 1st output sample for this channel */ + op += o_inc; + + for (i = 1; i < n; i++) { + int step,dp,c,cm; + + if (i&1) { /* 1st of pair */ + cm = *ip & 0x0f; + } else { + cm = (*ip++)>>4; + if ((i&7) == 0) /* ends the 8-sample input block for this channel */ + ip += i_inc; /* skip ip for next group */ + } + + step = imaStepSizeTable[state]; + /* Update the state for the next sample */ + c = cm & 0x07; + state = imaStateAdjustTable[state][c]; + + dp = 0; + if (c & 4) dp += step; + step = step >> 1; + if (c & 2) dp += step; + step = step >> 1; + if (c & 1) dp += step; + step = step >> 1; + dp += step; + + if (c != cm) { + val -= dp; + if (val<-0x8000) val = -0x8000; + } else { + val += dp; + if (val>0x7fff) val = 0x7fff; + } + *op = val; + op += o_inc; + } + return; +} + +/* lsx_ima_block_expand_i() outputs interleaved samples into one output buffer */ +void lsx_ima_block_expand_i( + unsigned chans, /* total channels */ + const unsigned char *ibuff,/* input buffer[blockAlign] */ + SAMPL *obuff, /* output samples, n*chans */ + int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */ +) +{ + unsigned ch; + for (ch=0; ch>8; + *op++ = *st; *op++ = 0; /* they could have put a mid-block state-correction here */ + op += o_inc; /* _sigh_ NEVER waste a byte. It's a rule! */ + } + + state = *st; + + for (i = 0; ip < itop; ip+=chans) { + int step,d,dp,c; + + d = *ip - val; /* difference between last prediction and current sample */ + + step = imaStepSizeTable[state]; + c = (abs(d)<<2)/step; + if (c > 7) c = 7; + /* Update the state for the next sample */ + state = imaStateAdjustTable[state][c]; + + if (op) { /* if we want output, put it in proper place */ + int cm = c; + if (d<0) cm |= 8; + if (i&1) { /* odd numbered output */ + *op++ |= (cm<<4); + if (i == 7) /* ends the 8-sample output block for this channel */ + op += o_inc; /* skip op for next group */ + } else { + *op = cm; + } + i = (i+1) & 0x07; + } + + dp = 0; + if (c & 4) dp += step; + step = step >> 1; + if (c & 2) dp += step; + step = step >> 1; + if (c & 1) dp += step; + step = step >> 1; + dp += step; + + if (d<0) { + val -= dp; + if (val<-0x8000) val = -0x8000; + } else { + val += dp; + if (val>0x7fff) val = 0x7fff; + } + + { + int x = *ip - val; + d2 += x*x; + } + + } + d2 /= n; /* be sure it's non-negative */ + *st = state; + return (int) sqrt(d2); +} + +/* mash one channel... if you want to use opt>0, 9 is a reasonable value */ +inline static void ImaMashChannel( + unsigned ch, /* channel number to encode, REQUIRE 0 <= ch < chans */ + unsigned chans, /* total channels */ + const SAMPL *ip, /* ip[] is interleaved input samples */ + int n, /* samples to encode PER channel, REQUIRE n % 8 == 1 */ + int *st, /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */ + unsigned char *obuff, /* output buffer[blockAlign] */ + int opt /* non-zero allows some cpu-intensive code to improve output */ +) +{ + int snext; + int s0,d0; + + s0 = *st; + if (opt>0) { + int low,hi,w; + int low0,hi0; + snext = s0; + d0 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL); + + w = 0; + low=hi=s0; + low0 = low-opt; if (low0<0) low0=0; + hi0 = hi+opt; if (hi0>ISSTMAX) hi0=ISSTMAX; + while (low>low0 || hilow0) { + int d2; + snext = --low; + d2 = ImaMashS(ch, chans, ip[ch], ip,n,&snext, NULL); + if (d2ISSTMAX) hi0=ISSTMAX; + } + } + if (w && hiISSTMAX) hi0=ISSTMAX; + } + } + w=1-w; + } + *st = s0; + } + ImaMashS(ch, chans, ip[ch], ip,n,st, obuff); +} + +/* mash one block. if you want to use opt>0, 9 is a reasonable value */ +void lsx_ima_block_mash_i( + unsigned chans, /* total channels */ + const SAMPL *ip, /* ip[] is interleaved input samples */ + int n, /* samples to encode PER channel, REQUIRE n % 8 == 1 */ + int *st, /* input/output state, REQUIRE 0 <= *st <= ISSTMAX */ + unsigned char *obuff, /* output buffer[blockAlign] */ + int opt /* non-zero allows some cpu-intensive code to improve output */ +) +{ + unsigned ch; + for (ch=0; ch= (size_t)4*chans) { + m -= 4*chans; /* number of bytes beyond block-header */ + m /= 4*chans; /* number of 4-byte blocks/channel beyond header */ + m = 8*m + 1; /* samples/chan beyond header + 1 in header */ + if (samplesPerBlock && m > samplesPerBlock) m = samplesPerBlock; + n += m; + } + return n; + /*wSamplesPerBlock = ((wBlockAlign - 4*wChannels)/(4*wChannels))*8 + 1;*/ +} + +/* + * size_t lsx_ima_bytes_per_block(chans, samplesPerBlock) + * return minimum blocksize which would be required + * to encode number of chans with given samplesPerBlock + */ +size_t lsx_ima_bytes_per_block( + size_t chans, + size_t samplesPerBlock +) +{ + size_t n; + /* per channel, ima has blocks of len 4, the 1st has 1st sample, the others + * up to 8 samples per block, + * so number of later blocks is (nsamp-1 + 7)/8, total blocks/chan is + * (nsamp-1+7)/8 + 1 = (nsamp+14)/8 + */ + n = ((size_t)samplesPerBlock + 14)/8 * 4 * chans; + return n; +} diff --git a/app/src/main/cpp/sox/ima_rw.h b/app/src/main/cpp/sox/ima_rw.h new file mode 100644 index 0000000..95debda --- /dev/null +++ b/app/src/main/cpp/sox/ima_rw.h @@ -0,0 +1,84 @@ +/* libSoX ima_rw.h -- codex utilities for WAV_FORMAT_IMA_ADPCM + * Copyright (C) 1999 Stanley J. Brooks + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "sox.h" + +#ifndef SAMPL +#define SAMPL short +#endif + +/* + * call lsx_ima_init_table() before any other Ima* functions, + * to create the fast lookup tables + */ +extern void lsx_ima_init_table(void); + +/* lsx_ima_block_expand_i() outputs interleaved samples into one output buffer */ +extern void lsx_ima_block_expand_i( + unsigned chans, /* total channels */ + const unsigned char *ibuff,/* input buffer[blockAlign] */ + SAMPL *obuff, /* output samples, n*chans */ + int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */ +); + +/* lsx_ima_block_expand_m() outputs non-interleaved samples into chan separate output buffers */ +extern void lsx_ima_block_expand_m( + unsigned chans, /* total channels */ + const unsigned char *ibuff,/* input buffer[blockAlign] */ + SAMPL **obuffs, /* chan output sample buffers, each takes n samples */ + int n /* samples to decode PER channel, REQUIRE n % 8 == 1 */ +); + +/* mash one block. if you want to use opt>0, 9 is a reasonable value */ +extern void lsx_ima_block_mash_i( + unsigned chans, /* total channels */ + const SAMPL *ip, /* ip[] is interleaved input samples */ + int n, /* samples to encode PER channel, REQUIRE n % 8 == 1 */ + int *st, /* input/output state[chans], REQUIRE 0 <= st[ch] <= ISSTMAX */ + unsigned char *obuff, /* output buffer[blockAlign] */ + int opt /* non-zero allows some cpu-intensive code to improve output */ +); + +/* Some helper functions for computing samples/block and blockalign */ + +/* + * lsx_ima_samples_in(dataLen, chans, blockAlign, samplesPerBlock) + * returns the number of samples/channel which would go + * in the dataLen, given the other parameters ... + * if input samplesPerBlock is 0, then returns the max + * samplesPerBlock which would go into a block of size blockAlign + * Yes, it is confusing usage. + */ +extern size_t lsx_ima_samples_in( + size_t dataLen, + size_t chans, + size_t blockAlign, + size_t samplesPerBlock +); + +/* + * size_t lsx_ima_bytes_per_block(chans, samplesPerBlock) + * return minimum blocksize which would be required + * to encode number of chans with given samplesPerBlock + */ +extern size_t lsx_ima_bytes_per_block( + size_t chans, + size_t samplesPerBlock +); + diff --git a/app/src/main/cpp/sox/input.c b/app/src/main/cpp/sox/input.c new file mode 100644 index 0000000..caaefab --- /dev/null +++ b/app/src/main/cpp/sox/input.c @@ -0,0 +1,58 @@ +/* libSoX effect: Input audio from a file (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct {sox_format_t * file;} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + if (argc != 2 || !(p->file = (sox_format_t *)argv[1]) || p->file->mode != 'r') + return SOX_EOF; + return SOX_SUCCESS; +} + +static int drain( + sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + + /* ensure that *osamp is a multiple of the number of channels. */ + *osamp -= *osamp % effp->out_signal.channels; + + /* Read up to *osamp samples into obuf; store the actual number read + * back to *osamp */ + *osamp = sox_read(p->file, obuf, *osamp); + + /* sox_read may return a number that is less than was requested; only if + * 0 samples is returned does it indicate that end-of-file has been reached + * or an error has occurred */ + if (!*osamp && p->file->sox_errno) + lsx_fail("%s: %s", p->file->filename, p->file->sox_errstr); + return *osamp? SOX_SUCCESS : SOX_EOF; +} + +sox_effect_handler_t const * lsx_input_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "input", NULL, SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_INTERNAL, + getopts, NULL, NULL, drain, NULL, NULL, sizeof(priv_t) + }; + return &handler; +} + diff --git a/app/src/main/cpp/sox/la-fmt.c b/app/src/main/cpp/sox/la-fmt.c new file mode 100644 index 0000000..708fe8d --- /dev/null +++ b/app/src/main/cpp/sox/la-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT(la, 8, SOX_FILE_BIT_REV, ALAW) diff --git a/app/src/main/cpp/sox/ladspa.c b/app/src/main/cpp/sox/ladspa.c new file mode 100644 index 0000000..374e2e5 --- /dev/null +++ b/app/src/main/cpp/sox/ladspa.c @@ -0,0 +1,492 @@ +/* LADSPA effect support for sox + * (c) Reuben Thomas 2007 + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#ifdef HAVE_LADSPA_H + +#include +#include +#include +#include +#include "ladspa.h" + +/* + * Assuming LADSPA_Data == float. This is the case in 2012 and has been + * the case for many years now. + */ +#define SOX_SAMPLE_TO_LADSPA_DATA(d,clips) \ + SOX_SAMPLE_TO_FLOAT_32BIT((d),(clips)) +#define LADSPA_DATA_TO_SOX_SAMPLE(d,clips) \ + SOX_FLOAT_32BIT_TO_SAMPLE((d),(clips)) + +static sox_effect_handler_t sox_ladspa_effect; + +/* Private data for resampling */ +typedef struct { + char *name; /* plugin name */ + lt_dlhandle lth; /* dynamic object handle */ + sox_bool clone; + const LADSPA_Descriptor *desc; /* plugin descriptor */ + LADSPA_Handle *handles; /* instantiated plugin handles */ + size_t handle_count; + LADSPA_Data *control; /* control ports */ + unsigned long *inputs; + size_t input_count; + unsigned long *outputs; + size_t output_count; + sox_bool latency_compensation; + LADSPA_Data *latency_control_port; + unsigned long in_latency; + unsigned long out_latency; +} priv_t; + +static LADSPA_Data ladspa_default(const LADSPA_PortRangeHint *p) +{ + LADSPA_Data d; + + if (LADSPA_IS_HINT_DEFAULT_0(p->HintDescriptor)) + d = 0.0; + else if (LADSPA_IS_HINT_DEFAULT_1(p->HintDescriptor)) + d = 1.0; + else if (LADSPA_IS_HINT_DEFAULT_100(p->HintDescriptor)) + d = 100.0; + else if (LADSPA_IS_HINT_DEFAULT_440(p->HintDescriptor)) + d = 440.0; + else if (LADSPA_IS_HINT_DEFAULT_MINIMUM(p->HintDescriptor)) + d = p->LowerBound; + else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM(p->HintDescriptor)) + d = p->UpperBound; + else if (LADSPA_IS_HINT_DEFAULT_LOW(p->HintDescriptor)) { + if (LADSPA_IS_HINT_LOGARITHMIC(p->HintDescriptor)) + d = exp(log(p->LowerBound) * 0.75 + log(p->UpperBound) * 0.25); + else + d = p->LowerBound * 0.75 + p->UpperBound * 0.25; + } else if (LADSPA_IS_HINT_DEFAULT_MIDDLE(p->HintDescriptor)) { + if (LADSPA_IS_HINT_LOGARITHMIC(p->HintDescriptor)) + d = exp(log(p->LowerBound) * 0.5 + log(p->UpperBound) * 0.5); + else + d = p->LowerBound * 0.5 + p->UpperBound * 0.5; + } else if (LADSPA_IS_HINT_DEFAULT_HIGH(p->HintDescriptor)) { + if (LADSPA_IS_HINT_LOGARITHMIC(p->HintDescriptor)) + d = exp(log(p->LowerBound) * 0.25 + log(p->UpperBound) * 0.75); + else + d = p->LowerBound * 0.25 + p->UpperBound * 0.75; + } else { /* shouldn't happen */ + /* FIXME: Deal with this at a higher level */ + lsx_fail("non-existent default value; using 0.1"); + d = 0.1; /* Should at least avoid divide by 0 */ + } + + return d; +} + +/* + * Process options + */ +static int sox_ladspa_getopts(sox_effect_t *effp, int argc, char **argv) +{ + priv_t * l_st = (priv_t *)effp->priv; + char *path; + int c; + union {LADSPA_Descriptor_Function fn; lt_ptr ptr;} ltptr; + unsigned long index = 0, i; + double arg; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, "+rl", NULL, lsx_getopt_flag_none, 1, &optstate); + + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + case 'r': l_st->clone = sox_true; break; + case 'l': l_st->latency_compensation = sox_true; break; + default: + lsx_fail("unknown option `-%c'", optstate.opt); + return lsx_usage(effp); + } + argc -= optstate.ind, argv += optstate.ind; + + /* Get module name */ + if (argc >= 1) { + l_st->name = argv[0]; + argc--; argv++; + } + + /* Load module */ + path = getenv("LADSPA_PATH"); + if (path == NULL) + path = LADSPA_PATH; + + if(lt_dlinit() || lt_dlsetsearchpath(path) + || (l_st->lth = lt_dlopenext(l_st->name)) == NULL) { + lsx_fail("could not open LADSPA plugin %s", l_st->name); + return SOX_EOF; + } + + /* Get descriptor function */ + if ((ltptr.ptr = lt_dlsym(l_st->lth, "ladspa_descriptor")) == NULL) { + lsx_fail("could not find ladspa_descriptor"); + return SOX_EOF; + } + + /* If no plugins in this module, complain */ + if (ltptr.fn(0UL) == NULL) { + lsx_fail("no plugins found"); + return SOX_EOF; + } + + /* Get first plugin descriptor */ + l_st->desc = ltptr.fn(0UL); + assert(l_st->desc); /* We already know this will work */ + + /* If more than one plugin, or first argument is not a number, try + to use first argument as plugin label. */ + if (argc > 0 && (ltptr.fn(1UL) != NULL || !sscanf(argv[0], "%lf", &arg))) { + while (l_st->desc && strcmp(l_st->desc->Label, argv[0]) != 0) + l_st->desc = ltptr.fn(++index); + if (l_st->desc == NULL) { + lsx_fail("no plugin called `%s' found", argv[0]); + return SOX_EOF; + } + argc--; argv++; + } + + /* Scan the ports for inputs and outputs */ + l_st->control = lsx_calloc(l_st->desc->PortCount, sizeof(LADSPA_Data)); + l_st->inputs = lsx_malloc(l_st->desc->PortCount * sizeof(unsigned long)); + l_st->outputs = lsx_malloc(l_st->desc->PortCount * sizeof(unsigned long)); + + for (i = 0; i < l_st->desc->PortCount; i++) { + const LADSPA_PortDescriptor port = l_st->desc->PortDescriptors[i]; + + /* Check port is well specified. All control ports should be + inputs, but don't bother checking, as we never rely on this. */ + if (LADSPA_IS_PORT_INPUT(port) && LADSPA_IS_PORT_OUTPUT(port)) { + lsx_fail("port %lu is both input and output", i); + return SOX_EOF; + } else if (LADSPA_IS_PORT_CONTROL(port) && LADSPA_IS_PORT_AUDIO(port)) { + lsx_fail("port %lu is both audio and control", i); + return SOX_EOF; + } + + if (LADSPA_IS_PORT_AUDIO(port)) { + if (LADSPA_IS_PORT_INPUT(port)) { + l_st->inputs[l_st->input_count++] = i; + } else if (LADSPA_IS_PORT_OUTPUT(port)) { + l_st->outputs[l_st->output_count++] = i; + } + } else { /* Control port */ + if (l_st->latency_compensation && + LADSPA_IS_PORT_CONTROL(port) && + LADSPA_IS_PORT_OUTPUT(port) && + strcmp(l_st->desc->PortNames[i], "latency") == 0) { + /* automatic latency compensation, Ardour does this, too */ + l_st->latency_control_port = &l_st->control[i]; + assert(*l_st->latency_control_port == 0); + lsx_debug("latency control port is %lu", i); + } else if (argc == 0) { + if (!LADSPA_IS_HINT_HAS_DEFAULT(l_st->desc->PortRangeHints[i].HintDescriptor)) { + lsx_fail("not enough arguments for control ports"); + return SOX_EOF; + } + l_st->control[i] = ladspa_default(&(l_st->desc->PortRangeHints[i])); + lsx_debug("default argument for port %lu is %f", i, l_st->control[i]); + } else { + if (!sscanf(argv[0], "%lf", &arg)) + return lsx_usage(effp); + l_st->control[i] = (LADSPA_Data)arg; + lsx_debug("argument for port %lu is %f", i, l_st->control[i]); + argc--; argv++; + } + } + } + + /* Stop if we have any unused arguments */ + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +/* + * Prepare processing. + */ +static int sox_ladspa_start(sox_effect_t * effp) +{ + priv_t * l_st = (priv_t *)effp->priv; + unsigned long i; + size_t h; + unsigned long rate = (unsigned long)effp->in_signal.rate; + + /* Instantiate the plugin */ + lsx_debug("rate for plugin is %g", effp->in_signal.rate); + + if (l_st->input_count == 1 && l_st->output_count == 1 && + effp->in_signal.channels == effp->out_signal.channels) { + /* for mono plugins, they are common */ + + if (!l_st->clone && effp->in_signal.channels > 1) { + lsx_fail("expected 1 input channel(s), found %u; consider using -r", + effp->in_signal.channels); + return SOX_EOF; + } + + /* + * create one handle per channel for mono plugins. ecasound does this, too. + * mono LADSPA plugins are common and SoX supported mono LADSPA plugins + * exclusively for a while. + */ + l_st->handles = lsx_malloc(effp->in_signal.channels * + sizeof(LADSPA_Handle *)); + + while (l_st->handle_count < effp->in_signal.channels) + l_st->handles[l_st->handle_count++] = l_st->desc->instantiate(l_st->desc, rate); + + } else { + /* + * assume the plugin is multi-channel capable with one instance, + * Some LADSPA plugins are stereo (e.g. bs2b-ladspa) + */ + + if (l_st->input_count < effp->in_signal.channels) { + lsx_fail("fewer plugin input ports than input channels (%u < %u)", + (unsigned)l_st->input_count, effp->in_signal.channels); + return SOX_EOF; + } + + /* warn if LADSPA audio ports are unused. ecasound does this, too */ + if (l_st->input_count > effp->in_signal.channels) + lsx_warn("more plugin input ports than input channels (%u > %u)", + (unsigned)l_st->input_count, effp->in_signal.channels); + + /* + * some LADSPA plugins increase/decrease the channel count + * (e.g. "mixer" in cmt or vocoder): + */ + if (l_st->output_count != effp->out_signal.channels) { + lsx_debug("changing output channels to match plugin output ports (%u => %u)", + effp->out_signal.channels, (unsigned)l_st->output_count); + effp->out_signal.channels = l_st->output_count; + } + + l_st->handle_count = 1; + l_st->handles = lsx_malloc(sizeof(LADSPA_Handle *)); + l_st->handles[0] = l_st->desc->instantiate(l_st->desc, rate); + } + + /* abandon everything completely on any failed handle instantiation */ + for (h = 0; h < l_st->handle_count; h++) { + if (l_st->handles[h] == NULL) { + /* cleanup the handles that did instantiate successfully */ + for (h = 0; l_st->desc->cleanup && h < l_st->handle_count; h++) { + if (l_st->handles[h]) + l_st->desc->cleanup(l_st->handles[h]); + } + + free(l_st->handles); + l_st->handle_count = 0; + lsx_fail("could not instantiate plugin"); + return SOX_EOF; + } + } + + for (i = 0; i < l_st->desc->PortCount; i++) { + const LADSPA_PortDescriptor port = l_st->desc->PortDescriptors[i]; + + if (LADSPA_IS_PORT_CONTROL(port)) { + for (h = 0; h < l_st->handle_count; h++) + l_st->desc->connect_port(l_st->handles[h], i, &(l_st->control[i])); + } + } + + /* If needed, activate the plugin instances */ + if (l_st->desc->activate) { + for (h = 0; h < l_st->handle_count; h++) + l_st->desc->activate(l_st->handles[h]); + } + + return SOX_SUCCESS; +} + +/* + * Process one bufferful of data. + */ +static int sox_ladspa_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * l_st = (priv_t *)effp->priv; + size_t i, len = min(*isamp, *osamp); + size_t j; + size_t h; + const size_t total_input_count = l_st->input_count * l_st->handle_count; + const size_t total_output_count = l_st->output_count * l_st->handle_count; + const size_t input_len = len / total_input_count; + size_t output_len = len / total_output_count; + + if (total_output_count < total_input_count) + output_len = input_len; + + *isamp = len; + *osamp = 0; + + if (len) { + LADSPA_Data *buf = lsx_calloc(len, sizeof(LADSPA_Data)); + LADSPA_Data *outbuf = lsx_calloc(len, sizeof(LADSPA_Data)); + LADSPA_Handle handle; + unsigned long port, l; + SOX_SAMPLE_LOCALS; + + /* + * prepare buffer for LADSPA input + * deinterleave sox samples and write non-interleaved data to + * input_port-specific buffer locations + */ + for (i = 0; i < input_len; i++) { + for (j = 0; j < total_input_count; j++) { + const sox_sample_t s = *ibuf++; + buf[j * input_len + i] = SOX_SAMPLE_TO_LADSPA_DATA(s, effp->clips); + } + } + + /* Connect the LADSPA input port(s) to the prepared buffers */ + for (j = 0; j < total_input_count; j++) { + handle = l_st->handles[j / l_st->input_count]; + port = l_st->inputs[j / l_st->handle_count]; + l_st->desc->connect_port(handle, port, buf + j * input_len); + } + + /* Connect the LADSPA output port(s) if used */ + for (j = 0; j < total_output_count; j++) { + handle = l_st->handles[j / l_st->output_count]; + port = l_st->outputs[j / l_st->handle_count]; + l_st->desc->connect_port(handle, port, outbuf + j * output_len); + } + + /* Run the plugin for each handle */ + for (h = 0; h < l_st->handle_count; h++) + l_st->desc->run(l_st->handles[h], input_len); + + /* check the latency control port if we have one */ + if (l_st->latency_control_port) { + lsx_debug("latency detected is %g", *l_st->latency_control_port); + l_st->in_latency = (unsigned long)floor(*l_st->latency_control_port); + + /* we will need this later in sox_ladspa_drain */ + l_st->out_latency = l_st->in_latency; + + /* latency for plugins is constant, only compensate once */ + l_st->latency_control_port = NULL; + } + + /* Grab output if effect produces it, re-interleaving it */ + l = min(output_len, l_st->in_latency); + for (i = l; i < output_len; i++) { + for (j = 0; j < total_output_count; j++) { + LADSPA_Data d = outbuf[j * output_len + i]; + *obuf++ = LADSPA_DATA_TO_SOX_SAMPLE(d, effp->clips); + (*osamp)++; + } + } + l_st->in_latency -= l; + + free(outbuf); + free(buf); + } + + return SOX_SUCCESS; +} + +/* + * Nothing to do if the plugin has no latency or latency compensation is + * disabled. + */ +static int sox_ladspa_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * l_st = (priv_t *)effp->priv; + sox_sample_t *ibuf, *dbuf; + size_t isamp, dsamp; + int r; + + if (l_st->out_latency == 0) { + *osamp = 0; + return SOX_SUCCESS; + } + + /* feed some silence at the end to push the rest of the data out */ + isamp = l_st->out_latency * effp->in_signal.channels; + dsamp = l_st->out_latency * effp->out_signal.channels; + ibuf = lsx_calloc(isamp, sizeof(sox_sample_t)); + dbuf = lsx_calloc(dsamp, sizeof(sox_sample_t)); + + r = sox_ladspa_flow(effp, ibuf, dbuf, &isamp, &dsamp); + *osamp = min(dsamp, *osamp); + memcpy(obuf, dbuf, *osamp * sizeof(sox_sample_t)); + + free(ibuf); + free(dbuf); + + return r == SOX_SUCCESS ? SOX_EOF : 0; +} + +/* + * Do anything required when you stop reading samples. + * Don't close input file! + */ +static int sox_ladspa_stop(sox_effect_t * effp) +{ + priv_t * l_st = (priv_t *)effp->priv; + size_t h; + + for (h = 0; h < l_st->handle_count; h++) { + /* If needed, deactivate and cleanup the plugin */ + if (l_st->desc->deactivate) + l_st->desc->deactivate(l_st->handles[h]); + if (l_st->desc->cleanup) + l_st->desc->cleanup(l_st->handles[h]); + } + free(l_st->handles); + l_st->handle_count = 0; + + return SOX_SUCCESS; +} + +static int sox_ladspa_kill(sox_effect_t * effp) +{ + priv_t * l_st = (priv_t *)effp->priv; + + free(l_st->control); + free(l_st->inputs); + free(l_st->outputs); + + return SOX_SUCCESS; +} + +static sox_effect_handler_t sox_ladspa_effect = { + "ladspa", + "MODULE [PLUGIN] [ARGUMENT...]", + SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_GAIN, + sox_ladspa_getopts, + sox_ladspa_start, + sox_ladspa_flow, + sox_ladspa_drain, + sox_ladspa_stop, + sox_ladspa_kill, + sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_ladspa_effect_fn(void) +{ + return &sox_ladspa_effect; +} + +#endif /* HAVE_LADSPA */ diff --git a/app/src/main/cpp/sox/ladspa.h b/app/src/main/cpp/sox/ladspa.h new file mode 100644 index 0000000..72c1c00 --- /dev/null +++ b/app/src/main/cpp/sox/ladspa.h @@ -0,0 +1,603 @@ +/* ladspa.h + + Linux Audio Developer's Simple Plugin API Version 1.1[LGPL]. + Copyright (C) 2000-2002 Richard W.E. Furse, Paul Barton-Davis, + Stefan Westerfeld. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 + USA. */ + +#ifndef LADSPA_INCLUDED +#define LADSPA_INCLUDED + +#define LADSPA_VERSION "1.1" +#define LADSPA_VERSION_MAJOR 1 +#define LADSPA_VERSION_MINOR 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/*****************************************************************************/ + +/* Overview: + + There is a large number of synthesis packages in use or development + on the Linux platform at this time. This API (`The Linux Audio + Developer's Simple Plugin API') attempts to give programmers the + ability to write simple `plugin' audio processors in C/C++ and link + them dynamically (`plug') into a range of these packages (`hosts'). + It should be possible for any host and any plugin to communicate + completely through this interface. + + This API is deliberately short and simple. To achieve compatibility + with a range of promising Linux sound synthesis packages it + attempts to find the `greatest common divisor' in their logical + behaviour. Having said this, certain limiting decisions are + implicit, notably the use of a fixed type (LADSPA_Data) for all + data transfer and absence of a parameterised `initialisation' + phase. See below for the LADSPA_Data typedef. + + Plugins are expected to distinguish between control and audio + data. Plugins have `ports' that are inputs or outputs for audio or + control data and each plugin is `run' for a `block' corresponding + to a short time interval measured in samples. Audio data is + communicated using arrays of LADSPA_Data, allowing a block of audio + to be processed by the plugin in a single pass. Control data is + communicated using single LADSPA_Data values. Control data has a + single value at the start of a call to the `run()' or `run_adding()' + function, and may be considered to remain this value for its + duration. The plugin may assume that all its input and output ports + have been connected to the relevant data location (see the + `connect_port()' function below) before it is asked to run. + + Plugins will reside in shared object files suitable for dynamic + linking by dlopen() and family. The file will provide a number of + `plugin types' that can be used to instantiate actual plugins + (sometimes known as `plugin instances') that can be connected + together to perform tasks. + + This API contains very limited error-handling. */ + +/*****************************************************************************/ + +/* Fundamental data type passed in and out of plugin. This data type + is used to communicate audio samples and control values. It is + assumed that the plugin will work sensibly given any numeric input + value although it may have a preferred range (see hints below). + + For audio it is generally assumed that 1.0f is the `0dB' reference + amplitude and is a `normal' signal level. */ + +typedef float LADSPA_Data; + +/*****************************************************************************/ + +/* Special Plugin Properties: + + Optional features of the plugin type are encapsulated in the + LADSPA_Properties type. This is assembled by ORing individual + properties together. */ + +typedef int LADSPA_Properties; + +/* Property LADSPA_PROPERTY_REALTIME indicates that the plugin has a + real-time dependency (e.g. listens to a MIDI device) and so its + output must not be cached or subject to significant latency. */ +#define LADSPA_PROPERTY_REALTIME 0x1 + +/* Property LADSPA_PROPERTY_INPLACE_BROKEN indicates that the plugin + may cease to work correctly if the host elects to use the same data + location for both input and output (see connect_port()). This + should be avoided as enabling this flag makes it impossible for + hosts to use the plugin to process audio `in-place.' */ +#define LADSPA_PROPERTY_INPLACE_BROKEN 0x2 + +/* Property LADSPA_PROPERTY_HARD_RT_CAPABLE indicates that the plugin + is capable of running not only in a conventional host but also in a + `hard real-time' environment. To qualify for this the plugin must + satisfy all of the following: + + (1) The plugin must not use malloc(), free() or other heap memory + management within its run() or run_adding() functions. All new + memory used in run() must be managed via the stack. These + restrictions only apply to the run() function. + + (2) The plugin will not attempt to make use of any library + functions with the exceptions of functions in the ANSI standard C + and C maths libraries, which the host is expected to provide. + + (3) The plugin will not access files, devices, pipes, sockets, IPC + or any other mechanism that might result in process or thread + blocking. + + (4) The plugin will take an amount of time to execute a run() or + run_adding() call approximately of form (A+B*SampleCount) where A + and B depend on the machine and host in use. This amount of time + may not depend on input signals or plugin state. The host is left + the responsibility to perform timings to estimate upper bounds for + A and B. */ +#define LADSPA_PROPERTY_HARD_RT_CAPABLE 0x4 + +#define LADSPA_IS_REALTIME(x) ((x) & LADSPA_PROPERTY_REALTIME) +#define LADSPA_IS_INPLACE_BROKEN(x) ((x) & LADSPA_PROPERTY_INPLACE_BROKEN) +#define LADSPA_IS_HARD_RT_CAPABLE(x) ((x) & LADSPA_PROPERTY_HARD_RT_CAPABLE) + +/*****************************************************************************/ + +/* Plugin Ports: + + Plugins have `ports' that are inputs or outputs for audio or + data. Ports can communicate arrays of LADSPA_Data (for audio + inputs/outputs) or single LADSPA_Data values (for control + input/outputs). This information is encapsulated in the + LADSPA_PortDescriptor type which is assembled by ORing individual + properties together. + + Note that a port must be an input or an output port but not both + and that a port must be a control or audio port but not both. */ + +typedef int LADSPA_PortDescriptor; + +/* Property LADSPA_PORT_INPUT indicates that the port is an input. */ +#define LADSPA_PORT_INPUT 0x1 + +/* Property LADSPA_PORT_OUTPUT indicates that the port is an output. */ +#define LADSPA_PORT_OUTPUT 0x2 + +/* Property LADSPA_PORT_CONTROL indicates that the port is a control + port. */ +#define LADSPA_PORT_CONTROL 0x4 + +/* Property LADSPA_PORT_AUDIO indicates that the port is a audio + port. */ +#define LADSPA_PORT_AUDIO 0x8 + +#define LADSPA_IS_PORT_INPUT(x) ((x) & LADSPA_PORT_INPUT) +#define LADSPA_IS_PORT_OUTPUT(x) ((x) & LADSPA_PORT_OUTPUT) +#define LADSPA_IS_PORT_CONTROL(x) ((x) & LADSPA_PORT_CONTROL) +#define LADSPA_IS_PORT_AUDIO(x) ((x) & LADSPA_PORT_AUDIO) + +/*****************************************************************************/ + +/* Plugin Port Range Hints: + + The host may wish to provide a representation of data entering or + leaving a plugin (e.g. to generate a GUI automatically). To make + this more meaningful, the plugin should provide `hints' to the host + describing the usual values taken by the data. + + Note that these are only hints. The host may ignore them and the + plugin must not assume that data supplied to it is meaningful. If + the plugin receives invalid input data it is expected to continue + to run without failure and, where possible, produce a sensible + output (e.g. a high-pass filter given a negative cutoff frequency + might switch to an all-pass mode). + + Hints are meaningful for all input and output ports but hints for + input control ports are expected to be particularly useful. + + More hint information is encapsulated in the + LADSPA_PortRangeHintDescriptor type which is assembled by ORing + individual hint types together. Hints may require further + LowerBound and UpperBound information. + + All the hint information for a particular port is aggregated in the + LADSPA_PortRangeHint structure. */ + +typedef int LADSPA_PortRangeHintDescriptor; + +/* Hint LADSPA_HINT_BOUNDED_BELOW indicates that the LowerBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) lower + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of LowerBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_BELOW 0x1 + +/* Hint LADSPA_HINT_BOUNDED_ABOVE indicates that the UpperBound field + of the LADSPA_PortRangeHint should be considered meaningful. The + value in this field should be considered the (inclusive) upper + bound of the valid range. If LADSPA_HINT_SAMPLE_RATE is also + specified then the value of UpperBound should be multiplied by the + sample rate. */ +#define LADSPA_HINT_BOUNDED_ABOVE 0x2 + +/* Hint LADSPA_HINT_TOGGLED indicates that the data item should be + considered a Boolean toggle. Data less than or equal to zero should + be considered `off' or `false,' and data above zero should be + considered `on' or `true.' LADSPA_HINT_TOGGLED may not be used in + conjunction with any other hint except LADSPA_HINT_DEFAULT_0 or + LADSPA_HINT_DEFAULT_1. */ +#define LADSPA_HINT_TOGGLED 0x4 + +/* Hint LADSPA_HINT_SAMPLE_RATE indicates that any bounds specified + should be interpreted as multiples of the sample rate. For + instance, a frequency range from 0Hz to the Nyquist frequency (half + the sample rate) could be requested by this hint in conjunction + with LowerBound = 0 and UpperBound = 0.5. Hosts that support bounds + at all must support this hint to retain meaning. */ +#define LADSPA_HINT_SAMPLE_RATE 0x8 + +/* Hint LADSPA_HINT_LOGARITHMIC indicates that it is likely that the + user will find it more intuitive to view values using a logarithmic + scale. This is particularly useful for frequencies and gains. */ +#define LADSPA_HINT_LOGARITHMIC 0x10 + +/* Hint LADSPA_HINT_INTEGER indicates that a user interface would + probably wish to provide a stepped control taking only integer + values. Any bounds set should be slightly wider than the actual + integer range required to avoid floating point rounding errors. For + instance, the integer set {0,1,2,3} might be described as [-0.1, + 3.1]. */ +#define LADSPA_HINT_INTEGER 0x20 + +/* The various LADSPA_HINT_HAS_DEFAULT_* hints indicate a `normal' + value for the port that is sensible as a default. For instance, + this value is suitable for use as an initial value in a user + interface or as a value the host might assign to a control port + when the user has not provided one. Defaults are encoded using a + mask so only one default may be specified for a port. Some of the + hints make use of lower and upper bounds, in which case the + relevant bound or bounds must be available and + LADSPA_HINT_SAMPLE_RATE must be applied as usual. The resulting + default must be rounded if LADSPA_HINT_INTEGER is present. Default + values were introduced in LADSPA v1.1. */ +#define LADSPA_HINT_DEFAULT_MASK 0x3C0 + +/* This default values indicates that no default is provided. */ +#define LADSPA_HINT_DEFAULT_NONE 0x0 + +/* This default hint indicates that the suggested lower bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MINIMUM 0x40 + +/* This default hint indicates that a low value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.75 + + log(upper) * 0.25). Otherwise, this should be (lower * 0.75 + upper + * 0.25). */ +#define LADSPA_HINT_DEFAULT_LOW 0x80 + +/* This default hint indicates that a middle value between the + suggested lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.5 + + log(upper) * 0.5). Otherwise, this should be (lower * 0.5 + upper * + 0.5). */ +#define LADSPA_HINT_DEFAULT_MIDDLE 0xC0 + +/* This default hint indicates that a high value between the suggested + lower and upper bounds should be chosen. For ports with + LADSPA_HINT_LOGARITHMIC, this should be exp(log(lower) * 0.25 + + log(upper) * 0.75). Otherwise, this should be (lower * 0.25 + upper + * 0.75). */ +#define LADSPA_HINT_DEFAULT_HIGH 0x100 + +/* This default hint indicates that the suggested upper bound for the + port should be used. */ +#define LADSPA_HINT_DEFAULT_MAXIMUM 0x140 + +/* This default hint indicates that the number 0 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_0 0x200 + +/* This default hint indicates that the number 1 should be used. Note + that this default may be used in conjunction with + LADSPA_HINT_TOGGLED. */ +#define LADSPA_HINT_DEFAULT_1 0x240 + +/* This default hint indicates that the number 100 should be used. */ +#define LADSPA_HINT_DEFAULT_100 0x280 + +/* This default hint indicates that the Hz frequency of `concert A' + should be used. This will be 440 unless the host uses an unusual + tuning convention, in which case it may be within a few Hz. */ +#define LADSPA_HINT_DEFAULT_440 0x2C0 + +#define LADSPA_IS_HINT_BOUNDED_BELOW(x) ((x) & LADSPA_HINT_BOUNDED_BELOW) +#define LADSPA_IS_HINT_BOUNDED_ABOVE(x) ((x) & LADSPA_HINT_BOUNDED_ABOVE) +#define LADSPA_IS_HINT_TOGGLED(x) ((x) & LADSPA_HINT_TOGGLED) +#define LADSPA_IS_HINT_SAMPLE_RATE(x) ((x) & LADSPA_HINT_SAMPLE_RATE) +#define LADSPA_IS_HINT_LOGARITHMIC(x) ((x) & LADSPA_HINT_LOGARITHMIC) +#define LADSPA_IS_HINT_INTEGER(x) ((x) & LADSPA_HINT_INTEGER) + +#define LADSPA_IS_HINT_HAS_DEFAULT(x) ((x) & LADSPA_HINT_DEFAULT_MASK) +#define LADSPA_IS_HINT_DEFAULT_MINIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MINIMUM) +#define LADSPA_IS_HINT_DEFAULT_LOW(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_LOW) +#define LADSPA_IS_HINT_DEFAULT_MIDDLE(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MIDDLE) +#define LADSPA_IS_HINT_DEFAULT_HIGH(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_HIGH) +#define LADSPA_IS_HINT_DEFAULT_MAXIMUM(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_MAXIMUM) +#define LADSPA_IS_HINT_DEFAULT_0(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_0) +#define LADSPA_IS_HINT_DEFAULT_1(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_1) +#define LADSPA_IS_HINT_DEFAULT_100(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_100) +#define LADSPA_IS_HINT_DEFAULT_440(x) (((x) & LADSPA_HINT_DEFAULT_MASK) \ + == LADSPA_HINT_DEFAULT_440) + +typedef struct _LADSPA_PortRangeHint { + + /* Hints about the port. */ + LADSPA_PortRangeHintDescriptor HintDescriptor; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_BELOW is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data LowerBound; + + /* Meaningful when hint LADSPA_HINT_BOUNDED_ABOVE is active. When + LADSPA_HINT_SAMPLE_RATE is also active then this value should be + multiplied by the relevant sample rate. */ + LADSPA_Data UpperBound; + +} LADSPA_PortRangeHint; + +/*****************************************************************************/ + +/* Plugin Handles: + + This plugin handle indicates a particular instance of the plugin + concerned. It is valid to compare this to NULL (0 for C++) but + otherwise the host should not attempt to interpret it. The plugin + may use it to reference internal instance data. */ + +typedef void * LADSPA_Handle; + +/*****************************************************************************/ + +/* Descriptor for a Type of Plugin: + + This structure is used to describe a plugin type. It provides a + number of functions to examine the type, instantiate it, link it to + buffers and workspaces and to run it. */ + +typedef struct _LADSPA_Descriptor { + + /* This numeric identifier indicates the plugin type + uniquely. Plugin programmers may reserve ranges of IDs from a + central body to avoid clashes. Hosts may assume that IDs are + below 0x1000000. */ + unsigned long UniqueID; + + /* This identifier can be used as a unique, case-sensitive + identifier for the plugin type within the plugin file. Plugin + types should be identified by file and label rather than by index + or plugin name, which may be changed in new plugin + versions. Labels must not contain white-space characters. */ + const char * Label; + + /* This indicates a number of properties of the plugin. */ + LADSPA_Properties Properties; + + /* This member points to the null-terminated name of the plugin + (e.g. "Sine Oscillator"). */ + const char * Name; + + /* This member points to the null-terminated string indicating the + maker of the plugin. This can be an empty string but not NULL. */ + const char * Maker; + + /* This member points to the null-terminated string indicating any + copyright applying to the plugin. If no Copyright applies the + string "None" should be used. */ + const char * Copyright; + + /* This indicates the number of ports (input AND output) present on + the plugin. */ + unsigned long PortCount; + + /* This member indicates an array of port descriptors. Valid indices + vary from 0 to PortCount-1. */ + const LADSPA_PortDescriptor * PortDescriptors; + + /* This member indicates an array of null-terminated strings + describing ports (e.g. "Frequency (Hz)"). Valid indices vary from + 0 to PortCount-1. */ + const char * const * PortNames; + + /* This member indicates an array of range hints for each port (see + above). Valid indices vary from 0 to PortCount-1. */ + const LADSPA_PortRangeHint * PortRangeHints; + + /* This may be used by the plugin developer to pass any custom + implementation data into an instantiate call. It must not be used + or interpreted by the host. It is expected that most plugin + writers will not use this facility as LADSPA_Handle should be + used to hold instance data. */ + void * ImplementationData; + + /* This member is a function pointer that instantiates a plugin. A + handle is returned indicating the new plugin instance. The + instantiation function accepts a sample rate as a parameter. The + plugin descriptor from which this instantiate function was found + must also be passed. This function must return NULL if + instantiation fails. + + Note that instance initialisation should generally occur in + activate() rather than here. */ + LADSPA_Handle (*instantiate)(const struct _LADSPA_Descriptor * Descriptor, + unsigned long SampleRate); + + /* This member is a function pointer that connects a port on an + instantiated plugin to a memory location at which a block of data + for the port will be read/written. The data location is expected + to be an array of LADSPA_Data for audio ports or a single + LADSPA_Data value for control ports. Memory issues will be + managed by the host. The plugin must read/write the data at these + locations every time run() or run_adding() is called and the data + present at the time of this connection call should not be + considered meaningful. + + connect_port() may be called more than once for a plugin instance + to allow the host to change the buffers that the plugin is + reading or writing. These calls may be made before or after + activate() or deactivate() calls. + + connect_port() must be called at least once for each port before + run() or run_adding() is called. When working with blocks of + LADSPA_Data the plugin should pay careful attention to the block + size passed to the run function as the block allocated may only + just be large enough to contain the block of samples. + + Plugin writers should be aware that the host may elect to use the + same buffer for more than one port and even use the same buffer + for both input and output (see LADSPA_PROPERTY_INPLACE_BROKEN). + However, overlapped buffers or use of a single buffer for both + audio and control data may result in unexpected behaviour. */ + void (*connect_port)(LADSPA_Handle Instance, + unsigned long Port, + LADSPA_Data * DataLocation); + + /* This member is a function pointer that initialises a plugin + instance and activates it for use. This is separated from + instantiate() to aid real-time support and so that hosts can + reinitialise a plugin instance by calling deactivate() and then + activate(). In this case the plugin instance must reset all state + information dependent on the history of the plugin instance + except for any data locations provided by connect_port() and any + gain set by set_run_adding_gain(). If there is nothing for + activate() to do then the plugin writer may provide a NULL rather + than an empty function. + + When present, hosts must call this function once before run() (or + run_adding()) is called for the first time. This call should be + made as close to the run() call as possible and indicates to + real-time plugins that they are now live. Plugins should not rely + on a prompt call to run() after activate(). activate() may not be + called again unless deactivate() is called first. Note that + connect_port() may be called before or after a call to + activate(). */ + void (*activate)(LADSPA_Handle Instance); + + /* This method is a function pointer that runs an instance of a + plugin for a block. Two parameters are required: the first is a + handle to the particular instance to be run and the second + indicates the block size (in samples) for which the plugin + instance may run. + + Note that if an activate() function exists then it must be called + before run() or run_adding(). If deactivate() is called for a + plugin instance then the plugin instance may not be reused until + activate() has been called again. + + If the plugin has the property LADSPA_PROPERTY_HARD_RT_CAPABLE + then there are various things that the plugin should not do + within the run() or run_adding() functions (see above). */ + void (*run)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that runs an instance of a + plugin for a block. This has identical behaviour to run() except + in the way data is output from the plugin. When run() is used, + values are written directly to the memory areas associated with + the output ports. However when run_adding() is called, values + must be added to the values already present in the memory + areas. Furthermore, output values written must be scaled by the + current gain set by set_run_adding_gain() (see below) before + addition. + + run_adding() is optional. When it is not provided by a plugin, + this function pointer must be set to NULL. When it is provided, + the function set_run_adding_gain() must be provided also. */ + void (*run_adding)(LADSPA_Handle Instance, + unsigned long SampleCount); + + /* This method is a function pointer that sets the output gain for + use when run_adding() is called (see above). If this function is + never called the gain is assumed to default to 1. Gain + information should be retained when activate() or deactivate() + are called. + + This function should be provided by the plugin if and only if the + run_adding() function is provided. When it is absent this + function pointer must be set to NULL. */ + void (*set_run_adding_gain)(LADSPA_Handle Instance, + LADSPA_Data Gain); + + /* This is the counterpart to activate() (see above). If there is + nothing for deactivate() to do then the plugin writer may provide + a NULL rather than an empty function. + + Hosts must deactivate all activated units after they have been + run() (or run_adding()) for the last time. This call should be + made as close to the last run() call as possible and indicates to + real-time plugins that they are no longer live. Plugins should + not rely on prompt deactivation. Note that connect_port() may be + called before or after a call to deactivate(). + + Deactivation is not similar to pausing as the plugin instance + will be reinitialised when activate() is called to reuse it. */ + void (*deactivate)(LADSPA_Handle Instance); + + /* Once an instance of a plugin has been finished with it can be + deleted using the following function. The instance handle passed + ceases to be valid after this call. + + If activate() was called for a plugin instance then a + corresponding call to deactivate() must be made before cleanup() + is called. */ + void (*cleanup)(LADSPA_Handle Instance); + +} LADSPA_Descriptor; + +/**********************************************************************/ + +/* Accessing a Plugin: */ + +/* The exact mechanism by which plugins are loaded is host-dependent, + however all most hosts will need to know is the name of shared + object file containing the plugin types. To allow multiple hosts to + share plugin types, hosts may wish to check for environment + variable LADSPA_PATH. If present, this should contain a + colon-separated path indicating directories that should be searched + (in order) when loading plugin types. + + A plugin programmer must include a function called + "ladspa_descriptor" with the following function prototype within + the shared object file. This function will have C-style linkage (if + you are using C++ this is taken care of by the `extern "C"' clause + at the top of the file). + + A host will find the plugin shared object file by one means or + another, find the ladspa_descriptor() function, call it, and + proceed from there. + + Plugin types are accessed by index (not ID) using values from 0 + upwards. Out of range indexes must result in this function + returning NULL, so the plugin count can be determined by checking + for the least index that results in NULL being returned. */ + +const LADSPA_Descriptor * ladspa_descriptor(unsigned long Index); + +/* Datatype corresponding to the ladspa_descriptor() function. */ +typedef const LADSPA_Descriptor * +(*LADSPA_Descriptor_Function)(unsigned long Index); + +/**********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* LADSPA_INCLUDED */ + +/* EOF */ diff --git a/app/src/main/cpp/sox/libsox.c b/app/src/main/cpp/sox/libsox.c new file mode 100644 index 0000000..8e9ebad --- /dev/null +++ b/app/src/main/cpp/sox/libsox.c @@ -0,0 +1,224 @@ +/* Implements the public API for libSoX general functions + * All public functions & data are prefixed with sox_ . + * + * (c) 2006-8 Chris Bagwell and SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +const char *sox_version(void) +{ + static char versionstr[20]; + + sprintf(versionstr, "%d.%d.%d", + (SOX_LIB_VERSION_CODE & 0xff0000) >> 16, + (SOX_LIB_VERSION_CODE & 0x00ff00) >> 8, + (SOX_LIB_VERSION_CODE & 0x0000ff)); + return(versionstr); +} + +sox_version_info_t const * sox_version_info(void) +{ +#define STRINGIZE1(x) #x +#define STRINGIZE(x) STRINGIZE1(x) + static char arch[30]; + static sox_version_info_t info = { + /* size */ + sizeof(sox_version_info_t), + /* flags */ + (sox_version_flags_t)( +#if HAVE_POPEN + sox_version_have_popen + +#endif +#if HAVE_MAGIC + sox_version_have_magic + +#endif +#if HAVE_OPENMP + sox_version_have_threads + +#endif +#ifdef HAVE_FMEMOPEN + sox_version_have_memopen + +#endif + sox_version_none), + /* version_code */ + SOX_LIB_VERSION_CODE, + /* version */ + NULL, + /* sox_version_extra */ +#ifdef PACKAGE_EXTRA + PACKAGE_EXTRA, +#else + NULL, +#endif + /* sox_time */ + __DATE__ " " __TIME__, + /* sox_distro */ +#ifdef DISTRO + DISTRO, +#else + NULL, +#endif + /* sox_compiler */ +#if defined __GNUC__ + "gcc " __VERSION__, +#elif defined _MSC_VER + "msvc " STRINGIZE(_MSC_FULL_VER), +#elif defined __SUNPRO_C + fprintf(file, "sun c " STRINGIZE(__SUNPRO_C), +#else + NULL, +#endif + /* sox_arch */ + NULL + }; + + if (!info.version) + { + info.version = sox_version(); + } + + if (!info.arch) + { + snprintf(arch, sizeof(arch), + "%" PRIuPTR "%" PRIuPTR "%" PRIuPTR "%" PRIuPTR + " %" PRIuPTR "%" PRIuPTR " %" PRIuPTR "%" PRIuPTR " %c %s", + sizeof(char), sizeof(short), sizeof(long), sizeof(off_t), + sizeof(float), sizeof(double), sizeof(int *), sizeof(int (*)(void)), + MACHINE_IS_BIGENDIAN ? 'B' : 'L', + (info.flags & sox_version_have_threads) ? "OMP" : ""); + arch[sizeof(arch) - 1] = 0; + info.arch = arch; + } + + return &info; +} + +/* Default routine to output messages; can be overridden */ +static void output_message( + unsigned level, const char *filename, const char *fmt, va_list ap) +{ + if (sox_globals.verbosity >= level) { + char base_name[128]; + sox_basename(base_name, sizeof(base_name), filename); + fprintf(stderr, "%s: ", base_name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } +} + +static sox_globals_t s_sox_globals = { + 2, /* unsigned verbosity */ + output_message, /* sox_output_message_handler */ + sox_false, /* sox_bool repeatable */ + 8192, /* size_t bufsiz */ + 0, /* size_t input_bufsiz */ + 0, /* int32_t ranqd1 */ + NULL, /* char const * stdin_in_use_by */ + NULL, /* char const * stdout_in_use_by */ + NULL, /* char const * subsystem */ + NULL, /* char * tmp_path */ + sox_false, /* sox_bool use_magic */ + sox_false, /* sox_bool use_threads */ + 10 /* size_t log2_dft_min_size */ +}; + +sox_globals_t * sox_get_globals(void) +{ + return &s_sox_globals; +} + +/* FIXME: Not thread safe using globals */ +static sox_effects_globals_t s_sox_effects_globals = + {sox_plot_off, &s_sox_globals}; + +sox_effects_globals_t * +sox_get_effects_globals(void) +{ + return &s_sox_effects_globals; +} + +char const * sox_strerror(int sox_errno) +{ + static char const * const errors[] = { + "Invalid Audio Header", + "Unsupported data format", + "Can't allocate memory", + "Operation not permitted", + "Operation not supported", + "Invalid argument", + }; + if (sox_errno < SOX_EHDR) + return strerror(sox_errno); + sox_errno -= SOX_EHDR; + if (sox_errno < 0 || (size_t)sox_errno >= array_length(errors)) + return "Unknown error"; + return errors[sox_errno]; +} + +size_t sox_basename(char * base_buffer, size_t base_buffer_len, const char * filename) +{ + if (!base_buffer || !base_buffer_len) + { + return 0; + } + else + { + char const * slash_pos = LAST_SLASH(filename); + char const * base_name = slash_pos ? slash_pos + 1 : filename; + char const * dot_pos = strrchr(base_name, '.'); + size_t i, len; + dot_pos = dot_pos ? dot_pos : base_name + strlen(base_name); + len = dot_pos - base_name; + len = min(len, base_buffer_len - 1); + for (i = 0; i < len; i++) + { + base_buffer[i] = base_name[i]; + } + base_buffer[i] = 0; + return i; + } +} + +#define SOX_MESSAGE_FUNCTION(name,level) \ +void name(char const * fmt, ...) { \ + va_list ap; \ + va_start(ap, fmt); \ + if (sox_globals.output_message_handler) \ + (*sox_globals.output_message_handler)(level,sox_globals.subsystem,fmt,ap); \ + va_end(ap); \ +} + +SOX_MESSAGE_FUNCTION(lsx_fail_impl , 1) +SOX_MESSAGE_FUNCTION(lsx_warn_impl , 2) +SOX_MESSAGE_FUNCTION(lsx_report_impl, 3) +SOX_MESSAGE_FUNCTION(lsx_debug_impl , 4) +SOX_MESSAGE_FUNCTION(lsx_debug_more_impl , 5) +SOX_MESSAGE_FUNCTION(lsx_debug_most_impl , 6) + +#undef SOX_MESSAGE_FUNCTION + +int sox_init(void) +{ + return lsx_effects_init(); +} + +int sox_quit(void) +{ + sox_format_quit(); + return lsx_effects_quit(); +} diff --git a/app/src/main/cpp/sox/libsox.sym b/app/src/main/cpp/sox/libsox.sym new file mode 100644 index 0000000..3962ea7 --- /dev/null +++ b/app/src/main/cpp/sox/libsox.sym @@ -0,0 +1,96 @@ +lsx_calloc +lsx_check_read_params +lsx_close_dllibrary +lsx_debug_impl +lsx_debug_more_impl +lsx_debug_most_impl +lsx_eof +lsx_error +lsx_fail_errno +lsx_fail_impl +lsx_filelength +lsx_find_enum_text +lsx_find_enum_value +lsx_find_file_extension +lsx_flush +lsx_getopt +lsx_getopt_init +lsx_id3_read_tag +lsx_lpc10_create_decoder_state +lsx_lpc10_create_encoder_state +lsx_lpc10_decode +lsx_lpc10_encode +lsx_malloc +lsx_open_dllibrary +lsx_rawread +lsx_rawwrite +lsx_read_b_buf +lsx_readbuf +lsx_readchars +lsx_realloc +lsx_realloc_array +lsx_report_impl +lsx_rewind +lsx_seeki +lsx_sigfigs3 +lsx_sigfigs3p +lsx_strcasecmp +lsx_strdup +lsx_tell +lsx_unreadb +lsx_warn_impl +lsx_write_b_buf +lsx_writeb +lsx_writebuf +lsx_writes +sox_add_effect +sox_append_comment +sox_append_comments +sox_basename +sox_close +sox_copy_comments +sox_create_effect +sox_create_effects_chain +sox_delete_comments +sox_delete_effect +sox_delete_effect_last +sox_delete_effects +sox_delete_effects_chain +sox_effect_options +sox_effects_clips +sox_find_comment +sox_find_effect +sox_find_format +sox_flow_effects +sox_format_init +sox_format_quit +sox_format_supports_encoding +sox_get_effect_fns +sox_get_effects_globals +sox_get_encodings_info +sox_get_format_fns +sox_get_globals +sox_init +sox_init_encodinginfo +sox_is_playlist +sox_num_comments +sox_open_mem_read +sox_open_mem_write +sox_open_memstream_write +sox_open_read +sox_open_write +sox_parse_playlist +sox_pop_effect_last +sox_precision +sox_push_effect_last +sox_quit +sox_read +sox_seek +sox_stop_effect +sox_strerror +sox_trim_clear_start +sox_trim_get_start +sox_version +sox_version_info +sox_write +sox_write_handler diff --git a/app/src/main/cpp/sox/libsox_i.c b/app/src/main/cpp/sox/libsox_i.c new file mode 100644 index 0000000..a5afb8e --- /dev/null +++ b/app/src/main/cpp/sox/libsox_i.c @@ -0,0 +1,116 @@ +/* libSoX internal functions that apply to both formats and effects + * All public functions & data are prefixed with lsx_ . + * + * Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "sox_i.h" + +#ifdef HAVE_IO_H + #include +#endif + +#ifdef HAVE_UNISTD_H + #include +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) + #define MKTEMP_X _O_BINARY|_O_TEMPORARY +#else + #define MKTEMP_X 0 +#endif + +#ifndef HAVE_MKSTEMP + #include + #include + #include + #define mkstemp(t) open(mktemp(t), MKTEMP_X|O_RDWR|O_TRUNC|O_CREAT, S_IREAD|S_IWRITE) + #define FAKE_MKSTEMP "fake " +#else + #define FAKE_MKSTEMP +#endif + +#ifdef WIN32 +static int check_dir(char * buf, size_t buflen, char const * name) +{ + struct stat st; + if (!name || stat(name, &st) || (st.st_mode & S_IFMT) != S_IFDIR) + { + return 0; + } + else + { + strncpy(buf, name, buflen); + buf[buflen - 1] = 0; + return strlen(name) == strlen(buf); + } +} +#endif + +FILE * lsx_tmpfile(void) +{ + char const * path = sox_globals.tmp_path; + + /* + On Win32, tmpfile() is broken - it creates the file in the root directory of + the current drive (the user probably doesn't have permission to write there!) + instead of in a valid temporary directory (like TEMP or TMP). So if tmp_path + is null, figure out a reasonable default. + To force use of tmpfile(), set sox_globals.tmp_path = "". + */ +#ifdef WIN32 + if (!path) + { + static char default_path[260] = ""; + if (default_path[0] == 0 + && !check_dir(default_path, sizeof(default_path), getenv("TEMP")) + && !check_dir(default_path, sizeof(default_path), getenv("TMP")) + #ifdef __CYGWIN__ + && !check_dir(default_path, sizeof(default_path), "/tmp") + #endif + ) + { + strcpy(default_path, "."); + } + + path = default_path; + } +#endif + + if (path && path[0]) { + /* Emulate tmpfile (delete on close); tmp dir is given tmp_path: */ + char const * const end = "/libSoX.tmp.XXXXXX"; + char * name = lsx_malloc(strlen(path) + strlen(end) + 1); + int fildes; + strcpy(name, path); + strcat(name, end); + fildes = mkstemp(name); +#ifdef HAVE_UNISTD_H + lsx_debug(FAKE_MKSTEMP "mkstemp, name=%s (unlinked)", name); + unlink(name); +#else + lsx_debug(FAKE_MKSTEMP "mkstemp, name=%s (O_TEMPORARY)", name); +#endif + free(name); + return fildes == -1? NULL : fdopen(fildes, "w+b"); + } + + /* Use standard tmpfile (delete on close); tmp dir is undefined: */ + lsx_debug("tmpfile()"); + return tmpfile(); +} diff --git a/app/src/main/cpp/sox/loudness.c b/app/src/main/cpp/sox/loudness.c new file mode 100644 index 0000000..eba86e6 --- /dev/null +++ b/app/src/main/cpp/sox/loudness.c @@ -0,0 +1,129 @@ +/* Effect: loudness filter Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "dft_filter.h" +#include + +typedef struct { + dft_filter_priv_t base; + double delta, start; + int n; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *)effp->priv; + dft_filter_priv_t * b = &p->base; + b->filter_ptr = &b->filter; + p->delta = -10; + p->start = 65; + p->n = 1023; + --argc, ++argv; + do { /* break-able block */ + NUMERIC_PARAMETER(delta,-50 , 15) /* FIXME expand range */ + NUMERIC_PARAMETER(start, 50 , 75) /* FIXME expand range */ + NUMERIC_PARAMETER(n ,127 ,2047) + } while (0); + p->n = 2 * p->n + 1; + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static double * make_filter(int n, double start, double delta, double rate) +{ + static const struct {double f, af, lu, tf;} iso226_table[] = { + { 20,0.532,-31.6,78.5},{ 25,0.506,-27.2,68.7},{ 31.5,0.480,-23.0,59.5}, + { 40,0.455,-19.1,51.1},{ 50,0.432,-15.9,44.0},{ 63,0.409,-13.0,37.5}, + { 80,0.387,-10.3,31.5},{ 100,0.367, -8.1,26.5},{ 125,0.349, -6.2,22.1}, + { 160,0.330, -4.5,17.9},{ 200,0.315, -3.1,14.4},{ 250,0.301, -2.0,11.4}, + { 315,0.288, -1.1, 8.6},{ 400,0.276, -0.4, 6.2},{ 500,0.267, 0.0, 4.4}, + { 630,0.259, 0.3, 3.0},{ 800,0.253, 0.5, 2.2},{ 1000,0.250, 0.0, 2.4}, + { 1250,0.246, -2.7, 3.5},{ 1600,0.244, -4.1, 1.7},{ 2000,0.243, -1.0,-1.3}, + { 2500,0.243, 1.7,-4.2},{ 3150,0.243, 2.5,-6.0},{ 4000,0.242, 1.2,-5.4}, + { 5000,0.242, -2.1,-1.5},{ 6300,0.245, -7.1, 6.0},{ 8000,0.254,-11.2,12.6}, + {10000,0.271,-10.7,13.9},{12500,0.301, -3.1,12.3}, + }; + #define LEN (array_length(iso226_table) + 2) + #define SPL(phon, t) (10 / t.af * log10(4.47e-3 * (pow(10., .025 * (phon)) - \ + 1.15) + pow(.4 * pow(10., (t.tf + t.lu) / 10 - 9), t.af)) - t.lu + 94) + double fs[LEN], spl[LEN], d[LEN], * work, * h; + int i, work_len; + + fs[0] = log(1.); + spl[0] = delta * .2; + for (i = 0; i < (int)LEN - 2; ++i) { + spl[i + 1] = SPL(start + delta, iso226_table[i]) - + SPL(start , iso226_table[i]); + fs[i + 1] = log(iso226_table[i].f); + } + fs[i + 1] = log(100000.); + spl[i + 1] = spl[0]; + lsx_prepare_spline3(fs, spl, (int)LEN, HUGE_VAL, HUGE_VAL, d); + + for (work_len = 8192; work_len < rate / 2; work_len <<= 1); + work = lsx_calloc(work_len, sizeof(*work)); + h = lsx_calloc(n, sizeof(*h)); + + for (i = 0; i <= work_len / 2; ++i) { + double f = rate * i / work_len; + double spl1 = f < 1? spl[0] : lsx_spline3(fs, spl, d, (int)LEN, log(f)); + work[i < work_len / 2 ? 2 * i : 1] = dB_to_linear(spl1); + } + lsx_safe_rdft(work_len, -1, work); + for (i = 0; i < n; ++i) + h[i] = work[(work_len - n / 2 + i) % work_len] * 2. / work_len; + lsx_apply_kaiser(h, n, lsx_kaiser_beta(40 + 2./3 * fabs(delta), .1)); + + free(work); + return h; + #undef SPL + #undef LEN +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + dft_filter_t * f = p->base.filter_ptr; + + if (p->delta == 0) + return SOX_EFF_NULL; + + if (!f->num_taps) { + double * h = make_filter(p->n, p->start, p->delta, effp->in_signal.rate); + if (effp->global_info->plot != sox_plot_off) { + char title[100]; + sprintf(title, "SoX effect: loudness %g (%g)", p->delta, p->start); + lsx_plot_fir(h, p->n, effp->in_signal.rate, + effp->global_info->plot, title, p->delta - 5, 0.); + return SOX_EOF; + } + lsx_set_dft_filter(f, h, p->n, p->n >> 1); + } + return lsx_dft_filter_effect_fn()->start(effp); +} + +sox_effect_handler_t const * lsx_loudness_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_dft_filter_effect_fn(); + handler.name = "loudness"; + handler.usage = "[gain [ref]]"; + handler.getopts = create; + handler.start = start; + handler.priv_size = sizeof(priv_t); + return &handler; +} diff --git a/app/src/main/cpp/sox/lpc10.c b/app/src/main/cpp/sox/lpc10.c new file mode 100644 index 0000000..58e9c11 --- /dev/null +++ b/app/src/main/cpp/sox/lpc10.c @@ -0,0 +1,225 @@ +/* libSoX lpc-10 format. + * + * Copyright 2007 Reuben Thomas + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include + +/* Private data */ +typedef struct { + struct lpc10_encoder_state *encst; + float speech[LPC10_SAMPLES_PER_FRAME]; + unsigned samples; + struct lpc10_decoder_state *decst; +} priv_t; + +/* + Write the bits in bits[0] through bits[len-1] to file f, in "packed" + format. + + bits is expected to be an array of len integer values, where each + integer is 0 to represent a 0 bit, and any other value represents a + 1 bit. This bit string is written to the file f in the form of + several 8 bit characters. If len is not a multiple of 8, then the + last character is padded with 0 bits -- the padding is in the least + significant bits of the last byte. The 8 bit characters are "filled" + in order from most significant bit to least significant. +*/ +static void write_bits(sox_format_t * ft, INT32 *bits, int len) +{ + int i; + uint8_t mask; /* The next bit position within the variable "data" to + place the next bit. */ + uint8_t data; /* The contents of the next byte to place in the + output. */ + + /* Fill in the array bits. + * The first compressed output bit will be the most significant + * bit of the byte, so initialize mask to 0x80. The next byte of + * compressed data is initially 0, and the desired bits will be + * turned on below. + */ + mask = 0x80; + data = 0; + + for (i = 0; i < len; i++) { + /* Turn on the next bit of output data, if necessary. */ + if (bits[i]) { + data |= mask; + } + /* + * If the byte data is full, determined by mask becoming 0, + * then write the byte to the output file, and reinitialize + * data and mask for the next output byte. Also add the byte + * if (i == len-1), because if len is not a multiple of 8, + * then mask won't yet be 0. */ + mask >>= 1; + if ((mask == 0) || (i == len-1)) { + lsx_writeb(ft, data); + data = 0; + mask = 0x80; + } + } +} + +/* + Read bits from file f into bits[0] through bits[len-1], in "packed" + format. + + Read ceiling(len/8) characters from file f, if that many are + available to read, otherwise read to the end of the file. The first + character's 8 bits, in order from MSB to LSB, are used to fill + bits[0] through bits[7]. The second character's bits are used to + fill bits[8] through bits[15], and so on. If ceiling(len/8) + characters are available to read, and len is not a multiple of 8, + then some of the least significant bits of the last character read + are completely ignored. Every entry of bits[] that is modified is + changed to either a 0 or a 1. + + The number of bits successfully read is returned, and is always in + the range 0 to len, inclusive. If it is less than len, it will + always be a multiple of 8. +*/ +static int read_bits(sox_format_t * ft, INT32 *bits, int len) +{ + int i; + uint8_t c = 0; + + /* Unpack the array bits into coded_frame. */ + for (i = 0; i < len; i++) { + if (i % 8 == 0) { + lsx_read_b_buf(ft, &c, (size_t) 1); + if (lsx_eof(ft)) { + return (i); + } + } + if (c & (0x80 >> (i & 7))) { + bits[i] = 1; + } else { + bits[i] = 0; + } + } + return (len); +} + +static int startread(sox_format_t * ft) +{ + priv_t * lpc = (priv_t *)ft->priv; + + if ((lpc->decst = create_lpc10_decoder_state()) == NULL) { + fprintf(stderr, "lpc10 could not allocate decoder state"); + return SOX_EOF; + } + lpc->samples = LPC10_SAMPLES_PER_FRAME; + return lsx_check_read_params(ft, 1, 8000., SOX_ENCODING_LPC10, 0, (uint64_t)0, sox_false); +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * lpc = (priv_t *)ft->priv; + + if ((lpc->encst = create_lpc10_encoder_state()) == NULL) { + fprintf(stderr, "lpc10 could not allocate encoder state"); + return SOX_EOF; + } + lpc->samples = 0; + + return SOX_SUCCESS; +} + +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t * lpc = (priv_t *)ft->priv; + size_t nread = 0; + + while (nread < len) { + SOX_SAMPLE_LOCALS; + /* Read more data if buffer is empty */ + if (lpc->samples == LPC10_SAMPLES_PER_FRAME) { + INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME]; + + if (read_bits(ft, bits, LPC10_BITS_IN_COMPRESSED_FRAME) != + LPC10_BITS_IN_COMPRESSED_FRAME) + break; + lpc10_decode(bits, lpc->speech, lpc->decst); + lpc->samples = 0; + } + + while (nread < len && lpc->samples < LPC10_SAMPLES_PER_FRAME) + buf[nread++] = SOX_FLOAT_32BIT_TO_SAMPLE(lpc->speech[lpc->samples++], ft->clips); + } + + return nread; +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * lpc = (priv_t *)ft->priv; + size_t nwritten = 0; + + while (len > 0) { + while (len > 0 && lpc->samples < LPC10_SAMPLES_PER_FRAME) { + SOX_SAMPLE_LOCALS; + lpc->speech[lpc->samples++] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[nwritten++], ft->clips); + len--; + } + + if (lpc->samples == LPC10_SAMPLES_PER_FRAME) { + INT32 bits[LPC10_BITS_IN_COMPRESSED_FRAME]; + + lpc10_encode(lpc->speech, bits, lpc->encst); + write_bits(ft, bits, LPC10_BITS_IN_COMPRESSED_FRAME); + lpc->samples = 0; + } + } + + return nwritten; +} + +static int stopread(sox_format_t * ft) +{ + priv_t * lpc = (priv_t *)ft->priv; + + free(lpc->decst); + + return SOX_SUCCESS; +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * lpc = (priv_t *)ft->priv; + + free(lpc->encst); + + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(lpc10) +{ + static char const * const names[] = {"lpc10", "lpc", NULL}; + static sox_rate_t const write_rates[] = {8000, 0}; + static unsigned const write_encodings[] = {SOX_ENCODING_LPC10, 0, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Low bandwidth, robotic sounding speech compression", names, SOX_FILE_MONO, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + NULL, write_encodings, write_rates, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/lu-fmt.c b/app/src/main/cpp/sox/lu-fmt.c new file mode 100644 index 0000000..6e29720 --- /dev/null +++ b/app/src/main/cpp/sox/lu-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT(lu, 8, SOX_FILE_BIT_REV, ULAW) diff --git a/app/src/main/cpp/sox/mat4.c b/app/src/main/cpp/sox/mat4.c new file mode 100644 index 0000000..7af2b93 --- /dev/null +++ b/app/src/main/cpp/sox/mat4.c @@ -0,0 +1,33 @@ +/* libSoX file format: MatLab4 Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(mat4) +{ + static char const * const names[] = {"mat4", "mat", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 32, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + 0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = "Gnu Octave 2.0 format"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/mat5.c b/app/src/main/cpp/sox/mat5.c new file mode 100644 index 0000000..e29a18d --- /dev/null +++ b/app/src/main/cpp/sox/mat5.c @@ -0,0 +1,33 @@ +/* libSoX file format: MatLab5 Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(mat5) +{ + static char const * const names[] = {"mat5", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 32, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + 0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = "Gnu Octave 2.1 format"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/maud.c b/app/src/main/cpp/sox/maud.c new file mode 100644 index 0000000..7bc716c --- /dev/null +++ b/app/src/main/cpp/sox/maud.c @@ -0,0 +1,344 @@ +/* libSoX MAUD file format handler, by Lutz Vieweg 1993 + * + * supports: mono and stereo, linear, a-law and u-law reading and writing + * + * an IFF format; description at http://lclevy.free.fr/amiga/MAUDINFO.TXT + * + * Copyright 1998-2006 Chris Bagwell and SoX Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" +#include +#include +#include +#include + +/* Private data for MAUD file */ +typedef struct { + uint32_t nsamples; +} priv_t; + +static void maudwriteheader(sox_format_t *); + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int startread(sox_format_t * ft) +{ + priv_t * p = (priv_t *) ft->priv; + + char buf[12]; + char *chunk_buf; + + unsigned short bitpersam; + uint32_t nom; + unsigned short denom; + unsigned short chaninf; + + uint32_t chunksize; + uint32_t trash32; + uint16_t trash16; + int rc; + + /* Needed for rawread() */ + rc = lsx_rawstartread(ft); + if (rc) + return rc; + + /* read FORM chunk */ + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "FORM", (size_t)4) != 0) + { + lsx_fail_errno(ft,SOX_EHDR,"MAUD: header does not begin with magic word `FORM'"); + return (SOX_EOF); + } + + lsx_readdw(ft, &trash32); /* totalsize */ + + if (lsx_reads(ft, buf, (size_t)4) == SOX_EOF || strncmp(buf, "MAUD", (size_t)4) != 0) + { + lsx_fail_errno(ft,SOX_EHDR,"MAUD: `FORM' chunk does not specify `MAUD' as type"); + return(SOX_EOF); + } + + /* read chunks until 'BODY' (or end) */ + + while (lsx_reads(ft, buf, (size_t)4) == SOX_SUCCESS && strncmp(buf,"MDAT",(size_t)4) != 0) { + + /* + buf[4] = 0; + lsx_debug("chunk %s",buf); + */ + + if (strncmp(buf,"MHDR",(size_t)4) == 0) { + + lsx_readdw(ft, &chunksize); + if (chunksize != 8*4) + { + lsx_fail_errno(ft,SOX_EHDR,"MAUD: MHDR chunk has bad size"); + return(SOX_EOF); + } + + /* number of samples stored in MDAT */ + lsx_readdw(ft, &(p->nsamples)); + + /* number of bits per sample as stored in MDAT */ + lsx_readw(ft, &bitpersam); + + /* number of bits per sample after decompression */ + lsx_readw(ft, &trash16); + + lsx_readdw(ft, &nom); /* clock source frequency */ + lsx_readw(ft, &denom); /* clock devide */ + if (denom == 0) + { + lsx_fail_errno(ft,SOX_EHDR,"MAUD: frequency denominator == 0, failed"); + return (SOX_EOF); + } + + ft->signal.rate = nom / denom; + + lsx_readw(ft, &chaninf); /* channel information */ + switch (chaninf) { + case 0: + ft->signal.channels = 1; + break; + case 1: + ft->signal.channels = 2; + break; + default: + lsx_fail_errno(ft,SOX_EFMT,"MAUD: unsupported number of channels in file"); + return (SOX_EOF); + } + + lsx_readw(ft, &chaninf); /* number of channels (mono: 1, stereo: 2, ...) */ + if (chaninf != ft->signal.channels) + { + lsx_fail_errno(ft,SOX_EFMT,"MAUD: unsupported number of channels in file"); + return(SOX_EOF); + } + + lsx_readw(ft, &chaninf); /* compression type */ + + lsx_readdw(ft, &trash32); /* rest of chunk, unused yet */ + lsx_readdw(ft, &trash32); + lsx_readdw(ft, &trash32); + + if (bitpersam == 8 && chaninf == 0) { + ft->encoding.bits_per_sample = 8; + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + } + else if (bitpersam == 8 && chaninf == 2) { + ft->encoding.bits_per_sample = 8; + ft->encoding.encoding = SOX_ENCODING_ALAW; + } + else if (bitpersam == 8 && chaninf == 3) { + ft->encoding.bits_per_sample = 8; + ft->encoding.encoding = SOX_ENCODING_ULAW; + } + else if (bitpersam == 16 && chaninf == 0) { + ft->encoding.bits_per_sample = 16; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + } + else + { + lsx_fail_errno(ft,SOX_EFMT,"MAUD: unsupported compression type detected"); + return(SOX_EOF); + } + + continue; + } + + if (strncmp(buf,"ANNO",(size_t)4) == 0) { + lsx_readdw(ft, &chunksize); + if (chunksize & 1) + chunksize++; + chunk_buf = lsx_malloc(chunksize + (size_t)1); + if (lsx_readbuf(ft, chunk_buf, (size_t)chunksize) + != chunksize) + { + lsx_fail_errno(ft,SOX_EOF,"MAUD: Unexpected EOF in ANNO header"); + return(SOX_EOF); + } + chunk_buf[chunksize] = '\0'; + lsx_debug("%s",chunk_buf); + free(chunk_buf); + + continue; + } + + /* some other kind of chunk */ + lsx_readdw(ft, &chunksize); + if (chunksize & 1) + chunksize++; + lsx_seeki(ft, (off_t)chunksize, SEEK_CUR); + continue; + + } + + if (strncmp(buf,"MDAT",(size_t)4) != 0) + { + lsx_fail_errno(ft,SOX_EFMT,"MAUD: MDAT chunk not found"); + return(SOX_EOF); + } + lsx_readdw(ft, &(p->nsamples)); + return(SOX_SUCCESS); +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * p = (priv_t *) ft->priv; + int rc; + + /* Needed for rawwrite() */ + rc = lsx_rawstartwrite(ft); + if (rc) + return rc; + + /* If you have to seek around the output file */ + if (! ft->seekable) + { + lsx_fail_errno(ft,SOX_EOF,"Output .maud file must be a file, not a pipe"); + return (SOX_EOF); + } + p->nsamples = 0x7f000000; + maudwriteheader(ft); + p->nsamples = 0; + return (SOX_SUCCESS); +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * p = (priv_t *) ft->priv; + + p->nsamples += len; + + return lsx_rawwrite(ft, buf, len); +} + +static int stopwrite(sox_format_t * ft) +{ + /* All samples are already written out. */ + + priv_t *p = (priv_t*)ft->priv; + uint32_t mdat_size; /* MDAT chunk size */ + mdat_size = p->nsamples * (ft->encoding.bits_per_sample >> 3); + lsx_padbytes(ft, (size_t) (mdat_size%2)); + + if (lsx_seeki(ft, (off_t)0, 0) != 0) + { + lsx_fail_errno(ft,errno,"can't rewind output file to rewrite MAUD header"); + return(SOX_EOF); + } + + maudwriteheader(ft); + return(SOX_SUCCESS); +} + +#define MAUDHEADERSIZE (4+(4+4+32)+(4+4+19+1)+(4+4)) +static void maudwriteheader(sox_format_t * ft) +{ + priv_t * p = (priv_t *) ft->priv; + uint32_t mdat_size; /* MDAT chunk size */ + + mdat_size = p->nsamples * (ft->encoding.bits_per_sample >> 3); + + lsx_writes(ft, "FORM"); + lsx_writedw(ft, MAUDHEADERSIZE + mdat_size + mdat_size%2); /* size of file */ + lsx_writes(ft, "MAUD"); /* File type */ + + lsx_writes(ft, "MHDR"); + lsx_writedw(ft, 8*4); /* number of bytes to follow */ + lsx_writedw(ft, p->nsamples); /* number of samples stored in MDAT */ + + switch (ft->encoding.encoding) { + + case SOX_ENCODING_UNSIGNED: + lsx_writew(ft, 8); /* number of bits per sample as stored in MDAT */ + lsx_writew(ft, 8); /* number of bits per sample after decompression */ + break; + + case SOX_ENCODING_SIGN2: + lsx_writew(ft, 16); /* number of bits per sample as stored in MDAT */ + lsx_writew(ft, 16); /* number of bits per sample after decompression */ + break; + + case SOX_ENCODING_ALAW: + case SOX_ENCODING_ULAW: + lsx_writew(ft, 8); /* number of bits per sample as stored in MDAT */ + lsx_writew(ft, 16); /* number of bits per sample after decompression */ + break; + + default: + break; + } + + lsx_writedw(ft, (unsigned)(ft->signal.rate + .5)); /* sample rate, Hz */ + lsx_writew(ft, (int) 1); /* clock devide */ + + if (ft->signal.channels == 1) { + lsx_writew(ft, 0); /* channel information */ + lsx_writew(ft, 1); /* number of channels (mono: 1, stereo: 2, ...) */ + } + else { + lsx_writew(ft, 1); + lsx_writew(ft, 2); + } + + switch (ft->encoding.encoding) { + + case SOX_ENCODING_UNSIGNED: + case SOX_ENCODING_SIGN2: + lsx_writew(ft, 0); /* no compression */ + break; + + case SOX_ENCODING_ULAW: + lsx_writew(ft, 3); + break; + + case SOX_ENCODING_ALAW: + lsx_writew(ft, 2); + break; + + default: + break; + } + + lsx_writedw(ft, 0); /* reserved */ + lsx_writedw(ft, 0); /* reserved */ + lsx_writedw(ft, 0); /* reserved */ + + lsx_writes(ft, "ANNO"); + lsx_writedw(ft, 19); /* length of block */ + lsx_writes(ft, "file created by SoX"); + lsx_padbytes(ft, (size_t)1); + + lsx_writes(ft, "MDAT"); + lsx_writedw(ft, p->nsamples * (ft->encoding.bits_per_sample >> 3)); /* samples in file */ +} + +LSX_FORMAT_HANDLER(maud) +{ + static char const * const names[] = {"maud", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 0, + SOX_ENCODING_UNSIGNED, 8, 0, + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_ALAW, 8, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Used with the ‘Toccata’ sound-card on the Amiga", + names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_STEREO, + startread, lsx_rawread, lsx_rawstopread, + startwrite, write_samples, stopwrite, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/mcompand.c b/app/src/main/cpp/sox/mcompand.c new file mode 100644 index 0000000..5682c5e --- /dev/null +++ b/app/src/main/cpp/sox/mcompand.c @@ -0,0 +1,524 @@ +/* multiband compander effect for SoX + * by Daniel Pouzzner 2002-Oct-8 + * + * Compander code adapted from the SoX compand effect, by Nick Bailey + * + * SoX is Copyright 1999 Chris Bagwell And Nick Bailey This source code is + * freely redistributable and may be used for any purpose. This copyright + * notice must be maintained. Chris Bagwell And Nick Bailey are not + * responsible for the consequences of using this software. + * + * + * Usage: + * mcompand quoted_compand_args [crossover_frequency + * quoted_compand_args [...]] + * + * quoted_compand_args are as for the compand effect: + * + * attack1,decay1[,attack2,decay2...] + * in-dB1,out-dB1[,in-dB2,out-dB2...] + * [ gain [ initial-volume [ delay ] ] ] + * + * Beware a variety of headroom (clipping) bugaboos. + * + * Implementation details: + * The input is divided into bands using 4th order Linkwitz-Riley IIRs. + * This is akin to the crossover of a loudspeaker, and results in flat + * frequency response absent compander action. + * + * The outputs of the array of companders is summed, and sample truncation + * is done on the final sum. + * + * Modifications to the predictive compression code properly maintain + * alignment of the outputs of the array of companders when the companders + * have different prediction intervals (volume application delays). Note + * that the predictive mode of the limiter needs some TLC - in fact, a + * rewrite - since what's really useful is to assure that a waveform won't + * be clipped, by slewing the volume in advance so that the peak is at + * limit (or below, if there's a higher subsequent peak visible in the + * lookahead window) once it's reached. */ + +#ifdef NDEBUG /* Enable assert always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox_i.h" +#include +#include +#include +#include "compandt.h" +#include "mcompand_xover.h" + +typedef struct { + sox_compandt_t transfer_fn; + + size_t expectedChannels; /* Also flags that channels aren't to be treated + individually when = 1 and input not mono */ + double *attackRate; /* An array of attack rates */ + double *decayRate; /* ... and of decay rates */ + double *volume; /* Current "volume" of each channel */ + double delay; /* Delay to apply before companding */ + double topfreq; /* upper bound crossover frequency */ + crossover_t filter; + sox_sample_t *delay_buf; /* Old samples, used for delay processing */ + size_t delay_size; /* lookahead for this band (in samples) - function of delay, above */ + ptrdiff_t delay_buf_ptr; /* Index into delay_buf */ + size_t delay_buf_cnt; /* No. of active entries in delay_buf */ +} comp_band_t; + +typedef struct { + size_t nBands; + sox_sample_t *band_buf1, *band_buf2, *band_buf3; + size_t band_buf_len; + size_t delay_buf_size;/* Size of delay_buf in samples */ + comp_band_t *bands; + + char *arg; /* copy of current argument */ +} priv_t; + +/* + * Process options + * + * Don't do initialization now. + * The 'info' fields are not yet filled in. + */ +static int sox_mcompand_getopts_1(comp_band_t * l, size_t n, char **argv) +{ + char *s; + size_t rates, i, commas; + + /* Start by checking the attack and decay rates */ + + for (s = argv[0], commas = 0; *s; ++s) + if (*s == ',') ++commas; + + if (commas % 2 == 0) /* There must be an even number of + attack/decay parameters */ + { + lsx_fail("compander: Odd number of attack & decay rate parameters"); + return (SOX_EOF); + } + + rates = 1 + commas/2; + l->attackRate = lsx_malloc(sizeof(double) * rates); + l->decayRate = lsx_malloc(sizeof(double) * rates); + l->volume = lsx_malloc(sizeof(double) * rates); + l->expectedChannels = rates; + l->delay_buf = NULL; + + /* Now tokenise the rates string and set up these arrays. Keep + them in seconds at the moment: we don't know the sample rate yet. */ + + s = strtok(argv[0], ","); i = 0; + do { + l->attackRate[i] = atof(s); s = strtok(NULL, ","); + l->decayRate[i] = atof(s); s = strtok(NULL, ","); + ++i; + } while (s != NULL); + + if (!lsx_compandt_parse(&l->transfer_fn, argv[1], n>2 ? argv[2] : 0)) + return SOX_EOF; + + /* Set the initial "volume" to be attibuted to the input channels. + Unless specified, choose 1.0 (maximum) otherwise clipping will + result if the user has seleced a long attack time */ + for (i = 0; i < l->expectedChannels; ++i) { + double v = n>=4 ? pow(10.0, atof(argv[3])/20) : 1.0; + l->volume[i] = v; + + /* If there is a delay, store it. */ + if (n >= 5) l->delay = atof(argv[4]); + else l->delay = 0.0; + } + return (SOX_SUCCESS); +} + +static int parse_subarg(char *s, char **subargv, size_t *subargc) { + char **ap; + char *s_p; + + s_p = s; + *subargc = 0; + for (ap = subargv; (*ap = strtok(s_p, " \t")) != NULL;) { + s_p = NULL; + if (*subargc == 5) { + ++*subargc; + break; + } + if (**ap != '\0') { + ++ap; + ++*subargc; + } + } + + if (*subargc < 2 || *subargc > 5) + { + lsx_fail("Wrong number of parameters for the compander effect within mcompand; usage:\n" + "\tattack1,decay1{,attack2,decay2} [soft-knee-dB:]in-dB1[,out-dB1]{,in-dB2,out-dB2} [gain [initial-volume-dB [delay]]]\n" + "\twhere {} means optional and repeatable and [] means optional.\n" + "\tdB values are floating point or -inf'; times are in seconds."); + return (SOX_EOF); + } else + return SOX_SUCCESS; +} + +static int getopts(sox_effect_t * effp, int argc, char **argv) +{ + char *subargv[6], *cp; + size_t subargc, i; + + priv_t * c = (priv_t *) effp->priv; + --argc, ++argv; + + c->band_buf1 = c->band_buf2 = c->band_buf3 = 0; + c->band_buf_len = 0; + + /* how many bands? */ + if (! (argc&1)) { + lsx_fail("mcompand accepts only an odd number of arguments:\argc" + " mcompand quoted_compand_args [crossover_freq quoted_compand_args [...]]"); + return SOX_EOF; + } + c->nBands = (argc+1)>>1; + + c->bands = lsx_calloc(c->nBands, sizeof(comp_band_t)); + + for (i=0;inBands;++i) { + c->arg = lsx_strdup(argv[i<<1]); + if (parse_subarg(c->arg,subargv,&subargc) != SOX_SUCCESS) + return SOX_EOF; + if (sox_mcompand_getopts_1(&c->bands[i], subargc, &subargv[0]) != SOX_SUCCESS) + return SOX_EOF; + free(c->arg); + c->arg = NULL; + if (i == (c->nBands-1)) + c->bands[i].topfreq = 0; + else { + c->bands[i].topfreq = lsx_parse_frequency(argv[(i<<1)+1],&cp); + if (*cp) { + lsx_fail("bad frequency in args to mcompand"); + return SOX_EOF; + } + if ((i>0) && (c->bands[i].topfreq < c->bands[i-1].topfreq)) { + lsx_fail("mcompand crossover frequencies must be in ascending order."); + return SOX_EOF; + } + } + } + + return SOX_SUCCESS; +} + +/* + * Prepare processing. + * Do all initializations. + */ +static int start(sox_effect_t * effp) +{ + priv_t * c = (priv_t *) effp->priv; + comp_band_t * l; + size_t i; + size_t band; + + for (band=0;bandnBands;++band) { + l = &c->bands[band]; + l->delay_size = c->bands[band].delay * effp->out_signal.rate * effp->out_signal.channels; + if (l->delay_size > c->delay_buf_size) + c->delay_buf_size = l->delay_size; + } + + for (band=0;bandnBands;++band) { + l = &c->bands[band]; + /* Convert attack and decay rates using number of samples */ + + for (i = 0; i < l->expectedChannels; ++i) { + if (l->attackRate[i] > 1.0/effp->out_signal.rate) + l->attackRate[i] = 1.0 - + exp(-1.0/(effp->out_signal.rate * l->attackRate[i])); + else + l->attackRate[i] = 1.0; + if (l->decayRate[i] > 1.0/effp->out_signal.rate) + l->decayRate[i] = 1.0 - + exp(-1.0/(effp->out_signal.rate * l->decayRate[i])); + else + l->decayRate[i] = 1.0; + } + + /* Allocate the delay buffer */ + if (c->delay_buf_size > 0) + l->delay_buf = lsx_calloc(sizeof(long), c->delay_buf_size); + l->delay_buf_ptr = 0; + l->delay_buf_cnt = 0; + + if (l->topfreq != 0) + crossover_setup(effp, &l->filter, l->topfreq); + } + return (SOX_SUCCESS); +} + +/* + * Update a volume value using the given sample + * value, the attack rate and decay rate + */ + +static void doVolume(double *v, double samp, comp_band_t * l, size_t chan) +{ + double s = samp/(~((sox_sample_t)1<<31)); + double delta = s - *v; + + if (delta > 0.0) /* increase volume according to attack rate */ + *v += delta * l->attackRate[chan]; + else /* reduce volume according to decay rate */ + *v += delta * l->decayRate[chan]; +} + +static int sox_mcompand_flow_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, const sox_sample_t *ibuf, sox_sample_t *obuf, size_t len, size_t filechans) +{ + size_t idone, odone; + + for (idone = 0, odone = 0; idone < len; ibuf += filechans) { + size_t chan; + + /* Maintain the volume fields by simulating a leaky pump circuit */ + + if (l->expectedChannels == 1 && filechans > 1) { + /* User is expecting same compander for all channels */ + double maxsamp = 0.0; + for (chan = 0; chan < filechans; ++chan) { + double rect = fabs((double)ibuf[chan]); + if (rect > maxsamp) + maxsamp = rect; + } + doVolume(&l->volume[0], maxsamp, l, (size_t) 0); + } else { + for (chan = 0; chan < filechans; ++chan) + doVolume(&l->volume[chan], fabs((double)ibuf[chan]), l, chan); + } + + /* Volume memory is updated: perform compand */ + for (chan = 0; chan < filechans; ++chan) { + int ch = l->expectedChannels > 1 ? chan : 0; + double level_in_lin = l->volume[ch]; + double level_out_lin = lsx_compandt(&l->transfer_fn, level_in_lin); + double checkbuf; + + if (c->delay_buf_size <= 0) { + checkbuf = ibuf[chan] * level_out_lin; + SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); + obuf[odone++] = checkbuf; + idone++; + } else { + /* FIXME: note that this lookahead algorithm is really lame: + the response to a peak is released before the peak + arrives. */ + + /* because volume application delays differ band to band, but + total delay doesn't, the volume is applied in an iteration + preceding that in which the sample goes to obuf, except in + the band(s) with the longest vol app delay. + + the offset between delay_buf_ptr and the sample to apply + vol to, is a constant equal to the difference between this + band's delay and the longest delay of all the bands. */ + + if (l->delay_buf_cnt >= l->delay_size) { + checkbuf = l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] * level_out_lin; + SOX_SAMPLE_CLIP_COUNT(checkbuf, effp->clips); + l->delay_buf[(l->delay_buf_ptr + c->delay_buf_size - l->delay_size)%c->delay_buf_size] = checkbuf; + } + if (l->delay_buf_cnt >= c->delay_buf_size) { + obuf[odone] = l->delay_buf[l->delay_buf_ptr]; + odone++; + idone++; + } else { + l->delay_buf_cnt++; + idone++; /* no "odone++" because we did not fill obuf[...] */ + } + l->delay_buf[l->delay_buf_ptr++] = ibuf[chan]; + l->delay_buf_ptr %= c->delay_buf_size; + } + } + } + + if (idone != odone || idone != len) { + /* Emergency brake - will lead to memory corruption otherwise since we + cannot report back to flow() how many samples were consumed/emitted. + Additionally, flow() doesn't know how to handle diverging + sub-compander delays. */ + lsx_fail("Using a compander delay within mcompand is currently not supported"); + exit(1); + /* FIXME */ + } + + return (SOX_SUCCESS); +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) { + priv_t * c = (priv_t *) effp->priv; + comp_band_t * l; + size_t len = min(*isamp, *osamp); + size_t band, i; + sox_sample_t *abuf, *bbuf, *cbuf, *oldabuf, *ibuf_copy; + double out; + + if (c->band_buf_len < len) { + c->band_buf1 = lsx_realloc(c->band_buf1,len*sizeof(sox_sample_t)); + c->band_buf2 = lsx_realloc(c->band_buf2,len*sizeof(sox_sample_t)); + c->band_buf3 = lsx_realloc(c->band_buf3,len*sizeof(sox_sample_t)); + c->band_buf_len = len; + } + + len -= len % effp->out_signal.channels; + + ibuf_copy = lsx_malloc(*isamp * sizeof(sox_sample_t)); + memcpy(ibuf_copy, ibuf, *isamp * sizeof(sox_sample_t)); + + /* split ibuf into bands using filters, pipe each band through sox_mcompand_flow_1, then add back together and write to obuf */ + + memset(obuf,0,len * sizeof *obuf); + for (band=0,abuf=ibuf_copy,bbuf=c->band_buf2,cbuf=c->band_buf1;bandnBands;++band) { + l = &c->bands[band]; + + if (l->topfreq) + crossover_flow(effp, &l->filter, abuf, bbuf, cbuf, len); + else { + bbuf = abuf; + abuf = cbuf; + } + if (abuf == ibuf_copy) + abuf = c->band_buf3; + (void)sox_mcompand_flow_1(effp, c,l,bbuf,abuf,len, (size_t)effp->out_signal.channels); + for (i=0;iclips); + obuf[i] = out; + } + oldabuf = abuf; + abuf = cbuf; + cbuf = oldabuf; + } + + *isamp = *osamp = len; + + free(ibuf_copy); + + return SOX_SUCCESS; +} + +static int sox_mcompand_drain_1(sox_effect_t * effp, priv_t * c, comp_band_t * l, sox_sample_t *obuf, size_t maxdrain) +{ + size_t done; + double out; + + /* + * Drain out delay samples. Note that this loop does all channels. + */ + for (done = 0; done < maxdrain && l->delay_buf_cnt > 0; done++) { + out = obuf[done] + l->delay_buf[l->delay_buf_ptr++]; + SOX_SAMPLE_CLIP_COUNT(out, effp->clips); + obuf[done] = out; + l->delay_buf_ptr %= c->delay_buf_size; + l->delay_buf_cnt--; + } + + /* tell caller number of samples played */ + return done; + +} + +/* + * Drain out compander delay lines. + */ +static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + size_t band, drained, mostdrained = 0; + priv_t * c = (priv_t *)effp->priv; + comp_band_t * l; + + *osamp -= *osamp % effp->out_signal.channels; + + memset(obuf,0,*osamp * sizeof *obuf); + for (band=0;bandnBands;++band) { + l = &c->bands[band]; + drained = sox_mcompand_drain_1(effp, c,l,obuf,*osamp); + if (drained > mostdrained) + mostdrained = drained; + } + + *osamp = mostdrained; + + if (mostdrained) + return SOX_SUCCESS; + else + return SOX_EOF; +} + +/* + * Clean up compander effect. + */ +static int stop(sox_effect_t * effp) +{ + priv_t * c = (priv_t *) effp->priv; + comp_band_t * l; + size_t band; + + free(c->band_buf1); + c->band_buf1 = NULL; + free(c->band_buf2); + c->band_buf2 = NULL; + free(c->band_buf3); + c->band_buf3 = NULL; + + for (band = 0; band < c->nBands; band++) { + l = &c->bands[band]; + free(l->delay_buf); + if (l->topfreq != 0) + free(l->filter.previous); + } + + return SOX_SUCCESS; +} + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * c = (priv_t *) effp->priv; + comp_band_t * l; + size_t band; + + for (band = 0; band < c->nBands; band++) { + l = &c->bands[band]; + lsx_compandt_kill(&l->transfer_fn); + free(l->decayRate); + free(l->attackRate); + free(l->volume); + } + free(c->arg); + free(c->bands); + c->bands = NULL; + + return SOX_SUCCESS; +} + +const sox_effect_handler_t *lsx_mcompand_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "mcompand", + "quoted_compand_args [crossover_frequency[k] quoted_compand_args [...]]\n" + "\n" + "quoted_compand_args are as for the compand effect:\n" + "\n" + " attack1,decay1[,attack2,decay2...]\n" + " in-dB1,out-dB1[,in-dB2,out-dB2...]\n" + " [ gain [ initial-volume [ delay ] ] ]", + SOX_EFF_MCHAN | SOX_EFF_GAIN, + getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t) + }; + + return &handler; +} diff --git a/app/src/main/cpp/sox/mcompand_xover.h b/app/src/main/cpp/sox/mcompand_xover.h new file mode 100644 index 0000000..cc2889e --- /dev/null +++ b/app/src/main/cpp/sox/mcompand_xover.h @@ -0,0 +1,106 @@ +/* libSoX Compander Crossover Filter (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define N 4 /* 4th order Linkwitz-Riley IIRs */ +#define CONVOLVE _ _ _ _ + +typedef struct {double in, out_low, out_high;} previous_t[N * 2]; + +typedef struct { + previous_t * previous; + size_t pos; + double coefs[3 *(N+1)]; +} crossover_t; + +static void square_quadratic(char const * name, double const * x, double * y) +{ + assert(N == 4); + y[0] = x[0] * x[0]; + y[1] = 2 * x[0] * x[1]; + y[2] = 2 * x[0] * x[2] + x[1] * x[1]; + y[3] = 2 * x[1] * x[2]; + y[4] = x[2] * x[2]; + lsx_debug("%s=[%.16g %.16g %.16g %.16g %.16g];", name, + y[0], y[1], y[2], y[3], y[4]); +} + +static int crossover_setup(sox_effect_t * effp, crossover_t * p, double frequency) +{ + double w0 = 2 * M_PI * frequency / effp->in_signal.rate; + double Q = sqrt(.5), alpha = sin(w0)/(2*Q); + double x[9], norm; + int i; + + if (w0 > M_PI) { + lsx_fail("frequency must not exceed half the sample-rate (Nyquist rate)"); + return SOX_EOF; + } + x[0] = (1 - cos(w0))/2; /* Cf. filter_LPF in biquads.c */ + x[1] = 1 - cos(w0); + x[2] = (1 - cos(w0))/2; + x[3] = (1 + cos(w0))/2; /* Cf. filter_HPF in biquads.c */ + x[4] = -(1 + cos(w0)); + x[5] = (1 + cos(w0))/2; + x[6] = 1 + alpha; + x[7] = -2*cos(w0); + x[8] = 1 - alpha; + for (norm = x[6], i = 0; i < 9; ++i) x[i] /= norm; + square_quadratic("lb", x , p->coefs); + square_quadratic("hb", x + 3, p->coefs + 5); + square_quadratic("a" , x + 6, p->coefs + 10); + + p->previous = lsx_calloc(effp->in_signal.channels, sizeof(*p->previous)); + return SOX_SUCCESS; +} + +static int crossover_flow(sox_effect_t * effp, crossover_t * p, sox_sample_t + *ibuf, sox_sample_t *obuf_low, sox_sample_t *obuf_high, size_t len0) +{ + double out_low, out_high; + size_t c, len = len0 / effp->in_signal.channels; + assert(len * effp->in_signal.channels == len0); + + while (len--) { + p->pos = p->pos? p->pos - 1 : N - 1; + for (c = 0; c < effp->in_signal.channels; ++c) { +#define _ out_low += p->coefs[j] * p->previous[c][p->pos + j].in \ + - p->coefs[2*N+2 + j] * p->previous[c][p->pos + j].out_low, ++j; + { + int j = 1; + out_low = p->coefs[0] * *ibuf; + CONVOLVE + assert(j == N+1); + *obuf_low++ = SOX_ROUND_CLIP_COUNT(out_low, effp->clips); + } +#undef _ +#define _ out_high += p->coefs[j+N+1] * p->previous[c][p->pos + j].in \ + - p->coefs[2*N+2 + j] * p->previous[c][p->pos + j].out_high, ++j; + { + int j = 1; + out_high = p->coefs[N+1] * *ibuf; + CONVOLVE + assert(j == N+1); + *obuf_high++ = SOX_ROUND_CLIP_COUNT(out_high, effp->clips); + } + p->previous[c][p->pos + N].in = p->previous[c][p->pos].in = *ibuf++; + p->previous[c][p->pos + N].out_low = p->previous[c][p->pos].out_low = out_low; + p->previous[c][p->pos + N].out_high = p->previous[c][p->pos].out_high = out_high; + } + } + return SOX_SUCCESS; +} + diff --git a/app/src/main/cpp/sox/mp3-util.h b/app/src/main/cpp/sox/mp3-util.h new file mode 100644 index 0000000..d896f28 --- /dev/null +++ b/app/src/main/cpp/sox/mp3-util.h @@ -0,0 +1,171 @@ +/* libSoX MP3 utilities Copyright (c) 2007-9 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#if defined(HAVE_LAME) + +static void write_comments(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + const char* comment; + + p->id3tag_init(p->gfp); + p->id3tag_set_pad(p->gfp, (size_t)ID3PADDING); + + /* Note: id3tag_set_fieldvalue is not present in LAME 3.97, so we're using + the 3.97-compatible methods for all of the tags that 3.97 supported. */ + /* FIXME: This is no more necessary, since support for LAME 3.97 has ended. */ + if ((comment = sox_find_comment(ft->oob.comments, "Title"))) + p->id3tag_set_title(p->gfp, comment); + if ((comment = sox_find_comment(ft->oob.comments, "Artist"))) + p->id3tag_set_artist(p->gfp, comment); + if ((comment = sox_find_comment(ft->oob.comments, "Album"))) + p->id3tag_set_album(p->gfp, comment); + if ((comment = sox_find_comment(ft->oob.comments, "Tracknumber"))) + p->id3tag_set_track(p->gfp, comment); + if ((comment = sox_find_comment(ft->oob.comments, "Year"))) + p->id3tag_set_year(p->gfp, comment); + if ((comment = sox_find_comment(ft->oob.comments, "Comment"))) + p->id3tag_set_comment(p->gfp, comment); + if ((comment = sox_find_comment(ft->oob.comments, "Genre"))) + { + if (p->id3tag_set_genre(p->gfp, comment)) + lsx_warn("\"%s\" is not a recognized ID3v1 genre.", comment); + } + + if ((comment = sox_find_comment(ft->oob.comments, "Discnumber"))) + { + char* id3tag_buf = lsx_malloc(strlen(comment) + 6); + if (id3tag_buf) + { + sprintf(id3tag_buf, "TPOS=%s", comment); + p->id3tag_set_fieldvalue(p->gfp, id3tag_buf); + free(id3tag_buf); + } + } +} + +#endif /* HAVE_LAME */ + +#ifdef HAVE_MAD_H + +static unsigned long xing_frames(priv_t * p, struct mad_bitptr ptr, unsigned bitlen) +{ + #define XING_MAGIC ( ('X' << 24) | ('i' << 16) | ('n' << 8) | 'g' ) + if (bitlen >= 96 && p->mad_bit_read(&ptr, 32) == XING_MAGIC && + (p->mad_bit_read(&ptr, 32) & 1 )) /* XING_FRAMES */ + return p->mad_bit_read(&ptr, 32); + return 0; +} + +static size_t mp3_duration(sox_format_t * ft) +{ + priv_t * p = (priv_t *) ft->priv; + struct mad_stream mad_stream; + struct mad_header mad_header; + struct mad_frame mad_frame; + size_t initial_bitrate = 0; /* Initialised to prevent warning */ + size_t tagsize = 0, consumed = 0, frames = 0; + sox_bool vbr = sox_false, depadded = sox_false; + size_t num_samples = 0; + + p->mad_stream_init(&mad_stream); + p->mad_header_init(&mad_header); + p->mad_frame_init(&mad_frame); + + do { /* Read data from the MP3 file */ + int read, padding = 0; + size_t leftover = mad_stream.bufend - mad_stream.next_frame; + + memmove(p->mp3_buffer, mad_stream.this_frame, leftover); + read = lsx_readbuf(ft, p->mp3_buffer + leftover, p->mp3_buffer_size - leftover); + if (read <= 0) { + lsx_debug("got exact duration by scan to EOF (frames=%" PRIuPTR " leftover=%" PRIuPTR ")", frames, leftover); + break; + } + for (; !depadded && padding < read && !p->mp3_buffer[padding]; ++padding); + depadded = sox_true; + p->mad_stream_buffer(&mad_stream, p->mp3_buffer + padding, leftover + read - padding); + + while (sox_true) { /* Decode frame headers */ + mad_stream.error = MAD_ERROR_NONE; + if (p->mad_header_decode(&mad_header, &mad_stream) == -1) { + if (mad_stream.error == MAD_ERROR_BUFLEN) + break; /* Normal behaviour; get some more data from the file */ + if (!MAD_RECOVERABLE(mad_stream.error)) { + lsx_warn("unrecoverable MAD error"); + break; + } + if (mad_stream.error == MAD_ERROR_LOSTSYNC) { + unsigned available = (mad_stream.bufend - mad_stream.this_frame); + tagsize = tagtype(mad_stream.this_frame, (size_t) available); + if (tagsize) { /* It's some ID3 tags, so just skip */ + if (tagsize >= available) { + lsx_seeki(ft, (off_t)(tagsize - available), SEEK_CUR); + depadded = sox_false; + } + p->mad_stream_skip(&mad_stream, min(tagsize, available)); + } + else lsx_warn("MAD lost sync"); + } + else lsx_warn("recoverable MAD error"); + continue; /* Not an audio frame */ + } + + num_samples += MAD_NSBSAMPLES(&mad_header) * 32; + consumed += mad_stream.next_frame - mad_stream.this_frame; + + lsx_debug_more("bitrate=%lu", mad_header.bitrate); + if (!frames) { + initial_bitrate = mad_header.bitrate; + + /* Get the precise frame count from the XING header if present */ + mad_frame.header = mad_header; + if (p->mad_frame_decode(&mad_frame, &mad_stream) == -1) + if (!MAD_RECOVERABLE(mad_stream.error)) { + lsx_warn("unrecoverable MAD error"); + break; + } + if ((frames = xing_frames(p, mad_stream.anc_ptr, mad_stream.anc_bitlen))) { + num_samples *= frames; + lsx_debug("got exact duration from XING frame count (%" PRIuPTR ")", frames); + break; + } + } + else vbr |= mad_header.bitrate != initial_bitrate; + + /* If not VBR, we can time just a few frames then extrapolate */ + if (++frames == 25 && !vbr) { + double frame_size = (double) consumed / frames; + size_t num_frames = (lsx_filelength(ft) - tagsize) / frame_size; + num_samples = num_samples / frames * num_frames; + lsx_debug("got approx. duration by CBR extrapolation"); + break; + } + } + } while (mad_stream.error == MAD_ERROR_BUFLEN); + + p->mad_frame_finish(&mad_frame); + mad_header_finish(&mad_header); + p->mad_stream_finish(&mad_stream); + lsx_rewind(ft); + + return num_samples; +} + +#endif /* HAVE_MAD_H */ diff --git a/app/src/main/cpp/sox/mp3.c b/app/src/main/cpp/sox/mp3.c new file mode 100644 index 0000000..1fd144d --- /dev/null +++ b/app/src/main/cpp/sox/mp3.c @@ -0,0 +1,1299 @@ +/* MP3 support for SoX + * + * Uses libmad for MP3 decoding + * libmp3lame for MP3 encoding + * and libtwolame for MP2 encoding + * + * Written by Fabrizio Gennari + * + * The decoding part is based on the decoder-tutorial program madlld + * written by Bertrand Petit , + */ + +#include "sox_i.h" +#include + +#if defined(HAVE_LAME_LAME_H) || defined(HAVE_LAME_H) || defined(DL_LAME) +#define HAVE_LAME 1 +#endif + +#if defined(HAVE_TWOLAME_H) || defined(DL_TWOLAME) + #define HAVE_TWOLAME 1 +#endif + +#if defined(HAVE_MAD_H) || defined(HAVE_LAME) || defined(HAVE_TWOLAME) + +#ifdef HAVE_MAD_H +#include +#endif + +#if defined(HAVE_LAME_LAME_H) +#include +#elif defined(HAVE_LAME_H) +#include +#elif defined(DL_LAME) +typedef struct lame_global_struct lame_global_flags; +typedef enum { + vbr_off=0, + vbr_default=4 +} vbr_mode; +#endif + +#if defined(HAVE_ID3TAG) && (defined(HAVE_IO_H) || defined(HAVE_UNISTD_H)) +#define USING_ID3TAG 1 +#endif + +#ifdef USING_ID3TAG + #include + #include "id3.h" +#if defined(HAVE_UNISTD_H) + #include +#elif defined(HAVE_IO_H) + #include +#endif +#else + #define ID3_TAG_FLAG_FOOTERPRESENT 0x10 +#endif + +#ifdef HAVE_TWOLAME_H + #include +#endif + +/* Under Windows, importing data from DLLs is a dicey proposition. This is true + * when using dlopen, but also true if linking directly against the DLL if the + * header does not mark the data as __declspec(dllexport), which mad.h does not. + * Sidestep the issue by defining our own mad_timer_zero. This is needed because + * mad_timer_zero is used in some of the mad.h macros. + */ +#ifdef HAVE_MAD_H +#define mad_timer_zero mad_timer_zero_stub +static mad_timer_t const mad_timer_zero_stub = {0, 0}; +#endif + +#define MAXFRAMESIZE 2880 +#define ID3PADDING 128 + +/* LAME takes float values as input. */ +#define MP3_LAME_PRECISION 24 + +/* MAD returns values with MAD_F_FRACBITS (28) bits of precision, though it's + not certain that all of them are meaningful. Default to 16 bits to + align with most users expectation of output file should be 16 bits. */ +#define MP3_MAD_PRECISION 16 + +static const char* const mad_library_names[] = +{ +#ifdef DL_MAD + "libmad", + "libmad-0", + "cygmad-0", +#endif + NULL +}; + +#ifdef DL_MAD + #define MAD_FUNC LSX_DLENTRY_DYNAMIC +#else + #define MAD_FUNC LSX_DLENTRY_STATIC +#endif + +#define MAD_FUNC_ENTRIES(f,x) \ + MAD_FUNC(f,x, void, mad_stream_buffer, (struct mad_stream *, unsigned char const *, unsigned long)) \ + MAD_FUNC(f,x, void, mad_stream_skip, (struct mad_stream *, unsigned long)) \ + MAD_FUNC(f,x, int, mad_stream_sync, (struct mad_stream *)) \ + MAD_FUNC(f,x, void, mad_stream_init, (struct mad_stream *)) \ + MAD_FUNC(f,x, void, mad_frame_init, (struct mad_frame *)) \ + MAD_FUNC(f,x, void, mad_synth_init, (struct mad_synth *)) \ + MAD_FUNC(f,x, int, mad_frame_decode, (struct mad_frame *, struct mad_stream *)) \ + MAD_FUNC(f,x, void, mad_timer_add, (mad_timer_t *, mad_timer_t)) \ + MAD_FUNC(f,x, void, mad_synth_frame, (struct mad_synth *, struct mad_frame const *)) \ + MAD_FUNC(f,x, char const *, mad_stream_errorstr, (struct mad_stream const *)) \ + MAD_FUNC(f,x, void, mad_frame_finish, (struct mad_frame *)) \ + MAD_FUNC(f,x, void, mad_stream_finish, (struct mad_stream *)) \ + MAD_FUNC(f,x, unsigned long, mad_bit_read, (struct mad_bitptr *, unsigned int)) \ + MAD_FUNC(f,x, int, mad_header_decode, (struct mad_header *, struct mad_stream *)) \ + MAD_FUNC(f,x, void, mad_header_init, (struct mad_header *)) \ + MAD_FUNC(f,x, signed long, mad_timer_count, (mad_timer_t, enum mad_units)) \ + MAD_FUNC(f,x, void, mad_timer_multiply, (mad_timer_t *, signed long)) + +static const char* const lame_library_names[] = +{ +#ifdef DL_LAME + "libmp3lame", + "libmp3lame-0", + "lame-enc", + "cygmp3lame-0", +#endif + NULL +}; + +#ifdef DL_LAME + #define LAME_FUNC LSX_DLENTRY_DYNAMIC +#else /* DL_LAME */ + #define LAME_FUNC LSX_DLENTRY_STATIC +#endif /* DL_LAME */ + +#define LAME_FUNC_ENTRIES(f,x) \ + LAME_FUNC(f,x, lame_global_flags*, lame_init, (void)) \ + LAME_FUNC(f,x, int, lame_set_errorf, (lame_global_flags *, void (*)(const char *, va_list))) \ + LAME_FUNC(f,x, int, lame_set_debugf, (lame_global_flags *, void (*)(const char *, va_list))) \ + LAME_FUNC(f,x, int, lame_set_msgf, (lame_global_flags *, void (*)(const char *, va_list))) \ + LAME_FUNC(f,x, int, lame_set_num_samples, (lame_global_flags *, unsigned long)) \ + LAME_FUNC(f,x, int, lame_get_num_channels, (const lame_global_flags *)) \ + LAME_FUNC(f,x, int, lame_set_num_channels, (lame_global_flags *, int)) \ + LAME_FUNC(f,x, int, lame_set_in_samplerate, (lame_global_flags *, int)) \ + LAME_FUNC(f,x, int, lame_set_out_samplerate, (lame_global_flags *, int)) \ + LAME_FUNC(f,x, int, lame_set_bWriteVbrTag, (lame_global_flags *, int)) \ + LAME_FUNC(f,x, int, lame_set_brate, (lame_global_flags *, int)) \ + LAME_FUNC(f,x, int, lame_set_quality, (lame_global_flags *, int)) \ + LAME_FUNC(f,x, vbr_mode, lame_get_VBR, (const lame_global_flags *)) \ + LAME_FUNC(f,x, int, lame_set_VBR, (lame_global_flags *, vbr_mode)) \ + LAME_FUNC(f,x, int, lame_set_VBR_q, (lame_global_flags *, int)) \ + LAME_FUNC(f,x, int, lame_init_params, (lame_global_flags *)) \ + LAME_FUNC(f,x, int, lame_encode_buffer_float, (lame_global_flags *, const float[], const float[], const int, unsigned char *, const int)) \ + LAME_FUNC(f,x, int, lame_encode_flush, (lame_global_flags *, unsigned char *, int)) \ + LAME_FUNC(f,x, int, lame_close, (lame_global_flags *)) \ + LAME_FUNC(f,x, size_t, lame_get_lametag_frame, (const lame_global_flags *, unsigned char*, size_t)) \ + LAME_FUNC(f,x, void, id3tag_init, (lame_global_flags *)) \ + LAME_FUNC(f,x, void, id3tag_set_title, (lame_global_flags *, const char* title)) \ + LAME_FUNC(f,x, void, id3tag_set_artist, (lame_global_flags *, const char* artist)) \ + LAME_FUNC(f,x, void, id3tag_set_album, (lame_global_flags *, const char* album)) \ + LAME_FUNC(f,x, void, id3tag_set_year, (lame_global_flags *, const char* year)) \ + LAME_FUNC(f,x, void, id3tag_set_comment, (lame_global_flags *, const char* comment)) \ + LAME_FUNC(f,x, int, id3tag_set_track, (lame_global_flags *, const char* track)) \ + LAME_FUNC(f,x, int, id3tag_set_genre, (lame_global_flags *, const char* genre)) \ + LAME_FUNC(f,x, size_t, id3tag_set_pad, (lame_global_flags *, size_t)) \ + LAME_FUNC(f,x, size_t, lame_get_id3v2_tag, (lame_global_flags *, unsigned char*, size_t)) \ + LAME_FUNC(f,x, int, id3tag_set_fieldvalue, (lame_global_flags *, const char *)) + +#ifdef HAVE_TWOLAME +static const char* const twolame_library_names[] = +{ +#ifdef DL_TWOLAME + "libtwolame", + "libtwolame-0", +#endif + NULL +}; +#endif + +#ifdef DL_TWOLAME + #define TWOLAME_FUNC LSX_DLENTRY_DYNAMIC +#else + #define TWOLAME_FUNC LSX_DLENTRY_STATIC +#endif + +#define TWOLAME_FUNC_ENTRIES(f,x) \ + TWOLAME_FUNC(f,x, twolame_options*, twolame_init, (void)) \ + TWOLAME_FUNC(f,x, int, twolame_get_num_channels, (twolame_options*)) \ + TWOLAME_FUNC(f,x, int, twolame_set_num_channels, (twolame_options*, int)) \ + TWOLAME_FUNC(f,x, int, twolame_set_in_samplerate, (twolame_options *, int)) \ + TWOLAME_FUNC(f,x, int, twolame_set_out_samplerate, (twolame_options *, int)) \ + TWOLAME_FUNC(f,x, int, twolame_set_brate, (twolame_options *, int)) \ + TWOLAME_FUNC(f,x, int, twolame_init_params, (twolame_options *)) \ + TWOLAME_FUNC(f,x, int, twolame_encode_buffer_float32_interleaved, (twolame_options *, const float [], int, unsigned char *, int)) \ + TWOLAME_FUNC(f,x, int, twolame_encode_flush, (twolame_options *, unsigned char *, int)) \ + TWOLAME_FUNC(f,x, void, twolame_close, (twolame_options **)) + +/* Private data */ +typedef struct mp3_priv_t { + unsigned char *mp3_buffer; + size_t mp3_buffer_size; + +#ifdef HAVE_MAD_H + struct mad_stream Stream; + struct mad_frame Frame; + struct mad_synth Synth; + mad_timer_t Timer; + ptrdiff_t cursamp; + size_t FrameCount; + LSX_DLENTRIES_TO_PTRS(MAD_FUNC_ENTRIES, mad_dl); +#endif /*HAVE_MAD_H*/ + +#if defined(HAVE_LAME) || defined(HAVE_TWOLAME) + float *pcm_buffer; + size_t pcm_buffer_size; + char mp2; +#endif + +#ifdef HAVE_LAME + lame_global_flags *gfp; + uint64_t num_samples; + int vbr_tag; + LSX_DLENTRIES_TO_PTRS(LAME_FUNC_ENTRIES, lame_dl); +#endif + +#ifdef HAVE_TWOLAME + twolame_options *opt; + LSX_DLENTRIES_TO_PTRS(TWOLAME_FUNC_ENTRIES, twolame_dl); +#endif +} priv_t; + +#ifdef HAVE_MAD_H + +/* This function merges the functions tagtype() and id3_tag_query() + from MAD's libid3tag, so we don't have to link to it + Returns 0 if the frame is not an ID3 tag, tag length if it is */ + +static int tagtype(const unsigned char *data, size_t length) +{ + if (length >= 3 && data[0] == 'T' && data[1] == 'A' && data[2] == 'G') + { + return 128; /* ID3V1 */ + } + + if (length >= 10 && + (data[0] == 'I' && data[1] == 'D' && data[2] == '3') && + data[3] < 0xff && data[4] < 0xff && + data[6] < 0x80 && data[7] < 0x80 && data[8] < 0x80 && data[9] < 0x80) + { /* ID3V2 */ + unsigned char flags; + unsigned int size; + flags = data[5]; + size = 10 + (data[6]<<21) + (data[7]<<14) + (data[8]<<7) + data[9]; + if (flags & ID3_TAG_FLAG_FOOTERPRESENT) + size += 10; + for (; size < length && !data[size]; ++size); /* Consume padding */ + return size; + } + + return 0; +} + +#endif /*HAVE_MAD_H*/ + +#include "mp3-util.h" + +#ifdef HAVE_MAD_H + +/* + * (Re)fill the stream buffer that is to be decoded. If any data + * still exists in the buffer then they are first shifted to be + * front of the stream buffer. + */ +static int sox_mp3_input(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + size_t bytes_read; + size_t remaining; + + remaining = p->Stream.bufend - p->Stream.next_frame; + + /* libmad does not consume all the buffer it's given. Some + * data, part of a truncated frame, is left unused at the + * end of the buffer. That data must be put back at the + * beginning of the buffer and taken in account for + * refilling the buffer. This means that the input buffer + * must be large enough to hold a complete frame at the + * highest observable bit-rate (currently 448 kb/s). + * TODO: Is 2016 bytes the size of the largest frame? + * (448000*(1152/32000))/8 + */ + memmove(p->mp3_buffer, p->Stream.next_frame, remaining); + + bytes_read = lsx_readbuf(ft, p->mp3_buffer+remaining, + p->mp3_buffer_size-remaining); + if (bytes_read == 0) + { + return SOX_EOF; + } + + p->mad_stream_buffer(&p->Stream, p->mp3_buffer, bytes_read+remaining); + p->Stream.error = 0; + + return SOX_SUCCESS; +} + +/* Attempts to read an ID3 tag at the current location in stream and + * consume it all. Returns SOX_EOF if no tag is found. Its up to + * caller to recover. + * */ +static int sox_mp3_inputtag(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + int rc = SOX_EOF; + size_t remaining; + size_t tagsize; + + + /* FIXME: This needs some more work if we are to ever + * look at the ID3 frame. This is because the Stream + * may not be able to hold the complete ID3 frame. + * We should consume the whole frame inside tagtype() + * instead of outside of tagframe(). That would support + * recovering when Stream contains less then 8-bytes (header) + * and also when ID3v2 is bigger then Stream buffer size. + * Need to pass in stream so that buffer can be + * consumed as well as letting additional data to be + * read in. + */ + remaining = p->Stream.bufend - p->Stream.next_frame; + if ((tagsize = tagtype(p->Stream.this_frame, remaining))) + { + p->mad_stream_skip(&p->Stream, tagsize); + rc = SOX_SUCCESS; + } + + /* We know that a valid frame hasn't been found yet + * so help libmad out and go back into frame seek mode. + * This is true whether an ID3 tag was found or not. + */ + p->mad_stream_sync(&p->Stream); + + return rc; +} + +static sox_bool sox_mp3_vbrtag(sox_format_t *ft) +{ + priv_t *p = ft->priv; + struct mad_bitptr *anc = &p->Stream.anc_ptr; + + if (p->Frame.header.layer != MAD_LAYER_III) + return sox_false; + + if (p->Stream.anc_bitlen < 32) + return sox_false; + + if (!memcmp(anc->byte, "Xing", 4) || + !memcmp(anc->byte, "Info", 4)) + return sox_true; + + return sox_false; +} + +static int startread(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + size_t ReadSize; + sox_bool ignore_length = ft->signal.length == SOX_IGNORE_LENGTH; + int open_library_result; + + LSX_DLLIBRARY_OPEN( + p, + mad_dl, + MAD_FUNC_ENTRIES, + "MAD decoder library", + mad_library_names, + open_library_result); + if (open_library_result) + return SOX_EOF; + + p->mp3_buffer_size = sox_globals.bufsiz; + p->mp3_buffer = lsx_malloc(p->mp3_buffer_size); + + ft->signal.length = SOX_UNSPEC; + if (ft->seekable) { +#ifdef USING_ID3TAG + lsx_id3_read_tag(ft, sox_true); + lsx_rewind(ft); + if (!ft->signal.length) +#endif + if (!ignore_length) + ft->signal.length = mp3_duration(ft); + } + + p->mad_stream_init(&p->Stream); + p->mad_frame_init(&p->Frame); + p->mad_synth_init(&p->Synth); + mad_timer_reset(&p->Timer); + + ft->encoding.encoding = SOX_ENCODING_MP3; + + /* Decode at least one valid frame to find out the input + * format. The decoded frame will be saved off so that it + * can be processed later. + */ + ReadSize = lsx_readbuf(ft, p->mp3_buffer, p->mp3_buffer_size); + if (ReadSize != p->mp3_buffer_size && lsx_error(ft)) + return SOX_EOF; + + p->mad_stream_buffer(&p->Stream, p->mp3_buffer, ReadSize); + + /* Find a valid frame before starting up. This makes sure + * that we have a valid MP3 and also skips past ID3v2 tags + * at the beginning of the audio file. + */ + p->Stream.error = 0; + while (p->mad_frame_decode(&p->Frame,&p->Stream)) + { + /* check whether input buffer needs a refill */ + if (p->Stream.error == MAD_ERROR_BUFLEN) + { + if (sox_mp3_input(ft) == SOX_EOF) + return SOX_EOF; + + continue; + } + + /* Consume any ID3 tags */ + sox_mp3_inputtag(ft); + + /* FIXME: We should probably detect when we've read + * a bunch of non-ID3 data and still haven't found a + * frame. In that case we can abort early without + * scanning the whole file. + */ + p->Stream.error = 0; + } + + if (p->Stream.error) + { + lsx_fail_errno(ft,SOX_EOF,"No valid MP3 frame found"); + return SOX_EOF; + } + + switch(p->Frame.header.mode) + { + case MAD_MODE_SINGLE_CHANNEL: + case MAD_MODE_DUAL_CHANNEL: + case MAD_MODE_JOINT_STEREO: + case MAD_MODE_STEREO: + ft->signal.channels = MAD_NCHANNELS(&p->Frame.header); + break; + default: + lsx_fail_errno(ft, SOX_EFMT, "Cannot determine number of channels"); + return SOX_EOF; + } + + ft->signal.precision = MP3_MAD_PRECISION; + ft->signal.rate=p->Frame.header.samplerate; + if (ignore_length) + ft->signal.length = SOX_UNSPEC; + else { + ft->signal.length *= ft->signal.channels; /* Keep separate from line above! */ + } + + if (!sox_mp3_vbrtag(ft)) + p->Stream.next_frame = p->Stream.this_frame; + + p->mad_frame_init(&p->Frame); + sox_mp3_input(ft); + + p->cursamp = 0; + + return SOX_SUCCESS; +} + +/* + * Read up to len samples from p->Synth + * If needed, read some more MP3 data, decode them and synth them + * Place in buf[]. + * Return number of samples read. + */ +static size_t sox_mp3read(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t *p = (priv_t *) ft->priv; + size_t donow,i,done=0; + mad_fixed_t sample; + size_t chan; + + do { + size_t x = (p->Synth.pcm.length - p->cursamp)*ft->signal.channels; + donow=min(len, x); + i=0; + while(isignal.channels;chan++){ + sample=p->Synth.pcm.samples[chan][p->cursamp]; + if (sample < -MAD_F_ONE) + sample=-MAD_F_ONE; + else if (sample >= MAD_F_ONE) + sample=MAD_F_ONE-1; + *buf++=(sox_sample_t)(sample<<(32-1-MAD_F_FRACBITS)); + i++; + } + p->cursamp++; + }; + + len-=donow; + done+=donow; + + if (len==0) break; + + /* check whether input buffer needs a refill */ + if (p->Stream.error == MAD_ERROR_BUFLEN) + { + if (sox_mp3_input(ft) == SOX_EOF) { + lsx_debug("sox_mp3_input EOF"); + break; + } + } + + if (p->mad_frame_decode(&p->Frame,&p->Stream)) + { + if(MAD_RECOVERABLE(p->Stream.error)) + { + sox_mp3_inputtag(ft); + continue; + } + else + { + if (p->Stream.error == MAD_ERROR_BUFLEN) + continue; + else + { + lsx_report("unrecoverable frame level error (%s).", + p->mad_stream_errorstr(&p->Stream)); + break; + } + } + } + p->FrameCount++; + p->mad_timer_add(&p->Timer,p->Frame.header.duration); + p->mad_synth_frame(&p->Synth,&p->Frame); + p->cursamp=0; + } while(1); + + return done; +} + +static int stopread(sox_format_t * ft) +{ + priv_t *p=(priv_t*) ft->priv; + + mad_synth_finish(&p->Synth); + p->mad_frame_finish(&p->Frame); + p->mad_stream_finish(&p->Stream); + + free(p->mp3_buffer); + LSX_DLLIBRARY_CLOSE(p, mad_dl); + return SOX_SUCCESS; +} + +static int sox_mp3seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * p = (priv_t *) ft->priv; + size_t initial_bitrate = p->Frame.header.bitrate; + size_t tagsize = 0, consumed = 0; + sox_bool vbr = sox_false; /* Variable Bit Rate */ + sox_bool depadded = sox_false; + uint64_t to_skip_samples = 0; + + /* Reset all */ + lsx_rewind(ft); + mad_timer_reset(&p->Timer); + p->FrameCount = 0; + + /* They where opened in startread */ + mad_synth_finish(&p->Synth); + p->mad_frame_finish(&p->Frame); + p->mad_stream_finish(&p->Stream); + + p->mad_stream_init(&p->Stream); + p->mad_frame_init(&p->Frame); + p->mad_synth_init(&p->Synth); + + offset /= ft->signal.channels; + to_skip_samples = offset; + + while(sox_true) { /* Read data from the MP3 file */ + size_t padding = 0; + size_t read; + size_t leftover = p->Stream.bufend - p->Stream.next_frame; + + memmove(p->mp3_buffer, p->Stream.this_frame, leftover); + read = lsx_readbuf(ft, p->mp3_buffer + leftover, p->mp3_buffer_size - leftover); + if (read == 0) { + lsx_debug("seek failure. unexpected EOF (frames=%" PRIuPTR " leftover=%" PRIuPTR ")", p->FrameCount, leftover); + break; + } + for (; !depadded && padding < read && !p->mp3_buffer[padding]; ++padding); + depadded = sox_true; + p->mad_stream_buffer(&p->Stream, p->mp3_buffer + padding, leftover + read - padding); + + while (sox_true) { /* Decode frame headers */ + static unsigned short samples; + p->Stream.error = MAD_ERROR_NONE; + + /* Not an audio frame */ + if (p->mad_header_decode(&p->Frame.header, &p->Stream) == -1) { + if (p->Stream.error == MAD_ERROR_BUFLEN) + break; /* Normal behaviour; get some more data from the file */ + if (!MAD_RECOVERABLE(p->Stream.error)) { + lsx_warn("unrecoverable MAD error"); + break; + } + if (p->Stream.error == MAD_ERROR_LOSTSYNC) { + unsigned available = (p->Stream.bufend - p->Stream.this_frame); + tagsize = tagtype(p->Stream.this_frame, (size_t) available); + if (tagsize) { /* It's some ID3 tags, so just skip */ + if (tagsize >= available) { + lsx_seeki(ft, (off_t)(tagsize - available), SEEK_CUR); + depadded = sox_false; + } + p->mad_stream_skip(&p->Stream, min(tagsize, available)); + } + else lsx_warn("MAD lost sync"); + } + else lsx_warn("recoverable MAD error"); + continue; + } + + consumed += p->Stream.next_frame - p->Stream.this_frame; + vbr |= (p->Frame.header.bitrate != initial_bitrate); + + samples = 32 * MAD_NSBSAMPLES(&p->Frame.header); + + p->FrameCount++; + p->mad_timer_add(&p->Timer, p->Frame.header.duration); + + if(to_skip_samples <= samples) + { + p->mad_frame_decode(&p->Frame,&p->Stream); + p->mad_synth_frame(&p->Synth, &p->Frame); + p->cursamp = to_skip_samples; + return SOX_SUCCESS; + } + else to_skip_samples -= samples; + + /* If not VBR, we can extrapolate frame size */ + if (p->FrameCount == 64 && !vbr) { + p->FrameCount = offset / samples; + to_skip_samples = offset % samples; + + if (SOX_SUCCESS != lsx_seeki(ft, (off_t)(p->FrameCount * consumed / 64 + tagsize), SEEK_SET)) + return SOX_EOF; + + /* Reset Stream for refilling buffer */ + p->mad_stream_finish(&p->Stream); + p->mad_stream_init(&p->Stream); + break; + } + } + }; + + return SOX_EOF; +} +#else /* !HAVE_MAD_H */ +static int startread(sox_format_t * ft) +{ + lsx_fail_errno(ft,SOX_EOF,"SoX was compiled without MP3 decoding support"); + return SOX_EOF; +} +#define sox_mp3read NULL +#define stopread NULL +#define sox_mp3seek NULL +#endif /*HAVE_MAD_H*/ + +#ifdef HAVE_LAME + +/* Adapters for lame message callbacks: */ + +static void errorf(const char* fmt, va_list va) +{ + sox_globals.subsystem=__FILE__; + if (sox_globals.output_message_handler) + (*sox_globals.output_message_handler)(1,sox_globals.subsystem,fmt,va); + return; +} + +static void debugf(const char* fmt, va_list va) +{ + sox_globals.subsystem=__FILE__; + if (sox_globals.output_message_handler) + (*sox_globals.output_message_handler)(4,sox_globals.subsystem,fmt,va); + return; +} + +static void msgf(const char* fmt, va_list va) +{ + sox_globals.subsystem=__FILE__; + if (sox_globals.output_message_handler) + (*sox_globals.output_message_handler)(3,sox_globals.subsystem,fmt,va); + return; +} + +/* These functions are considered optional. If they aren't present in the + library, the stub versions defined here will be used instead. */ + +UNUSED static void id3tag_init_stub(lame_global_flags * gfp UNUSED) + { return; } +UNUSED static void id3tag_set_title_stub(lame_global_flags * gfp UNUSED, const char* title UNUSED) + { return; } +UNUSED static void id3tag_set_artist_stub(lame_global_flags * gfp UNUSED, const char* artist UNUSED) + { return; } +UNUSED static void id3tag_set_album_stub(lame_global_flags * gfp UNUSED, const char* album UNUSED) + { return; } +UNUSED static void id3tag_set_year_stub(lame_global_flags * gfp UNUSED, const char* year UNUSED) + { return; } +UNUSED static void id3tag_set_comment_stub(lame_global_flags * gfp UNUSED, const char* comment UNUSED) + { return; } +UNUSED static void id3tag_set_track_stub(lame_global_flags * gfp UNUSED, const char* track UNUSED) + { return; } +UNUSED static int id3tag_set_genre_stub(lame_global_flags * gfp UNUSED, const char* genre UNUSED) + { return 0; } +UNUSED static size_t id3tag_set_pad_stub(lame_global_flags * gfp UNUSED, size_t n UNUSED) + { return 0; } +UNUSED static size_t lame_get_id3v2_tag_stub(lame_global_flags * gfp UNUSED, unsigned char * buffer UNUSED, size_t size UNUSED) + { return 0; } +UNUSED static int id3tag_set_fieldvalue_stub(lame_global_flags * gfp UNUSED, const char *fieldvalue UNUSED) + { return 0; } + +static int get_id3v2_tag_size(sox_format_t * ft) +{ + size_t bytes_read; + int id3v2_size; + unsigned char id3v2_header[10]; + + if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0) { + lsx_warn("cannot update id3 tag - failed to seek to beginning"); + return SOX_EOF; + } + + /* read 10 bytes in case there's an ID3 version 2 header here */ + bytes_read = lsx_readbuf(ft, id3v2_header, sizeof(id3v2_header)); + if (bytes_read != sizeof(id3v2_header)) { + lsx_warn("cannot update id3 tag - failed to read id3 header"); + return SOX_EOF; /* not readable, maybe opened Write-Only */ + } + + /* does the stream begin with the ID3 version 2 file identifier? */ + if (!strncmp((char *) id3v2_header, "ID3", (size_t)3)) { + /* the tag size (minus the 10-byte header) is encoded into four + * bytes where the most significant bit is clear in each byte */ + id3v2_size = (((id3v2_header[6] & 0x7f) << 21) + | ((id3v2_header[7] & 0x7f) << 14) + | ((id3v2_header[8] & 0x7f) << 7) + | (id3v2_header[9] & 0x7f)) + + sizeof(id3v2_header); + } else { + /* no ID3 version 2 tag in this stream */ + id3v2_size = 0; + } + return id3v2_size; +} + +static void rewrite_id3v2_tag(sox_format_t * ft, size_t id3v2_size, uint64_t num_samples) +{ + priv_t *p = (priv_t *)ft->priv; + size_t new_size; + unsigned char * buffer; + + if (LSX_DLFUNC_IS_STUB(p, lame_get_id3v2_tag)) + { + if (p->num_samples) + lsx_warn("cannot update track length info - tag update not supported with this version of LAME. Track length will be incorrect."); + else + lsx_report("cannot update track length info - tag update not supported with this version of LAME. Track length will be unspecified."); + return; + } + + buffer = lsx_malloc(id3v2_size); + if (!buffer) + { + lsx_warn("cannot update track length info - failed to allocate buffer"); + return; + } + + if (num_samples > ULONG_MAX) + { + lsx_warn("cannot accurately update track length info - file is too long"); + num_samples = 0; + } + p->lame_set_num_samples(p->gfp, (unsigned long)num_samples); + lsx_debug("updated MP3 TLEN to %lu samples", (unsigned long)num_samples); + + new_size = p->lame_get_id3v2_tag(p->gfp, buffer, id3v2_size); + + if (new_size != id3v2_size && new_size-ID3PADDING <= id3v2_size) { + p->id3tag_set_pad(p->gfp, ID3PADDING + id3v2_size - new_size); + new_size = p->lame_get_id3v2_tag(p->gfp, buffer, id3v2_size); + } + + if (new_size != id3v2_size) { + if (LSX_DLFUNC_IS_STUB(p, id3tag_set_pad)) + { + if (p->num_samples) + lsx_warn("cannot update track length info - tag size adjustment not supported with this version of LAME. Track length will be invalid."); + else + lsx_report("cannot update track length info - tag size adjustment not supported with this version of LAME. Track length will be unspecified."); + } + else + lsx_warn("cannot update track length info - failed to adjust tag size"); + } else { + lsx_seeki(ft, (off_t)0, SEEK_SET); + /* Overwrite the Id3v2 tag (this time TLEN should be accurate) */ + if (lsx_writebuf(ft, buffer, id3v2_size) != 1) { + lsx_debug("Rewrote Id3v2 tag (%" PRIuPTR " bytes)", id3v2_size); + } + } + + free(buffer); +} + +static void rewrite_tags(sox_format_t * ft, uint64_t num_samples) +{ + priv_t *p = (priv_t *)ft->priv; + + off_t file_size; + int id3v2_size; + + if (lsx_seeki(ft, (off_t)0, SEEK_END)) { + lsx_warn("cannot update tags - seek to end failed"); + return; + } + + /* Get file size */ + file_size = lsx_tell(ft); + + if (file_size == 0) { + lsx_warn("cannot update tags - file size is 0"); + return; + } + + id3v2_size = get_id3v2_tag_size(ft); + if (id3v2_size > 0 && num_samples != p->num_samples) { + rewrite_id3v2_tag(ft, id3v2_size, num_samples); + } + + if (p->vbr_tag) { + size_t lametag_size; + uint8_t buffer[MAXFRAMESIZE]; + + if (lsx_seeki(ft, (off_t)id3v2_size, SEEK_SET)) { + lsx_warn("cannot write VBR tag - seek to tag block failed"); + return; + } + + lametag_size = p->lame_get_lametag_frame(p->gfp, buffer, sizeof(buffer)); + if (lametag_size > sizeof(buffer)) { + lsx_warn("cannot write VBR tag - VBR tag too large for buffer"); + return; + } + + if (lametag_size < 1) { + return; + } + + if (lsx_writebuf(ft, buffer, lametag_size) != lametag_size) { + lsx_warn("cannot write VBR tag - VBR tag write failed"); + } else { + lsx_debug("rewrote VBR tag (%" PRIuPTR " bytes)", lametag_size); + } + } +} + +#endif /* HAVE_LAME */ + +#if defined(HAVE_LAME) || defined(HAVE_TWOLAME) + +#define LAME_BUFFER_SIZE(num_samples) (((num_samples) + 3) / 4 * 5 + 7200) + +static int startwrite(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + int openlibrary_result; + int fail = 0; + + if (ft->encoding.encoding != SOX_ENCODING_MP3) { + if(ft->encoding.encoding != SOX_ENCODING_UNKNOWN) + lsx_report("Encoding forced to MP2/MP3"); + ft->encoding.encoding = SOX_ENCODING_MP3; + } + + if(strchr(ft->filetype, '2')) + p->mp2 = 1; + + if (p->mp2) { +#ifdef HAVE_TWOLAME + LSX_DLLIBRARY_OPEN( + p, + twolame_dl, + TWOLAME_FUNC_ENTRIES, + "Twolame encoder library", + twolame_library_names, + openlibrary_result); +#else + lsx_fail_errno(ft,SOX_EOF,"SoX was compiled without MP2 encoding support"); + return SOX_EOF; +#endif + } else { +#ifdef HAVE_LAME + LSX_DLLIBRARY_OPEN( + p, + lame_dl, + LAME_FUNC_ENTRIES, + "LAME encoder library", + lame_library_names, + openlibrary_result); +#else + lsx_fail_errno(ft,SOX_EOF,"SoX was compiled without MP3 encoding support"); + return SOX_EOF; +#endif + } + if (openlibrary_result) + return SOX_EOF; + + p->mp3_buffer_size = LAME_BUFFER_SIZE(sox_globals.bufsiz / max(ft->signal.channels, 1)); + p->mp3_buffer = lsx_malloc(p->mp3_buffer_size); + + p->pcm_buffer_size = sox_globals.bufsiz * sizeof(float); + p->pcm_buffer = lsx_malloc(p->pcm_buffer_size); + + if (p->mp2) { +#ifdef HAVE_TWOLAME + p->opt = p->twolame_init(); + + if (p->opt == NULL){ + lsx_fail_errno(ft,SOX_EOF,"Initialization of Twolame library failed"); + return(SOX_EOF); + } +#endif + } else { +#ifdef HAVE_LAME + p->gfp = p->lame_init(); + + if (p->gfp == NULL){ + lsx_fail_errno(ft,SOX_EOF,"Initialization of LAME library failed"); + return(SOX_EOF); + } + + /* First set message callbacks so we don't miss any messages: */ + p->lame_set_errorf(p->gfp,errorf); + p->lame_set_debugf(p->gfp,debugf); + p->lame_set_msgf (p->gfp,msgf); + + p->num_samples = ft->signal.length == SOX_IGNORE_LENGTH ? 0 : ft->signal.length / max(ft->signal.channels, 1); + p->lame_set_num_samples(p->gfp, p->num_samples > ULONG_MAX ? 0 : (unsigned long)p->num_samples); +#endif + } + + ft->signal.precision = MP3_LAME_PRECISION; + + if (ft->signal.channels != SOX_ENCODING_UNKNOWN) { + if (p->mp2) { +#ifdef HAVE_TWOLAME + fail = (p->twolame_set_num_channels(p->opt,(int)ft->signal.channels) != 0); +#endif + } else { +#ifdef HAVE_LAME + fail = (p->lame_set_num_channels(p->gfp,(int)ft->signal.channels) < 0); +#endif + } + if (fail) { + lsx_fail_errno(ft,SOX_EOF,"Unsupported number of channels"); + return(SOX_EOF); + } + } + else { + if (p->mp2) { +#ifdef HAVE_TWOLAME + ft->signal.channels = p->twolame_get_num_channels(p->opt); /* Twolame default */ +#endif + } else { +#ifdef HAVE_LAME + ft->signal.channels = p->lame_get_num_channels(p->gfp); /* LAME default */ +#endif + } + } + + if (p->mp2) { +#ifdef HAVE_TWOLAME + p->twolame_set_in_samplerate(p->opt,(int)ft->signal.rate); + p->twolame_set_out_samplerate(p->opt,(int)ft->signal.rate); +#endif + } else { +#ifdef HAVE_LAME + p->lame_set_in_samplerate(p->gfp,(int)ft->signal.rate); + p->lame_set_out_samplerate(p->gfp,(int)ft->signal.rate); +#endif + } + + if (!p->mp2) { +#ifdef HAVE_LAME + if (!LSX_DLFUNC_IS_STUB(p, id3tag_init)) + write_comments(ft); +#endif + } + + /* The primary parameter to the LAME encoder is the bit rate. If the + * value of encoding.compression is a positive integer, it's taken as + * the bitrate in kbps (that is if you specify 128, it use 128 kbps). + * + * The second most important parameter is probably "quality" (really + * performance), which allows balancing encoding speed vs. quality. + * In LAME, 0 specifies highest quality but is very slow, while + * 9 selects poor quality, but is fast. (5 is the default and 2 is + * recommended as a good trade-off for high quality encodes.) + * + * Because encoding.compression is a float, the fractional part is used + * to select quality. 128.2 selects 128 kbps encoding with a quality + * of 2. There is one problem with this approach. We need 128 to specify + * 128 kbps encoding with default quality, so .0 means use default. Instead + * of .0 you have to use .01 to specify the highest quality (128.01). + * + * LAME uses bitrate to specify a constant bitrate, but higher quality + * can be achieved using Variable Bit Rate (VBR). VBR quality (really + * size) is selected using a number from 0 to 9. Use a value of 0 for high + * quality, larger files, and 9 for smaller files of lower quality. 4 is + * the default. + * + * In order to squeeze the selection of VBR into the encoding.compression + * float we use negative numbers to select VRR. -4.2 would select default + * VBR encoding (size) with high quality (speed). One special case is 0, + * which is a valid VBR encoding parameter but not a valid bitrate. + * Compression value of 0 is always treated as a high quality vbr, as a + * result both -0.2 and 0.2 are treated as highest quality VBR (size) and + * high quality (speed). + * + * Note: It would have been nice to simply use low values, 0-9, to trigger + * VBR mode, but 8 kbps is a valid bit rate, so negative values were + * used instead. + */ + + lsx_debug("-C option is %f", ft->encoding.compression); + + if (ft->encoding.compression == HUGE_VAL) { + /* Do nothing, use defaults: */ + lsx_report("using %s encoding defaults", p->mp2? "MP2" : "MP3"); + } else { + double abs_compression = fabs(ft->encoding.compression); + double floor_compression = floor(abs_compression); + double fraction_compression = abs_compression - floor_compression; + int bitrate_q = (int)floor_compression; + int encoder_q = + fraction_compression == 0.0 + ? -1 + : (int)(fraction_compression * 10.0 + 0.5); + + if (ft->encoding.compression < 0.5) { + if (p->mp2) { + lsx_fail_errno(ft,SOX_EOF,"Variable bitrate encoding not supported for MP2 audio"); + return(SOX_EOF); + } +#ifdef HAVE_LAME + if (p->lame_get_VBR(p->gfp) == vbr_off) + p->lame_set_VBR(p->gfp, vbr_default); + + if (ft->seekable) { + p->vbr_tag = 1; + } else { + lsx_warn("unable to write VBR tag because we can't seek"); + } + + if (p->lame_set_VBR_q(p->gfp, bitrate_q) < 0) + { + lsx_fail_errno(ft, SOX_EOF, + "lame_set_VBR_q(%d) failed (should be between 0 and 9)", + bitrate_q); + return(SOX_EOF); + } + lsx_report("lame_set_VBR_q(%d)", bitrate_q); +#endif + } else { + if (p->mp2) { +#ifdef HAVE_TWOLAME + fail = (p->twolame_set_brate(p->opt, bitrate_q) != 0); +#endif + } else { +#ifdef HAVE_LAME + fail = (p->lame_set_brate(p->gfp, bitrate_q) < 0); +#endif + } + if (fail) { + lsx_fail_errno(ft, SOX_EOF, + "%slame_set_brate(%d) failed", p->mp2? "two" : "", bitrate_q); + return(SOX_EOF); + } + lsx_report("(two)lame_set_brate(%d)", bitrate_q); + } + + /* Set Quality */ + + if (encoder_q < 0 || p->mp2) { + /* use default quality value */ + lsx_report("using %s default quality", p->mp2? "MP2" : "MP3"); + } else { +#ifdef HAVE_LAME + if (p->lame_set_quality(p->gfp, encoder_q) < 0) { + lsx_fail_errno(ft, SOX_EOF, + "lame_set_quality(%d) failed", encoder_q); + return(SOX_EOF); + } + lsx_report("lame_set_quality(%d)", encoder_q); +#endif + } + } + + if (!p->mp2) { +#ifdef HAVE_LAME + p->lame_set_bWriteVbrTag(p->gfp, p->vbr_tag); +#endif + } + + if (p->mp2) { +#ifdef HAVE_TWOLAME + fail = (p->twolame_init_params(p->opt) != 0); +#endif + } else { +#ifdef HAVE_LAME + fail = (p->lame_init_params(p->gfp) < 0); +#endif + } + if (fail) { + lsx_fail_errno(ft,SOX_EOF,"%s initialization failed", p->mp2? "Twolame" : "LAME"); + return(SOX_EOF); + } + + return(SOX_SUCCESS); +} + +#define MP3_SAMPLE_TO_FLOAT(d) ((float)(32768*SOX_SAMPLE_TO_FLOAT_32BIT(d,))) + +static size_t sox_mp3write(sox_format_t * ft, const sox_sample_t *buf, size_t samp) +{ + priv_t *p = (priv_t *)ft->priv; + size_t new_buffer_size; + float *buffer_l, *buffer_r = NULL; + int nsamples = samp/ft->signal.channels; + int i,j; + int written = 0; + SOX_SAMPLE_LOCALS; + + new_buffer_size = samp * sizeof(float); + if (p->pcm_buffer_size < new_buffer_size) { + float *new_buffer = lsx_realloc(p->pcm_buffer, new_buffer_size); + if (!new_buffer) { + lsx_fail_errno(ft, SOX_ENOMEM, "Out of memory"); + return 0; + } + p->pcm_buffer_size = new_buffer_size; + p->pcm_buffer = new_buffer; + } + + buffer_l = p->pcm_buffer; + + if (p->mp2) + { + size_t s; + for(s = 0; s < samp; s++) + buffer_l[s] = SOX_SAMPLE_TO_FLOAT_32BIT(buf[s],); + } + else + { + if (ft->signal.channels == 2) + { + /* lame doesn't support interleaved samples for floats so we must break + * them out into seperate buffers. + */ + buffer_r = p->pcm_buffer + nsamples; + j=0; + for (i = 0; i < nsamples; i++) + { + buffer_l[i] = MP3_SAMPLE_TO_FLOAT(buf[j++]); + buffer_r[i] = MP3_SAMPLE_TO_FLOAT(buf[j++]); + } + } + else + { + j=0; + for (i = 0; i < nsamples; i++) { + buffer_l[i] = MP3_SAMPLE_TO_FLOAT(buf[j++]); + } + } + } + + new_buffer_size = LAME_BUFFER_SIZE(nsamples); + if (p->mp3_buffer_size < new_buffer_size) { + unsigned char *new_buffer = lsx_realloc(p->mp3_buffer, new_buffer_size); + if (!new_buffer) { + lsx_fail_errno(ft, SOX_ENOMEM, "Out of memory"); + return 0; + } + p->mp3_buffer_size = new_buffer_size; + p->mp3_buffer = new_buffer; + } + + if(p->mp2) { +#ifdef HAVE_TWOLAME + written = p->twolame_encode_buffer_float32_interleaved(p->opt, buffer_l, + nsamples, p->mp3_buffer, (int)p->mp3_buffer_size); +#endif + } else { +#ifdef HAVE_LAME + written = p->lame_encode_buffer_float(p->gfp, buffer_l, buffer_r, + nsamples, p->mp3_buffer, (int)p->mp3_buffer_size); +#endif + } + if (written < 0) { + lsx_fail_errno(ft,SOX_EOF,"Encoding failed"); + return 0; + } + + if (lsx_writebuf(ft, p->mp3_buffer, (size_t)written) < (size_t)written) + { + lsx_fail_errno(ft,SOX_EOF,"File write failed"); + return 0; + } + + return samp; +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t *p = (priv_t *) ft->priv; + uint64_t num_samples = ft->olength == SOX_IGNORE_LENGTH ? 0 : ft->olength / max(ft->signal.channels, 1); + int written = 0; + + if (p->mp2) { +#ifdef HAVE_TWOLAME + written = p->twolame_encode_flush(p->opt, p->mp3_buffer, (int)p->mp3_buffer_size); +#endif + } else { +#ifdef HAVE_LAME + written = p->lame_encode_flush(p->gfp, p->mp3_buffer, (int)p->mp3_buffer_size); +#endif + } + if (written < 0) + lsx_fail_errno(ft, SOX_EOF, "Encoding failed"); + else if (lsx_writebuf(ft, p->mp3_buffer, (size_t)written) < (size_t)written) + lsx_fail_errno(ft, SOX_EOF, "File write failed"); + else if (!p->mp2) { +#ifdef HAVE_LAME + if (ft->seekable && (num_samples != p->num_samples || p->vbr_tag)) + rewrite_tags(ft, num_samples); +#endif + } + + free(p->mp3_buffer); + free(p->pcm_buffer); + + if(p->mp2) { +#ifdef HAVE_TWOLAME + p->twolame_close(&p->opt); + LSX_DLLIBRARY_CLOSE(p, twolame_dl); +#endif + } else { +#ifdef HAVE_LAME + p->lame_close(p->gfp); + LSX_DLLIBRARY_CLOSE(p, lame_dl); +#endif + } + return SOX_SUCCESS; +} + +#else /* !(HAVE_LAME || HAVE_TWOLAME) */ +static int startwrite(sox_format_t * ft UNUSED) +{ + lsx_fail_errno(ft,SOX_EOF,"SoX was compiled with neither MP2 nor MP3 encoding support"); + return SOX_EOF; +} +#define sox_mp3write NULL +#define stopwrite NULL +#endif /* HAVE_LAME || HAVE_TWOLAME */ + +LSX_FORMAT_HANDLER(mp3) +{ + static char const * const names[] = {"mp3", "mp2", "audio/mpeg", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_MP3, 0, 0}; + static sox_rate_t const write_rates[] = { + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "MPEG Layer 2/3 lossy audio compression", names, 0, + startread, sox_mp3read, stopread, + startwrite, sox_mp3write, stopwrite, + sox_mp3seek, write_encodings, write_rates, sizeof(priv_t) + }; + return &handler; +} +#endif /* defined(HAVE_MAD_H) || defined(HAVE_LAME) || defined(HAVE_TWOLAME) */ diff --git a/app/src/main/cpp/sox/noiseprof.c b/app/src/main/cpp/sox/noiseprof.c new file mode 100644 index 0000000..d94e7d4 --- /dev/null +++ b/app/src/main/cpp/sox/noiseprof.c @@ -0,0 +1,223 @@ +/* noiseprof - SoX Noise Profiling Effect. + * + * Written by Ian Turner (vectro@vectro.org) + * Copyright 1999 Ian Turner and others + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "noisered.h" + +#include +#include +#include + +typedef struct { + float *sum; + int *profilecount; + + float *window; +} chandata_t; + +typedef struct { + char* output_filename; + FILE* output_file; + + chandata_t *chandata; + size_t bufdata; +} priv_t; + +/* + * Get the filename, if any. We don't open it until sox_noiseprof_start. + */ +static int sox_noiseprof_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * data = (priv_t *) effp->priv; + --argc, ++argv; + + if (argc == 1) { + data->output_filename = argv[0]; + } else if (argc > 1) + return lsx_usage(effp); + + return (SOX_SUCCESS); +} + +/* + * Prepare processing. + * Do all initializations. + */ +static int sox_noiseprof_start(sox_effect_t * effp) +{ + priv_t * data = (priv_t *) effp->priv; + unsigned channels = effp->in_signal.channels; + unsigned i; + + /* Note: don't fall back to stderr if stdout is unavailable + * since we already use stderr for diagnostics. */ + if (!data->output_filename || !strcmp(data->output_filename, "-")) { + if (effp->global_info->global_info->stdout_in_use_by) { + lsx_fail("stdout already in use by `%s'", effp->global_info->global_info->stdout_in_use_by); + return SOX_EOF; + } + effp->global_info->global_info->stdout_in_use_by = effp->handler.name; + data->output_file = stdout; + } + else if ((data->output_file = fopen(data->output_filename, "wb")) == NULL) { + lsx_fail("Couldn't open profile file %s: %s", data->output_filename, strerror(errno)); + return SOX_EOF; + } + + data->chandata = lsx_calloc(channels, sizeof(*(data->chandata))); + data->bufdata = 0; + for (i = 0; i < channels; i ++) { + data->chandata[i].sum = lsx_calloc(FREQCOUNT, sizeof(float)); + data->chandata[i].profilecount = lsx_calloc(FREQCOUNT, sizeof(int)); + data->chandata[i].window = lsx_calloc(WINDOWSIZE, sizeof(float)); + } + + return SOX_SUCCESS; +} + +/* Collect statistics from the complete window on channel chan. */ +static void collect_data(chandata_t* chan) { + float *out = lsx_calloc(FREQCOUNT, sizeof(float)); + int i; + + lsx_power_spectrum_f(WINDOWSIZE, chan->window, out); + + for (i = 0; i < FREQCOUNT; i ++) { + if (out[i] > 0) { + float value = log(out[i]); + chan->sum[i] += value; + chan->profilecount[i] ++; + } + } + + free(out); +} + +/* + * Grab what we can from ibuf, and process if we have a whole window. + */ +static int sox_noiseprof_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * p = (priv_t *) effp->priv; + size_t samp = min(*isamp, *osamp); + size_t chans = effp->in_signal.channels; + size_t i, j, n = min(samp / chans, WINDOWSIZE - p->bufdata); + + memcpy(obuf, ibuf, n * chans * sizeof(*obuf)); /* Pass on audio unaffected */ + *isamp = *osamp = n * chans; + + /* Collect data for every channel. */ + for (i = 0; i < chans; i ++) { + SOX_SAMPLE_LOCALS; + chandata_t * chan = &(p->chandata[i]); + for (j = 0; j < n; j ++) + chan->window[j + p->bufdata] = + SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + j * chans],); + if (n + p->bufdata == WINDOWSIZE) + collect_data(chan); + } + + p->bufdata += n; + assert(p->bufdata <= WINDOWSIZE); + if (p->bufdata == WINDOWSIZE) + p->bufdata = 0; + + return SOX_SUCCESS; +} + +/* + * Finish off the last window. + */ + +static int sox_noiseprof_drain(sox_effect_t * effp, sox_sample_t *obuf UNUSED, size_t *osamp) +{ + priv_t * data = (priv_t *) effp->priv; + int tracks = effp->in_signal.channels; + int i; + + *osamp = 0; + + if (data->bufdata == 0) { + return SOX_EOF; + } + + for (i = 0; i < tracks; i ++) { + int j; + for (j = data->bufdata+1; j < WINDOWSIZE; j ++) { + data->chandata[i].window[j] = 0; + } + collect_data(&(data->chandata[i])); + } + + if (data->bufdata == WINDOWSIZE || data->bufdata == 0) + return SOX_EOF; + else + return SOX_SUCCESS; +} + +/* + * Print profile and clean up. + */ +static int sox_noiseprof_stop(sox_effect_t * effp) +{ + priv_t * data = (priv_t *) effp->priv; + size_t i; + + for (i = 0; i < effp->in_signal.channels; i ++) { + int j; + chandata_t* chan = &(data->chandata[i]); + + fprintf(data->output_file, "Channel %lu: ", (unsigned long)i); + + for (j = 0; j < FREQCOUNT; j ++) { + double r = chan->profilecount[j] != 0 ? + chan->sum[j] / chan->profilecount[j] : 0; + fprintf(data->output_file, "%s%f", j == 0 ? "" : ", ", r); + } + fprintf(data->output_file, "\n"); + + free(chan->sum); + free(chan->profilecount); + } + + free(data->chandata); + + if (data->output_file != stdout) + fclose(data->output_file); + + return (SOX_SUCCESS); +} + +static sox_effect_handler_t sox_noiseprof_effect = { + "noiseprof", + "[profile-file]", + SOX_EFF_MCHAN | SOX_EFF_MODIFY, + sox_noiseprof_getopts, + sox_noiseprof_start, + sox_noiseprof_flow, + sox_noiseprof_drain, + sox_noiseprof_stop, + NULL, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_noiseprof_effect_fn(void) +{ + return &sox_noiseprof_effect; +} diff --git a/app/src/main/cpp/sox/noisered.c b/app/src/main/cpp/sox/noisered.c new file mode 100644 index 0000000..5281279 --- /dev/null +++ b/app/src/main/cpp/sox/noisered.c @@ -0,0 +1,357 @@ +/* noisered - Noise Reduction Effect. + * + * Written by Ian Turner (vectro@vectro.org) + * + * Copyright 1999 Ian Turner + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Authors are not responsible for the consequences of using this software. + */ + +#include "noisered.h" + +#include +#include +#include +#include + +typedef struct { + float *window; + float *lastwindow; + float *noisegate; + float *smoothing; +} chandata_t; + +/* Holds profile information */ +typedef struct { + char* profile_filename; + float threshold; + + chandata_t *chandata; + size_t bufdata; +} priv_t; + +static void FFT(unsigned NumSamples, + int InverseTransform, + const float *RealIn, float *ImagIn, float *RealOut, float *ImagOut) +{ + unsigned i; + double * work = malloc(2 * NumSamples * sizeof(*work)); + for (i = 0; i < 2 * NumSamples; i += 2) { + work[i] = RealIn[i >> 1]; + work[i + 1] = ImagIn? ImagIn[i >> 1] : 0; + } + lsx_safe_cdft(2 * (int)NumSamples, InverseTransform? -1 : 1, work); + if (InverseTransform) for (i = 0; i < 2 * NumSamples; i += 2) { + RealOut[i >> 1] = work[i] / NumSamples; + ImagOut[i >> 1] = work[i + 1] / NumSamples; + } + else for (i = 0; i < 2 * NumSamples; i += 2) { + RealOut[i >> 1] = work[i]; + ImagOut[i >> 1] = work[i + 1]; + } + free(work); +} + +/* + * Get the options. Default file is stdin (if the audio + * input file isn't coming from there, of course!) + */ +static int sox_noisered_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *) effp->priv; + --argc, ++argv; + + if (argc > 0) { + p->profile_filename = argv[0]; + ++argv; + --argc; + } + + p->threshold = 0.5; + do { /* break-able block */ + NUMERIC_PARAMETER(threshold, 0, 1); + } while (0); + + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +/* + * Prepare processing. + * Do all initializations. + */ +static int sox_noisered_start(sox_effect_t * effp) +{ + priv_t * data = (priv_t *) effp->priv; + size_t fchannels = 0; + size_t channels = effp->in_signal.channels; + size_t i; + FILE * ifp = lsx_open_input_file(effp, data->profile_filename, sox_false); + + if (!ifp) + return SOX_EOF; + + data->chandata = lsx_calloc(channels, sizeof(*(data->chandata))); + data->bufdata = 0; + for (i = 0; i < channels; i ++) { + data->chandata[i].noisegate = lsx_calloc(FREQCOUNT, sizeof(float)); + data->chandata[i].smoothing = lsx_calloc(FREQCOUNT, sizeof(float)); + data->chandata[i].lastwindow = NULL; + } + while (1) { + unsigned long i1_ul; + size_t i1; + float f1; + if (2 != fscanf(ifp, " Channel %lu: %f", &i1_ul, &f1)) + break; + i1 = i1_ul; + if (i1 != fchannels) { + lsx_fail("noisered: Got channel %lu, expected channel %lu.", + (unsigned long)i1, (unsigned long)fchannels); + return SOX_EOF; + } + + data->chandata[fchannels].noisegate[0] = f1; + for (i = 1; i < FREQCOUNT; i ++) { + if (1 != fscanf(ifp, ", %f", &f1)) { + lsx_fail("noisered: Not enough data for channel %lu " + "(expected %d, got %lu)", (unsigned long)fchannels, FREQCOUNT, (unsigned long)i); + return SOX_EOF; + } + data->chandata[fchannels].noisegate[i] = f1; + } + fchannels ++; + } + if (fchannels != channels) { + lsx_fail("noisered: channel mismatch: %lu in input, %lu in profile.", + (unsigned long)channels, (unsigned long)fchannels); + return SOX_EOF; + } + if (ifp != stdin) + fclose(ifp); + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ + + return (SOX_SUCCESS); +} + +/* Mangle a single window. Each output sample (except the first and last + * half-window) is the result of two distinct calls to this function, + * due to overlapping windows. */ +static void reduce_noise(chandata_t* chan, float* window, double level) +{ + float *inr, *ini, *outr, *outi, *power; + float *smoothing = chan->smoothing; + int i; + + inr = lsx_calloc(WINDOWSIZE * 5, sizeof(float)); + ini = inr + WINDOWSIZE; + outr = ini + WINDOWSIZE; + outi = outr + WINDOWSIZE; + power = outi + WINDOWSIZE; + + for (i = 0; i < FREQCOUNT; i ++) + assert(smoothing[i] >= 0 && smoothing[i] <= 1); + + memcpy(inr, window, WINDOWSIZE*sizeof(float)); + + FFT(WINDOWSIZE, 0, inr, NULL, outr, outi); + + memcpy(inr, window, WINDOWSIZE*sizeof(float)); + lsx_apply_hann_f(inr, WINDOWSIZE); + lsx_power_spectrum_f(WINDOWSIZE, inr, power); + + for (i = 0; i < FREQCOUNT; i ++) { + float smooth; + float plog; + plog = log(power[i]); + if (power[i] != 0 && plog < chan->noisegate[i] + level*8.0) + smooth = 0.0; + else + smooth = 1.0; + + smoothing[i] = smooth * 0.5 + smoothing[i] * 0.5; + } + + /* Audacity says this code will eliminate tinkle bells. + * I have no idea what that means. */ + for (i = 2; i < FREQCOUNT - 2; i ++) { + if (smoothing[i]>=0.5 && + smoothing[i]<=0.55 && + smoothing[i-1]<0.1 && + smoothing[i-2]<0.1 && + smoothing[i+1]<0.1 && + smoothing[i+2]<0.1) + smoothing[i] = 0.0; + } + + outr[0] *= smoothing[0]; + outi[0] *= smoothing[0]; + outr[FREQCOUNT-1] *= smoothing[FREQCOUNT-1]; + outi[FREQCOUNT-1] *= smoothing[FREQCOUNT-1]; + + for (i = 1; i < FREQCOUNT-1; i ++) { + int j = WINDOWSIZE - i; + float smooth = smoothing[i]; + + outr[i] *= smooth; + outi[i] *= smooth; + outr[j] *= smooth; + outi[j] *= smooth; + } + + FFT(WINDOWSIZE, 1, outr, outi, inr, ini); + lsx_apply_hann_f(inr, WINDOWSIZE); + + memcpy(window, inr, WINDOWSIZE*sizeof(float)); + + for (i = 0; i < FREQCOUNT; i ++) + assert(smoothing[i] >= 0 && smoothing[i] <= 1); + + free(inr); +} + +/* Do window management once we have a complete window, including mangling + * the current window. */ +static int process_window(sox_effect_t * effp, priv_t * data, unsigned chan_num, unsigned num_chans, + sox_sample_t *obuf, unsigned len) { + int j; + float* nextwindow; + int use = min(len, WINDOWSIZE)-min(len,(WINDOWSIZE/2)); + chandata_t *chan = &(data->chandata[chan_num]); + int first = (chan->lastwindow == NULL); + SOX_SAMPLE_LOCALS; + + if ((nextwindow = lsx_calloc(WINDOWSIZE, sizeof(float))) == NULL) + return SOX_EOF; + + memcpy(nextwindow, chan->window+WINDOWSIZE/2, + sizeof(float)*(WINDOWSIZE/2)); + + reduce_noise(chan, chan->window, data->threshold); + if (!first) { + for (j = 0; j < use; j ++) { + float s = chan->window[j] + chan->lastwindow[WINDOWSIZE/2 + j]; + obuf[chan_num + num_chans * j] = + SOX_FLOAT_32BIT_TO_SAMPLE(s, effp->clips); + } + free(chan->lastwindow); + } else { + for (j = 0; j < use; j ++) { + assert(chan->window[j] >= -1 && chan->window[j] <= 1); + obuf[chan_num + num_chans * j] = + SOX_FLOAT_32BIT_TO_SAMPLE(chan->window[j], effp->clips); + } + } + chan->lastwindow = chan->window; + chan->window = nextwindow; + + return use; +} + +/* + * Read in windows, and call process_window once we get a whole one. + */ +static int sox_noisered_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * data = (priv_t *) effp->priv; + size_t samp = min(*isamp, *osamp); + size_t tracks = effp->in_signal.channels; + size_t track_samples = samp / tracks; + size_t ncopy = min(track_samples, WINDOWSIZE-data->bufdata); + size_t whole_window = (ncopy + data->bufdata == WINDOWSIZE); + int oldbuf = data->bufdata; + size_t i; + + /* FIXME: Make this automatic for all effects */ + assert(effp->in_signal.channels == effp->out_signal.channels); + + if (whole_window) + data->bufdata = WINDOWSIZE/2; + else + data->bufdata += ncopy; + + /* Reduce noise on every channel. */ + for (i = 0; i < tracks; i ++) { + SOX_SAMPLE_LOCALS; + chandata_t* chan = &(data->chandata[i]); + size_t j; + + if (chan->window == NULL) + chan->window = lsx_calloc(WINDOWSIZE, sizeof(float)); + + for (j = 0; j < ncopy; j ++) + chan->window[oldbuf + j] = + SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[i + tracks * j], effp->clips); + + if (!whole_window) + continue; + else + process_window(effp, data, (unsigned) i, (unsigned) tracks, obuf, (unsigned) (oldbuf + ncopy)); + } + + *isamp = tracks*ncopy; + if (whole_window) + *osamp = tracks*(WINDOWSIZE/2); + else + *osamp = 0; + + return SOX_SUCCESS; +} + +/* + * We have up to half a window left to dump. + */ + +static int sox_noisered_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * data = (priv_t *)effp->priv; + unsigned i; + unsigned tracks = effp->in_signal.channels; + for (i = 0; i < tracks; i ++) + *osamp = process_window(effp, data, i, tracks, obuf, (unsigned) data->bufdata); + + /* FIXME: This is very picky. osamp needs to be big enough to get all + * remaining data or it will be discarded. + */ + return (SOX_EOF); +} + +/* + * Clean up. + */ +static int sox_noisered_stop(sox_effect_t * effp) +{ + priv_t * data = (priv_t *) effp->priv; + size_t i; + + for (i = 0; i < effp->in_signal.channels; i ++) { + chandata_t* chan = &(data->chandata[i]); + free(chan->lastwindow); + free(chan->window); + free(chan->smoothing); + free(chan->noisegate); + } + + free(data->chandata); + + return (SOX_SUCCESS); +} + +static sox_effect_handler_t sox_noisered_effect = { + "noisered", + "[profile-file [amount]]", + SOX_EFF_MCHAN|SOX_EFF_LENGTH, + sox_noisered_getopts, + sox_noisered_start, + sox_noisered_flow, + sox_noisered_drain, + sox_noisered_stop, + NULL, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_noisered_effect_fn(void) +{ + return &sox_noisered_effect; +} diff --git a/app/src/main/cpp/sox/noisered.h b/app/src/main/cpp/sox/noisered.h new file mode 100644 index 0000000..5d1ec11 --- /dev/null +++ b/app/src/main/cpp/sox/noisered.h @@ -0,0 +1,26 @@ +/* noiseprof.h - Headers for SoX Noise Profiling Effect. + * + * Written by Ian Turner (vectro@vectro.org) + * Copyright 1999 Ian Turner and others + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +#define WINDOWSIZE 2048 +#define HALFWINDOW (WINDOWSIZE / 2) +#define FREQCOUNT (HALFWINDOW + 1) diff --git a/app/src/main/cpp/sox/nulfile.c b/app/src/main/cpp/sox/nulfile.c new file mode 100644 index 0000000..857de84 --- /dev/null +++ b/app/src/main/cpp/sox/nulfile.c @@ -0,0 +1,58 @@ +/* libSoX file format: null (c) 2006-8 SoX contributors + * Based on an original idea by Carsten Borchardt + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +static int startread(sox_format_t * ft) +{ + if (!ft->signal.rate) { + ft->signal.rate = SOX_DEFAULT_RATE; + lsx_report("sample rate not specified; using %g", ft->signal.rate); + } + ft->signal.precision = ft->encoding.bits_per_sample? + ft->encoding.bits_per_sample: SOX_SAMPLE_PRECISION; + /* Default number of channels is application-dependent */ + return SOX_SUCCESS; +} + +static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + /* Reading from null generates silence i.e. (sox_sample_t)0. */ + (void)ft; + memset(buf, 0, sizeof(sox_sample_t) * len); + return len; /* Return number of samples "read". */ +} + +static size_t write_samples( + sox_format_t * ft, sox_sample_t const * buf, size_t len) +{ + /* Writing to null just discards the samples */ + (void)ft, (void)buf; + return len; /* Return number of samples "written". */ +} + +LSX_FORMAT_HANDLER(nul) +{ + static const char * const names[] = {"null", NULL}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + NULL, names, SOX_FILE_DEVICE | SOX_FILE_PHONY | SOX_FILE_NOSTDIO, + startread, read_samples,NULL,NULL, write_samples,NULL,NULL, NULL, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/optional-fmts.am b/app/src/main/cpp/sox/optional-fmts.am new file mode 100644 index 0000000..ecdeaa4 --- /dev/null +++ b/app/src/main/cpp/sox/optional-fmts.am @@ -0,0 +1,297 @@ + + +if HAVE_ALSA +if STATIC_ALSA + libsox_la_SOURCES += alsa.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @ALSA_LIBS@ +else + libsox_la_LIBADD += @ALSA_LIBS@ +endif +else + libsox_fmt_alsa_la_SOURCES = alsa.c + libsox_fmt_alsa_la_LIBADD = @ALSA_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_alsa.la +endif +endif + +if HAVE_AMRNB +if STATIC_AMRNB + libsox_la_SOURCES += amr-nb.c amr.h +if STATIC_LIBSOX_ONLY + sox_LDADD += @AMRNB_LIBS@ +else + libsox_la_LIBADD += @AMRNB_LIBS@ +endif +else + libsox_fmt_amr_nb_la_SOURCES = amr-nb.c amr.h + libsox_fmt_amr_nb_la_LIBADD = @AMRNB_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_amr_nb.la +endif +endif + +if HAVE_AMRWB +if STATIC_AMRWB + libsox_la_SOURCES += amr-wb.c amr.h +if STATIC_LIBSOX_ONLY + sox_LDADD += @AMRWB_LIBS@ +else + libsox_la_LIBADD += @AMRWB_LIBS@ +endif +else + libsox_fmt_amr_wb_la_SOURCES = amr-wb.c amr.h + libsox_fmt_amr_wb_la_LIBADD = @AMRWB_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_amr_wb.la +endif +endif + +if HAVE_AO +if STATIC_AO + libsox_la_SOURCES += ao.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @AO_LIBS@ +else + libsox_la_LIBADD += @AO_LIBS@ +endif +else + libsox_fmt_ao_la_SOURCES = ao.c + libsox_fmt_ao_la_LIBADD = @AO_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_ao.la +endif +endif + +if HAVE_COREAUDIO +if STATIC_COREAUDIO + libsox_la_SOURCES += coreaudio.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @COREAUDIO_LIBS@ +else + libsox_la_LIBADD += @COREAUDIO_LIBS@ +endif +else + libsox_fmt_coreaudio_la_SOURCES = coreaudio.c + libsox_fmt_coreaudio_la_LIBADD = @COREAUDIO_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_coreaudio.la +endif +endif + +if HAVE_FLAC +if STATIC_FLAC + libsox_la_SOURCES += flac.c + libsox_la_CFLAGS += @FLAC_CFLAGS@ +if STATIC_LIBSOX_ONLY + sox_LDADD += @FLAC_LIBS@ +else + libsox_la_LIBADD += @FLAC_LIBS@ +endif +else + libsox_fmt_flac_la_SOURCES = flac.c + libsox_fmt_opus_la_CFLAGS = @FLAC_CFLAGS@ + libsox_fmt_flac_la_LIBADD = @FLAC_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_flac.la +endif +endif + +if HAVE_GSM +if STATIC_GSM + libsox_la_SOURCES += gsm.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @LIBGSM_LIBS@ +else + libsox_la_LIBADD += @LIBGSM_LIBS@ +endif +else + libsox_fmt_gsm_la_SOURCES = gsm.c + libsox_fmt_gsm_la_LIBADD = @LIBGSM_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_gsm.la +endif +endif + +if HAVE_LPC10 +if STATIC_LPC10 + libsox_la_SOURCES += lpc10.c + libsox_la_CFLAGS += @LPC10_CFLAGS@ +if STATIC_LIBSOX_ONLY + sox_LDADD += @LPC10_LIBS@ +else + libsox_la_LIBADD += @LPC10_LIBS@ +endif +else + libsox_fmt_lpc10_la_SOURCES = lpc10.c + libsox_fmt_lpc10_la_CFLAGS = @LPC10_CFLAGS@ + libsox_fmt_lpc10_la_LIBADD = @LPC10_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_lpc10.la +endif +endif + +if HAVE_MP3 +if STATIC_MP3 + libsox_la_SOURCES += mp3.c mp3-util.h +if STATIC_LIBSOX_ONLY + sox_LDADD += @MP3_LIBS@ +else + libsox_la_LIBADD += @MP3_LIBS@ +endif +else + libsox_fmt_mp3_la_SOURCES = mp3.c mp3-util.h + libsox_fmt_mp3_la_LIBADD = @MP3_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_mp3.la +endif +endif + +if HAVE_OPUS +if STATIC_OPUS + libsox_la_SOURCES += opus.c + libsox_la_CFLAGS += @OPUS_CFLAGS@ +if STATIC_LIBSOX_ONLY + sox_LDADD += @OPUS_LIBS@ +else + libsox_la_LIBADD += @OPUS_LIBS@ +endif +else + libsox_fmt_opus_la_SOURCES = opus.c + libsox_fmt_opus_la_CFLAGS = @OPUS_CFLAGS@ + libsox_fmt_opus_la_LIBADD = @OPUS_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_opus.la +endif +endif + +if HAVE_OSS +if STATIC_OSS + libsox_la_SOURCES += oss.c +else + libsox_fmt_oss_la_SOURCES = oss.c + pkglib_LTLIBRARIES += libsox_fmt_oss.la +endif +endif + +if HAVE_PULSEAUDIO +if STATIC_PULSEAUDIO + libsox_la_SOURCES += pulseaudio.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @PULSEAUDIO_LIBS@ +else + libsox_la_LIBADD += @PULSEAUDIO_LIBS@ +endif +else + libsox_fmt_pulseaudio_la_SOURCES = pulseaudio.c + libsox_fmt_pulseaudio_la_LIBADD = @PULSEAUDIO_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_pulseaudio.la +endif +endif + +if HAVE_WAVEAUDIO +if STATIC_WAVEAUDIO + libsox_la_SOURCES += waveaudio.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @WAVEAUDIO_LIBS@ +else + libsox_la_LIBADD += @WAVEAUDIO_LIBS@ +endif +else + libsox_fmt_waveaudio_la_SOURCES = waveaudio.c + libsox_fmt_waveaudio_la_LIBADD = @WAVEAUDIO_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_waveaudio.la +endif +endif + +if HAVE_SNDIO +if STATIC_SNDIO + libsox_la_SOURCES += sndio.c + libsox_la_LIBADD += @SNDIO_LIBS@ +if STATIC_LIBSOX_ONLY + sox_LDADD += @SNDIO_LIBS@ +else + libsox_la_LIBADD += @SNDIO_LIBS@ +endif +else + libsox_fmt_sndio_la_SOURCES = sndio.c + libsox_fmt_sndio_la_LIBADD = @SNDIO_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_sndio.la +endif +endif + +if HAVE_SUNAUDIO +if STATIC_SUNAUDIO + libsox_la_SOURCES += sunaudio.c +else + libsox_fmt_sunau_la_SOURCES = sunaudio.c + pkglib_LTLIBRARIES += libsox_fmt_sunau.la +endif +endif + +if HAVE_OGGVORBIS +if STATIC_OGGVORBIS + libsox_la_SOURCES += vorbis.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @OGGVORBIS_LIBS@ +else + libsox_la_LIBADD += @OGGVORBIS_LIBS@ +endif +else + libsox_fmt_vorbis_la_SOURCES = vorbis.c + libsox_fmt_vorbis_la_LIBADD = @OGGVORBIS_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_vorbis.la +endif +endif + +if HAVE_WAVPACK +if STATIC_WAVPACK + libsox_la_SOURCES += wavpack.c +if STATIC_LIBSOX_ONLY + sox_LDADD += @WAVPACK_LIBS@ +else + libsox_la_LIBADD += @WAVPACK_LIBS@ +endif +else + libsox_fmt_wavpack_la_SOURCES = wavpack.c + libsox_fmt_wavpack_la_LIBADD = @WAVPACK_LIBS@ + pkglib_LTLIBRARIES += libsox_fmt_wavpack.la +endif +endif + + +if HAVE_SNDFILE +if STATIC_SNDFILE + libsox_la_SOURCES += sndfile.c caf.c mat4.c mat5.c paf.c fap.c w64.c xi.c pvf.c sd2.c + libsox_la_CFLAGS += @LIBSNDFILE_CFLAGS@ +if STATIC_LIBSOX_ONLY + sox_LDADD += @LIBSNDFILE_LIBS@ +else + libsox_la_LIBADD += @LIBSNDFILE_LIBS@ +endif +else +libsox_fmt_sndfile_la_SOURCES = sndfile.c +libsox_fmt_sndfile_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_sndfile_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_caf_la_SOURCES = caf.c sndfile.c +libsox_fmt_caf_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_caf_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_mat4_la_SOURCES = mat4.c sndfile.c +libsox_fmt_mat4_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_mat4_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_mat5_la_SOURCES = mat5.c sndfile.c +libsox_fmt_mat5_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_mat5_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_paf_la_SOURCES = paf.c sndfile.c +libsox_fmt_paf_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_paf_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_fap_la_SOURCES = fap.c sndfile.c +libsox_fmt_fap_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_fap_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_w64_la_SOURCES = w64.c sndfile.c +libsox_fmt_w64_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_w64_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_xi_la_SOURCES = xi.c sndfile.c +libsox_fmt_wi_la_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_xi_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_pvf_la_SOURCES = pvf.c sndfile.c +libsox_fmt_pvf_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_pvf_la_LIBADD = @LIBSNDFILE_LIBS@ +libsox_fmt_sd2_la_SOURCES = sd2.c sndfile.c +libsox_fmt_sd2_CFLAGS = @LIBSNDFILE_CFLAGS@ +libsox_fmt_sd2_la_LIBADD = @LIBSNDFILE_LIBS@ +pkglib_LTLIBRARIES += libsox_fmt_sndfile.la libsox_fmt_caf.la libsox_fmt_mat4.la libsox_fmt_mat5.la libsox_fmt_paf.la libsox_fmt_fap.la libsox_fmt_w64.la libsox_fmt_xi.la libsox_fmt_pvf.la libsox_fmt_sd2.la +endif +endif + diff --git a/app/src/main/cpp/sox/opus.c b/app/src/main/cpp/sox/opus.c new file mode 100644 index 0000000..49fa74b --- /dev/null +++ b/app/src/main/cpp/sox/opus.c @@ -0,0 +1,235 @@ +/* libSoX Opus-in-Ogg sound format handler + * Copyright (C) 2013 John Stumpo + * + * Largely based on vorbis.c: + * libSoX Ogg Vorbis sound format handler + * Copyright 2001, Stan Seibert + * + * Portions from oggenc, (c) Michael Smith , + * ogg123, (c) Kenneth Arnold , and + * libvorbisfile (c) Xiphophorus Company + * + * May 9, 2001 - Stan Seibert (indigo@aztec.asu.edu) + * Ogg Vorbis handler initially written. + * + * July 5, 1991 - Skeleton file + * Copyright 1991 Lance Norskog And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" + +#include +#include +#include + +#include + +#define DEF_BUF_LEN 4096 + +#define BUF_ERROR -1 +#define BUF_EOF 0 +#define BUF_DATA 1 + +typedef struct { + /* Decoding data */ + OggOpusFile *of; + char *buf; + size_t buf_len; + size_t start; + size_t end; /* Unsent data samples in buf[start] through buf[end-1] */ + int current_section; + int eof; +} priv_t; + +/******** Callback functions used in op_open_callbacks ************/ + +static int callback_read(void* ft_data, unsigned char* ptr, int nbytes) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + return lsx_readbuf(ft, ptr, (size_t)nbytes); +} + +static int callback_seek(void* ft_data, opus_int64 off, int whence) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + int ret = ft->seekable ? lsx_seeki(ft, (off_t)off, whence) : -1; + + if (ret == EBADF) + ret = -1; + return ret; +} + +static int callback_close(void* ft_data UNUSED) +{ + /* Do nothing so sox can close the file for us */ + return 0; +} + +static opus_int64 callback_tell(void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + return lsx_tell(ft); +} + +/********************* End callbacks *****************************/ + + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int startread(sox_format_t * ft) +{ + priv_t * vb = (priv_t *) ft->priv; + const OpusTags *ot; + int i; + + OpusFileCallbacks callbacks = { + callback_read, + callback_seek, + callback_tell, + callback_close + }; + + /* Init the decoder */ + vb->of = op_open_callbacks(ft, &callbacks, NULL, (size_t) 0, NULL); + if (vb->of == NULL) { + lsx_fail_errno(ft, SOX_EHDR, "Input not an Ogg Opus audio stream"); + return (SOX_EOF); + } + + /* Get info about the Opus stream */ + ot = op_tags(vb->of, -1); + + /* Record audio info */ + ft->signal.rate = 48000; /* libopusfile always uses 48 kHz */ + ft->encoding.encoding = SOX_ENCODING_OPUS; + ft->signal.channels = op_channel_count(vb->of, -1); + + /* op_pcm_total doesn't work on non-seekable files so + * skip that step in that case. Also, it reports + * "frame"-ish results so we must * channels. + */ + if (ft->seekable) + ft->signal.length = op_pcm_total(vb->of, -1) * ft->signal.channels; + + /* Record comments */ + for (i = 0; i < ot->comments; i++) + sox_append_comment(&ft->oob.comments, ot->user_comments[i]); + + /* Setup buffer */ + vb->buf_len = DEF_BUF_LEN; + vb->buf_len -= vb->buf_len % (ft->signal.channels*2); /* 2 bytes per sample */ + vb->buf = lsx_calloc(vb->buf_len, sizeof(char)); + vb->start = vb->end = 0; + + /* Fill in other info */ + vb->eof = 0; + vb->current_section = -1; + + return (SOX_SUCCESS); +} + + +/* Refill the buffer with samples. Returns BUF_EOF if the end of the + * Opus data was reached while the buffer was being filled, + * BUF_ERROR is something bad happens, and BUF_DATA otherwise */ +static int refill_buffer(sox_format_t * ft) +{ + priv_t * vb = (priv_t *) ft->priv; + int num_read; + + if (vb->start == vb->end) /* Samples all played */ + vb->start = vb->end = 0; + + while (vb->end < vb->buf_len) { + num_read = op_read(vb->of, (opus_int16*) (vb->buf + vb->end), + (int) ((vb->buf_len - vb->end) / sizeof(opus_int16)), + &vb->current_section); + if (num_read == 0) + return (BUF_EOF); + else if (num_read == OP_HOLE) + lsx_warn("Warning: hole in stream; probably harmless"); + else if (num_read < 0) + return (BUF_ERROR); + else + vb->end += num_read * sizeof(opus_int16) * ft->signal.channels; + } + return (BUF_DATA); +} + + +/* + * Read up to len samples from file. + * Convert to signed longs. + * Place in buf[]. + * Return number of samples read. + */ + +static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + priv_t * vb = (priv_t *) ft->priv; + size_t i; + int ret; + sox_sample_t l; + + + for (i = 0; i < len; i++) { + if (vb->start == vb->end) { + if (vb->eof) + break; + ret = refill_buffer(ft); + if (ret == BUF_EOF || ret == BUF_ERROR) { + vb->eof = 1; + if (vb->end == 0) + break; + } + } + + l = (vb->buf[vb->start + 1] << 24) + | (0xffffff & (vb->buf[vb->start] << 16)); + *(buf + i) = l; + vb->start += 2; + } + return i; +} + +/* + * Do anything required when you stop reading samples. + * Don't close input file! + */ +static int stopread(sox_format_t * ft) +{ + priv_t * vb = (priv_t *) ft->priv; + + free(vb->buf); + op_free(vb->of); + + return (SOX_SUCCESS); +} + +static int seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * vb = (priv_t *) ft->priv; + + return op_pcm_seek(vb->of, (opus_int64)(offset / ft->signal.channels))? SOX_EOF:SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(opus) +{ + static const char *const names[] = {"opus", NULL}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Xiph.org's Opus lossy compression", names, 0, + startread, read_samples, stopread, + NULL, NULL, NULL, + seek, NULL, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/oss.c b/app/src/main/cpp/sox/oss.c new file mode 100644 index 0000000..35c7cd2 --- /dev/null +++ b/app/src/main/cpp/sox/oss.c @@ -0,0 +1,446 @@ +/* Copyright 1997 Chris Bagwell And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Chris Bagwell And Sundry Contributors are not + * responsible for the consequences of using this software. + * + * Direct to Open Sound System (OSS) sound driver + * OSS is a popular unix sound driver for Intel x86 unices (eg. Linux) + * and several other unixes (such as SunOS/Solaris). + * This driver is compatible with OSS original source that was called + * USS, Voxware and TASD. + * + * added by Chris Bagwell (cbagwell@sprynet.com) on 2/19/96 + * based on info grabed from vplay.c in Voxware snd-utils-3.5 package. + * and on LINUX_PLAYER patches added by Greg Lee + * which was originally from Directo to Sound Blaster device driver (sbdsp.c). + * SBLAST patches by John T. Kohl. + * + * Changes: + * + * Nov. 26, 1999 Stan Brooks + * Moved initialization code common to startread and startwrite + * into a single function ossdspinit(). + * + */ + +#include "sox_i.h" + +#include +#include +#include +#ifdef HAVE_SYS_SOUNDCARD_H + #include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +/* these appear in the sys/soundcard.h of OSS 4.x, and in Linux's + * sound/core/oss/pcm_oss.c (2.6.24 and later), but are typically + * not included in system header files. + */ +#ifndef AFMT_S32_LE +#define AFMT_S32_LE 0x00001000 +#endif +#ifndef AFMT_S32_BE +#define AFMT_S32_BE 0x00002000 +#endif + +#include + +typedef struct +{ + char* pOutput; + unsigned cOutput; + int device; + unsigned sample_shift; +} priv_t; + +/* common r/w initialization code */ +static int ossinit(sox_format_t* ft) +{ + int sampletype, samplesize; + int tmp, rc; + char const* szDevname; + priv_t* pPriv = (priv_t*)ft->priv; + + if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) + { + szDevname = getenv("OSS_AUDIODEV"); + if (szDevname != NULL) + { + lsx_report("Using device name from OSS_AUDIODEV environment variable: %s", szDevname); + } + else + { + szDevname = "/dev/dsp"; + lsx_report("Using default OSS device name: %s", szDevname); + } + } + else + { + szDevname = ft->filename; + lsx_report("Using user-specified device name: %s", szDevname); + } + + pPriv->device = open( + szDevname, + ft->mode == 'r' ? O_RDONLY : O_WRONLY); + if (pPriv->device < 0) { + lsx_fail_errno(ft, errno, "open failed for device: %s", szDevname); + return SOX_EOF; + } + + if (ft->encoding.bits_per_sample == 8) { + sampletype = AFMT_U8; + samplesize = 8; + pPriv->sample_shift = 0; + if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + if (ft->encoding.encoding != SOX_ENCODING_UNSIGNED) { + lsx_report("OSS driver only supports unsigned with bytes"); + lsx_report("Forcing to unsigned"); + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + } + } + else if (ft->encoding.bits_per_sample == 16) { + /* Attempt to use endian that user specified */ + if (ft->encoding.reverse_bytes) + sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE; + else + sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; + samplesize = 16; + pPriv->sample_shift = 1; + if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) + ft->encoding.encoding = SOX_ENCODING_SIGN2; + if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { + lsx_report("OSS driver only supports signed with words"); + lsx_report("Forcing to signed linear"); + ft->encoding.encoding = SOX_ENCODING_SIGN2; + } + } + else if (ft->encoding.bits_per_sample == 32) { + /* Attempt to use endian that user specified */ + if (ft->encoding.reverse_bytes) + sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S32_LE : AFMT_S32_BE; + else + sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S32_BE : AFMT_S32_LE; + samplesize = 32; + pPriv->sample_shift = 2; + if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) + ft->encoding.encoding = SOX_ENCODING_SIGN2; + if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { + lsx_report("OSS driver only supports signed with words"); + lsx_report("Forcing to signed linear"); + ft->encoding.encoding = SOX_ENCODING_SIGN2; + } + } + else { + /* Attempt to use endian that user specified */ + if (ft->encoding.reverse_bytes) + sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_LE : AFMT_S16_BE; + else + sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; + samplesize = 16; + pPriv->sample_shift = 1; + ft->encoding.bits_per_sample = 16; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + lsx_report("OSS driver only supports bytes and words"); + lsx_report("Forcing to signed linear word"); + } + + ft->signal.channels = 2; + + if (ioctl(pPriv->device, (size_t) SNDCTL_DSP_RESET, 0) < 0) + { + lsx_fail_errno(ft,SOX_EOF,"Unable to reset OSS device %s. Possibly accessing an invalid file/device", szDevname); + return(SOX_EOF); + } + + /* Query the supported formats and find the best match + */ + rc = ioctl(pPriv->device, SNDCTL_DSP_GETFMTS, &tmp); + if (rc == 0) { + if ((tmp & sampletype) == 0) + { + /* is 16-bit supported? */ + if (samplesize == 16 && (tmp & (AFMT_S16_LE|AFMT_S16_BE)) == 0) + { + /* Must not like 16-bits, try 8-bits */ + ft->encoding.bits_per_sample = 8; + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + lsx_report("OSS driver doesn't like signed words"); + lsx_report("Forcing to unsigned bytes"); + tmp = sampletype = AFMT_U8; + samplesize = 8; + pPriv->sample_shift = 0; + } + /* is 8-bit supported */ + else if (samplesize == 8 && (tmp & AFMT_U8) == 0) + { + ft->encoding.bits_per_sample = 16; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + lsx_report("OSS driver doesn't like unsigned bytes"); + lsx_report("Forcing to signed words"); + sampletype = (MACHINE_IS_BIGENDIAN) ? AFMT_S16_BE : AFMT_S16_LE; + samplesize = 16; + pPriv->sample_shift = 1; + } + /* determine which 16-bit format to use */ + if (samplesize == 16 && (tmp & sampletype) == 0) + { + /* Either user requested something not supported + * or hardware doesn't support machine endian. + * Force to opposite as the above test showed + * it supports at least one of the two endians. + */ + sampletype = (sampletype == AFMT_S16_BE) ? AFMT_S16_LE : AFMT_S16_BE; + ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; + } + + } + tmp = sampletype; + rc = ioctl(pPriv->device, SNDCTL_DSP_SETFMT, &tmp); + } + /* Give up and exit */ + if (rc < 0 || tmp != sampletype) + { + lsx_fail_errno(ft,SOX_EOF,"Unable to set the sample size to %d", samplesize); + return (SOX_EOF); + } + + tmp = 1; + if (ioctl(pPriv->device, SNDCTL_DSP_STEREO, &tmp) < 0 || tmp != 1) + { + lsx_warn("Couldn't set to stereo"); + ft->signal.channels = 1; + } + + tmp = ft->signal.rate; + if (ioctl(pPriv->device, SNDCTL_DSP_SPEED, &tmp) < 0 || + (int)ft->signal.rate != tmp) { + /* If the rate the sound card is using is not within 1% of what + * the user specified then override the user setting. + * The only reason not to always override this is because of + * clock-rounding problems. Sound cards will sometimes use + * things like 44101 when you ask for 44100. No need overriding + * this and having strange output file rates for something that + * we can't hear anyways. + */ + if ((int)ft->signal.rate - tmp > (tmp * .01) || + tmp - (int)ft->signal.rate > (tmp * .01)) + ft->signal.rate = tmp; + } + + if (ioctl(pPriv->device, (size_t) SNDCTL_DSP_SYNC, NULL) < 0) { + lsx_fail_errno(ft,SOX_EOF,"Unable to sync dsp"); + return (SOX_EOF); + } + + if (ft->mode == 'r') { + pPriv->cOutput = 0; + pPriv->pOutput = NULL; + } else { + size_t cbOutput = sox_globals.bufsiz; + pPriv->cOutput = cbOutput >> pPriv->sample_shift; + pPriv->pOutput = lsx_malloc(cbOutput); + } + + return(SOX_SUCCESS); +} + +static int ossstop(sox_format_t* ft) +{ + priv_t* pPriv = (priv_t*)ft->priv; + if (pPriv->device >= 0) { + close(pPriv->device); + } + if (pPriv->pOutput) { + free(pPriv->pOutput); + } + return SOX_SUCCESS; +} + +static size_t ossread(sox_format_t* ft, sox_sample_t* pOutput, size_t cOutput) +{ + priv_t* pPriv = (priv_t*)ft->priv; + char* pbOutput = (char*)pOutput; + size_t cbOutputLeft = cOutput << pPriv->sample_shift; + size_t i, cRead; + int cbRead; + SOX_SAMPLE_LOCALS; + LSX_USE_VAR(sox_macro_temp_double); + + while (cbOutputLeft) { + cbRead = read(pPriv->device, pbOutput, cbOutputLeft); + if (cbRead <= 0) { + if (cbRead < 0) { + lsx_fail_errno(ft, errno, "Error reading from device"); + return 0; + } + break; + } + cbOutputLeft -= cbRead; + pbOutput += cbRead; + } + + /* Convert in-place (backwards) */ + cRead = cOutput - (cbOutputLeft >> pPriv->sample_shift); + if (ft->encoding.reverse_bytes) { + switch (pPriv->sample_shift) + { + case 0: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE( + ((sox_uint8_t*)pOutput)[i - 1], + dummy); + } + break; + case 1: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_SIGNED_16BIT_TO_SAMPLE( + lsx_swapw(((sox_int16_t*)pOutput)[i - 1]), + dummy); + } + break; + case 2: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_SIGNED_32BIT_TO_SAMPLE( + lsx_swapdw(((sox_int32_t*)pOutput)[i - 1]), + dummy); + } + break; + } + } else { + switch (pPriv->sample_shift) + { + case 0: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE( + ((sox_uint8_t*)pOutput)[i - 1], + dummy); + } + break; + case 1: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_SIGNED_16BIT_TO_SAMPLE( + ((sox_int16_t*)pOutput)[i - 1], + dummy); + } + break; + case 2: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_SIGNED_32BIT_TO_SAMPLE( + ((sox_int32_t*)pOutput)[i - 1], + dummy); + } + break; + } + } + + return cRead; +} + +static size_t osswrite( + sox_format_t* ft, + const sox_sample_t* pInput, + size_t cInput) +{ + priv_t* pPriv = (priv_t*)ft->priv; + size_t cInputRemaining = cInput; + unsigned cClips = 0; + SOX_SAMPLE_LOCALS; + + while (cInputRemaining) { + size_t cStride; + size_t i; + size_t cbStride; + int cbWritten; + + cStride = cInputRemaining; + if (cStride > pPriv->cOutput) { + cStride = pPriv->cOutput; + } + + if (ft->encoding.reverse_bytes) + { + switch (pPriv->sample_shift) + { + case 0: + for (i = 0; i != cStride; i++) { + ((sox_uint8_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput[i], cClips); + } + break; + case 1: + for (i = 0; i != cStride; i++) { + sox_int16_t s16 = SOX_SAMPLE_TO_SIGNED_16BIT(pInput[i], cClips); + ((sox_int16_t*)pPriv->pOutput)[i] = lsx_swapw(s16); + } + break; + case 2: + for (i = 0; i != cStride; i++) { + ((sox_int32_t*)pPriv->pOutput)[i] = + lsx_swapdw(SOX_SAMPLE_TO_SIGNED_32BIT(pInput[i], cClips)); + } + break; + } + } else { + switch (pPriv->sample_shift) + { + case 0: + for (i = 0; i != cStride; i++) { + ((sox_uint8_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput[i], cClips); + } + break; + case 1: + for (i = 0; i != cStride; i++) { + ((sox_int16_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_SIGNED_16BIT(pInput[i], cClips); + } + break; + case 2: + for (i = 0; i != cStride; i++) { + ((sox_int32_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_SIGNED_32BIT(pInput[i], cClips); + } + break; + } + } + + cbStride = cStride << pPriv->sample_shift; + i = 0; + do { + cbWritten = write(pPriv->device, &pPriv->pOutput[i], cbStride - i); + i += cbWritten; + if (cbWritten <= 0) { + lsx_fail_errno(ft, errno, "Error writing to device"); + return 0; + } + } while (i != cbStride); + + cInputRemaining -= cStride; + pInput += cStride; + } + + return cInput; +} + +LSX_FORMAT_HANDLER(oss) +{ + static char const* const names[] = {"ossdsp", "oss", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 32, 16, 0, + SOX_ENCODING_UNSIGNED, 8, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Open Sound System device driver for unix-like systems", + names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + ossinit, ossread, ossstop, + ossinit, osswrite, ossstop, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/output.c b/app/src/main/cpp/sox/output.c new file mode 100644 index 0000000..c06ab7b --- /dev/null +++ b/app/src/main/cpp/sox/output.c @@ -0,0 +1,59 @@ +/* libSoX effect: Output audio to a file (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct {sox_format_t * file;} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + if (argc != 2 || !(p->file = (sox_format_t *)argv[1]) || p->file->mode != 'w') + return SOX_EOF; + return SOX_SUCCESS; +} + +static int flow(sox_effect_t *effp, sox_sample_t const * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + /* Write out *isamp samples */ + size_t len = sox_write(p->file, ibuf, *isamp); + + /* len is the number of samples that were actually written out; if this is + * different to *isamp, then something has gone wrong--most often, it's + * out of disc space */ + if (len != *isamp) { + lsx_fail("%s: %s", p->file->filename, p->file->sox_errstr); + return SOX_EOF; + } + + /* Outputting is the last `effect' in the effect chain so always passes + * 0 samples on to the next effect (as there isn't one!) */ + (void)obuf, *osamp = 0; + return SOX_SUCCESS; /* All samples output successfully */ +} + +sox_effect_handler_t const * lsx_output_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "output", NULL, SOX_EFF_MCHAN | SOX_EFF_INTERNAL, + getopts, NULL, flow, NULL, NULL, NULL, sizeof(priv_t) + }; + return &handler; +} + diff --git a/app/src/main/cpp/sox/overdrive.c b/app/src/main/cpp/sox/overdrive.c new file mode 100644 index 0000000..dd8489f --- /dev/null +++ b/app/src/main/cpp/sox/overdrive.c @@ -0,0 +1,71 @@ +/* libSoX effect: Overdrive (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct { + double gain, colour, last_in, last_out, b0, b1, a1; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + --argc, ++argv; + p->gain = p->colour = 20; + do { + NUMERIC_PARAMETER(gain, 0, 100) + NUMERIC_PARAMETER(colour, 0, 100) + } while (0); + p->gain = dB_to_linear(p->gain); + p->colour /= 200; + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + + if (p->gain == 1) + return SOX_EFF_NULL; + + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t dummy = 0, len = *isamp = *osamp = min(*isamp, *osamp); + while (len--) { + SOX_SAMPLE_LOCALS; + double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++, dummy), d0 = d; + d *= p->gain; + d += p->colour; + d = d < -1? -2./3 : d > 1? 2./3 : d - d * d * d * (1./3); + p->last_out = d - p->last_in + .995 * p->last_out; + p->last_in = d; + *obuf++ = SOX_FLOAT_64BIT_TO_SAMPLE(d0 * .5 + p->last_out * .75, dummy); + } + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_overdrive_effect_fn(void) +{ + static sox_effect_handler_t handler = {"overdrive", "[gain [colour]]", + SOX_EFF_GAIN, create, start, flow, NULL, NULL, NULL, sizeof(priv_t)}; + return &handler; +} diff --git a/app/src/main/cpp/sox/pad.c b/app/src/main/cpp/sox/pad.c new file mode 100644 index 0000000..c04086f --- /dev/null +++ b/app/src/main/cpp/sox/pad.c @@ -0,0 +1,180 @@ +/* libSoX effect: Pad With Silence (c) 2006 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct { + unsigned npads; /* Number of pads requested */ + struct { + char * str; /* Command-line argument to parse for this pad */ + uint64_t start; /* Start padding when in_pos equals this */ + uint64_t pad; /* Number of samples to pad */ + } * pads; + + uint64_t in_pos; /* Number of samples read from the input stream */ + unsigned pads_pos; /* Number of pads completed so far */ + uint64_t pad_pos; /* Number of samples through the current pad */ +} priv_t; + +static int parse(sox_effect_t * effp, char * * argv, sox_rate_t rate) +{ + priv_t * p = (priv_t *)effp->priv; + char const * next; + unsigned i; + uint64_t last_seen = 0; + const uint64_t in_length = argv ? 0 : + (effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN); + + for (i = 0; i < p->npads; ++i) { + if (argv) /* 1st parse only */ + p->pads[i].str = lsx_strdup(argv[i]); + next = lsx_parsesamples(rate, p->pads[i].str, &p->pads[i].pad, 't'); + if (next == NULL) break; + if (*next == '\0') + p->pads[i].start = i? UINT64_MAX : 0; + else { + if (*next != '@') break; + next = lsx_parseposition(rate, next+1, argv ? NULL : &p->pads[i].start, + last_seen, in_length, '='); + if (next == NULL || *next != '\0') break; + last_seen = p->pads[i].start; + if (p->pads[i].start == SOX_UNKNOWN_LEN) + p->pads[i].start = UINT64_MAX; /* currently the same value, but ... */ + } + if (!argv) { + /* Do this check only during the second pass when the actual + sample rate is known, otherwise it might fail on legal + commands like + pad 1@0.5 1@30000s + if the rate is, e.g., 48k. */ + if (i > 0 && p->pads[i].start <= p->pads[i-1].start) break; + } + } + if (i < p->npads) + return lsx_usage(effp); + return SOX_SUCCESS; +} + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + --argc, ++argv; + p->npads = argc; + p->pads = lsx_calloc(p->npads, sizeof(*p->pads)); + return parse(effp, argv, 1e5); /* No rate yet; parse with dummy */ +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + + /* Re-parse now rate is known */ + if (parse(effp, 0, effp->in_signal.rate) != SOX_SUCCESS) + return SOX_EOF; + + if ((effp->out_signal.length = effp->in_signal.length) != SOX_UNKNOWN_LEN) { + for (i = 0; i < p->npads; ++i) + effp->out_signal.length += + p->pads[i].pad * effp->in_signal.channels; + + /* Check that the last pad position (except for "at the end") + is within bounds. */ + i = p->npads; + if (i > 0 && p->pads[i-1].start == UINT64_MAX) + i--; + if (i > 0 && + p->pads[i-1].start * effp->in_signal.channels + > effp->in_signal.length) + { + lsx_fail("pad position after end of audio"); + return SOX_EOF; + } + } + + p->in_pos = p->pad_pos = p->pads_pos = 0; + for (i = 0; i < p->npads; ++i) + if (p->pads[i].pad) + return SOX_SUCCESS; + return SOX_EFF_NULL; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t c, idone = 0, odone = 0; + *isamp /= effp->in_signal.channels; + *osamp /= effp->in_signal.channels; + + do { + /* Copying: */ + for (; idone < *isamp && odone < *osamp && !(p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start); ++idone, ++odone, ++p->in_pos) + for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = *ibuf++; + + /* Padding: */ + if (p->pads_pos != p->npads && p->in_pos == p->pads[p->pads_pos].start) { + for (; odone < *osamp && p->pad_pos < p->pads[p->pads_pos].pad; ++odone, ++p->pad_pos) + for (c = 0; c < effp->in_signal.channels; ++c) *obuf++ = 0; + if (p->pad_pos == p->pads[p->pads_pos].pad) { /* Move to next pad? */ + ++p->pads_pos; + p->pad_pos = 0; + } + } + } while (idone < *isamp && odone < *osamp); + + *isamp = idone * effp->in_signal.channels; + *osamp = odone * effp->in_signal.channels; + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + static size_t isamp = 0; + if (p->pads_pos != p->npads && p->in_pos != p->pads[p->pads_pos].start) + p->in_pos = UINT64_MAX; /* Invoke the final pad (with no given start) */ + return flow(effp, 0, obuf, &isamp, osamp); +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + if (p->pads_pos != p->npads) + lsx_warn("Input audio too short; pads not applied: %u", p->npads-p->pads_pos); + return SOX_SUCCESS; +} + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + for (i = 0; i < p->npads; ++i) + free(p->pads[i].str); + free(p->pads); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_pad_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "pad", "{length[@position]}", SOX_EFF_MCHAN|SOX_EFF_LENGTH|SOX_EFF_MODIFY, + create, start, flow, drain, stop, lsx_kill, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/paf.c b/app/src/main/cpp/sox/paf.c new file mode 100644 index 0000000..f71adc9 --- /dev/null +++ b/app/src/main/cpp/sox/paf.c @@ -0,0 +1,31 @@ +/* libSoX file format: PAF Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(paf) +{ + static char const * const names[] = {"paf", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 24, 16, 8,0,0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = + "Ensoniq PARIS digital audio editing system (big endian)"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/phaser.c b/app/src/main/cpp/sox/phaser.c new file mode 100644 index 0000000..0455f1b --- /dev/null +++ b/app/src/main/cpp/sox/phaser.c @@ -0,0 +1,147 @@ +/* Effect: phaser Copyright (C) 1998 Juergen Mueller And Sundry Contributors + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Juergen Mueller And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * Flow diagram scheme: August 24, 1998 + * + * * gain-in +---+ * gain-out + * ibuff ----------->| |----------------------------------> obuff + * | + | * decay + * | |<------------+ + * +---+ _______ | + * | | | | + * +---| delay |---+ + * |_______| + * /|\ + * | + * +---------------+ +------------------+ + * | Delay control |<-----| modulation speed | + * +---------------+ +------------------+ + * + * The delay is controled by a sine or triangle modulation. + * + * Usage: + * phaser gain-in gain-out delay decay speed [ -s | -t ] + * + * Where: + * gain-in, decay : 0.0 .. 1.0 volume + * gain-out : 0.0 .. volume + * delay : 0.0 .. 5.0 msec + * speed : 0.1 .. 2.0 Hz modulation speed + * -s : modulation by sine (default) + * -t : modulation by triangle + * + * Note: + * When decay is close to 1.0, the samples may begin clipping or the output + * can saturate! Hint: + * in-gain < (1 - decay * decay) + * 1 / out-gain > gain-in / (1 - decay) + */ + +#include "sox_i.h" +#include + +typedef struct { + double in_gain, out_gain, delay_ms, decay, mod_speed; + lsx_wave_t mod_type; + + int * mod_buf; + size_t mod_buf_len; + int mod_pos; + + double * delay_buf; + size_t delay_buf_len; + int delay_pos; +} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *) effp->priv; + char chars[2]; + + /* Set non-zero defaults: */ + p->in_gain = .4; + p->out_gain = .74; + p->delay_ms = 3.; + p->decay = .4; + p->mod_speed = .5; + + --argc, ++argv; + do { /* break-able block */ + NUMERIC_PARAMETER(in_gain , .0, 1) + NUMERIC_PARAMETER(out_gain , .0, 1e9) + NUMERIC_PARAMETER(delay_ms , .0, 5) + NUMERIC_PARAMETER(decay , .0, .99) + NUMERIC_PARAMETER(mod_speed, .1, 2) + } while (0); + + if (argc && sscanf(*argv, "-%1[st]%c", chars, chars + 1) == 1) { + p->mod_type = *chars == 's'? SOX_WAVE_SINE : SOX_WAVE_TRIANGLE; + --argc, ++argv; + } + + if (p->in_gain > (1 - p->decay * p->decay)) + lsx_warn("warning: gain-in might cause clipping"); + if (p->in_gain / (1 - p->decay) > 1 / p->out_gain) + lsx_warn("warning: gain-out might cause clipping"); + + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + + p->delay_buf_len = p->delay_ms * .001 * effp->in_signal.rate + .5; + p->delay_buf = lsx_calloc(p->delay_buf_len, sizeof(*p->delay_buf)); + + p->mod_buf_len = effp->in_signal.rate / p->mod_speed + .5; + p->mod_buf = lsx_malloc(p->mod_buf_len * sizeof(*p->mod_buf)); + lsx_generate_wave_table(p->mod_type, SOX_INT, p->mod_buf, p->mod_buf_len, + 1., (double)p->delay_buf_len, M_PI_2); + + p->delay_pos = p->mod_pos = 0; + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, + sox_sample_t *obuf, size_t *isamp, size_t *osamp) +{ + priv_t * p = (priv_t *) effp->priv; + size_t len = *isamp = *osamp = min(*isamp, *osamp); + + while (len--) { + double d = *ibuf++ * p->in_gain + p->delay_buf[ + (p->delay_pos + p->mod_buf[p->mod_pos]) % p->delay_buf_len] * p->decay; + p->mod_pos = (p->mod_pos + 1) % p->mod_buf_len; + + p->delay_pos = (p->delay_pos + 1) % p->delay_buf_len; + p->delay_buf[p->delay_pos] = d; + + *obuf++ = SOX_ROUND_CLIP_COUNT(d * p->out_gain, effp->clips); + } + return SOX_SUCCESS; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + + free(p->delay_buf); + free(p->mod_buf); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_phaser_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "phaser", "gain-in gain-out delay decay speed [ -s | -t ]", + SOX_EFF_LENGTH | SOX_EFF_GAIN, getopts, start, flow, NULL, stop, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/prc.c b/app/src/main/cpp/sox/prc.c new file mode 100644 index 0000000..58f765e --- /dev/null +++ b/app/src/main/cpp/sox/prc.c @@ -0,0 +1,449 @@ +/* Psion Record format (format of sound files used for EPOC machines). + * The file normally has no extension, so SoX uses .prc (Psion ReCord). + * Based (heavily) on the wve.c format file. + * Hacked by Bert van Leeuwen (bert@e.co.za) + * + * Header check improved, ADPCM encoding added, and other improvements + * by Reuben Thomas , using file format info at + * http://software.frodo.looijaard.name/psiconv/formats/ + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Includes code for ADPCM framing based on code carrying the + * following copyright: + * + ******************************************************************* + Copyright 1992 by Stichting Mathematisch Centrum, Amsterdam, The + Netherlands. + + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and its + documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appear in all copies and that + both that copyright notice and this permission notice appear in + supporting documentation, and that the names of Stichting Mathematisch + Centrum or CWI not be used in advertising or publicity pertaining to + distribution of the software without specific, written prior permission. + + STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO + THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND + FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE + FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT + OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + ******************************************************************/ + + +#include "sox_i.h" + +#include "adpcms.h" + +#include +#include +#include +#include + +typedef struct { + uint32_t nsamp, nbytes; + short padding; + short repeats; + off_t data_start; /* for seeking */ + adpcm_io_t adpcm; + unsigned frame_samp; /* samples left to read in current frame */ +} priv_t; + +static void prcwriteheader(sox_format_t * ft); + +static int seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * p = (priv_t *)ft->priv; + if (ft->encoding.encoding == SOX_ENCODING_ALAW) + return lsx_offset_seek(ft, (off_t)p->data_start, (off_t)offset); + return SOX_EOF; +} + +/* File header. The first 4 words are fixed; the rest of the header + could theoretically be different, and this is the first place to + check with apparently invalid files. + + N.B. All offsets are from start of file. */ +static const char prc_header[41] = { + /* Header section */ + '\x37','\x00','\x00','\x10', /* 0x00: File type (UID 1) */ + '\x6d','\x00','\x00','\x10', /* 0x04: File kind (UID 2) */ + '\x7e','\x00','\x00','\x10', /* 0x08: Application ID (UID 3) */ + '\xcf','\xac','\x08','\x55', /* 0x0c: Checksum of UIDs 1-3 */ + '\x14','\x00','\x00','\x00', /* 0x10: File offset of Section Table Section */ + /* Section Table Section: a BListL, i.e. a list of longs preceded by + length byte. + The longs are in (ID, offset) pairs, each pair identifying a + section. */ + '\x04', /* 0x14: List has 4 bytes, i.e. 2 pairs */ + '\x52','\x00','\x00','\x10', /* 0x15: ID: Record Section */ + '\x34','\x00','\x00','\x00', /* 0x19: Offset to Record Section */ + '\x89','\x00','\x00','\x10', /* 0x1d: ID: Application ID Section */ + '\x25','\x00','\x00','\x00', /* 0x21: Offset to Application ID Section */ + '\x7e','\x00','\x00','\x10', /* 0x25: Application ID Section: + Record.app identifier */ + /* Next comes the string, which can be either case. */ +}; + +/* Format of the Record Section (offset 0x34): + +00 L Uncompressed data length +04 ID a1 01 00 10 for ADPCM, 00 00 00 00 for A-law +08 W number of times sound will be repeated (0 = played once) +0a B Volume setting (01-05) +0b B Always 00 (?) +0c L Time between repeats in usec +10 LListB (i.e. long giving number of bytes followed by bytes) Sound Data +*/ + +static int prc_checkheader(sox_format_t * ft, char *head) +{ + lsx_readbuf(ft, head, sizeof(prc_header)); + return memcmp(head, prc_header, sizeof(prc_header)) == 0; +} + +static int startread(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + char head[sizeof(prc_header)]; + uint8_t byte; + uint16_t reps; + uint32_t len, listlen, encoding, repgap; + unsigned char volume; + char appname[0x40]; /* Maximum possible length of name */ + + /* Check the header */ + if (prc_checkheader(ft, head)) + lsx_debug("Found Psion Record header"); + else { + lsx_fail_errno(ft,SOX_EHDR,"Not a Psion Record file"); + return (SOX_EOF); + } + + lsx_readb(ft, &byte); + if ((byte & 0x3) != 0x2) { + lsx_fail_errno(ft, SOX_EHDR, "Invalid length byte for application name string %d", (int)(byte)); + return SOX_EOF; + } + + byte >>= 2; + assert(byte < 64); + lsx_reads(ft, appname, (size_t)byte); + if (strncasecmp(appname, "record.app", (size_t) byte) != 0) { + lsx_fail_errno(ft, SOX_EHDR, "Invalid application name string %.63s", appname); + return SOX_EOF; + } + + lsx_readdw(ft, &len); + p->nsamp = len; + lsx_debug("Number of samples: %d", len); + + lsx_readdw(ft, &encoding); + lsx_debug("Encoding of samples: %x", encoding); + if (encoding == 0) + ft->encoding.encoding = SOX_ENCODING_ALAW; + else if (encoding == 0x100001a1) + ft->encoding.encoding = SOX_ENCODING_IMA_ADPCM; + else { + lsx_fail_errno(ft, SOX_EHDR, "Unrecognised encoding"); + return SOX_EOF; + } + + lsx_readw(ft, &reps); /* Number of repeats */ + lsx_debug("Repeats: %d", reps); + + lsx_readb(ft, &volume); + lsx_debug("Volume: %d", (unsigned)volume); + if (volume < 1 || volume > 5) + lsx_warn("Volume %d outside range 1..5", volume); + + lsx_readb(ft, &byte); /* Unused and seems always zero */ + + lsx_readdw(ft, &repgap); /* Time between repeats in usec */ + lsx_debug("Time between repeats (usec): %u", repgap); + + lsx_readdw(ft, &listlen); /* Length of samples list */ + lsx_debug("Number of bytes in samples list: %u", listlen); + + if (ft->signal.rate != 0 && ft->signal.rate != 8000) + lsx_report("PRC only supports 8 kHz; overriding."); + ft->signal.rate = 8000; + + if (ft->signal.channels != 1 && ft->signal.channels != 0) + lsx_report("PRC only supports 1 channel; overriding."); + ft->signal.channels = 1; + + p->data_start = lsx_tell(ft); + ft->signal.length = p->nsamp / ft->signal.channels; + + if (ft->encoding.encoding == SOX_ENCODING_ALAW) { + ft->encoding.bits_per_sample = 8; + if (lsx_rawstartread(ft)) + return SOX_EOF; + } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { + p->frame_samp = 0; + if (lsx_adpcm_ima_start(ft, &p->adpcm)) + return SOX_EOF; + } + + return (SOX_SUCCESS); +} + +/* Read a variable-length encoded count */ +/* Ignore return code of lsx_readb, as it doesn't really matter if EOF + is delayed until the caller. */ +static unsigned read_cardinal(sox_format_t * ft) +{ + unsigned a; + uint8_t byte; + + if (lsx_readb(ft, &byte) == SOX_EOF) + return (unsigned)SOX_EOF; + lsx_debug_more("Cardinal byte 1: %x", byte); + a = byte; + if (!(a & 1)) + a >>= 1; + else { + if (lsx_readb(ft, &byte) == SOX_EOF) + return (unsigned)SOX_EOF; + lsx_debug_more("Cardinal byte 2: %x", byte); + a |= byte << 8; + if (!(a & 2)) + a >>= 2; + else if (!(a & 4)) { + if (lsx_readb(ft, &byte) == SOX_EOF) + return (unsigned)SOX_EOF; + lsx_debug_more("Cardinal byte 3: %x", byte); + a |= byte << 16; + if (lsx_readb(ft, &byte) == SOX_EOF) + return (unsigned)SOX_EOF; + lsx_debug_more("Cardinal byte 4: %x", byte); + a |= byte << 24; + a >>= 3; + } + } + + return a; +} + +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t samp) +{ + priv_t * p = (priv_t *)ft->priv; + + lsx_debug_more("length now = %d", p->nsamp); + + if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { + size_t nsamp, read; + + if (p->frame_samp == 0) { + unsigned framelen = read_cardinal(ft); + uint32_t trash; + + if (framelen == (unsigned)SOX_EOF) + return 0; + + lsx_debug_more("frame length %d", framelen); + p->frame_samp = framelen; + + /* Discard length of compressed data */ + lsx_debug_more("compressed length %d", read_cardinal(ft)); + /* Discard length of BListL */ + lsx_readdw(ft, &trash); + lsx_debug_more("list length %d", trash); + + /* Reset CODEC for start of frame */ + lsx_adpcm_reset(&p->adpcm, ft->encoding.encoding); + } + nsamp = min(p->frame_samp, samp); + p->nsamp += nsamp; + read = lsx_adpcm_read(ft, &p->adpcm, buf, nsamp); + p->frame_samp -= read; + lsx_debug_more("samples left in this frame: %d", p->frame_samp); + return read; + } else { + p->nsamp += samp; + return lsx_rawread(ft, buf, samp); + } +} + +static int stopread(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + + if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) + return lsx_adpcm_stopread(ft, &p->adpcm); + else + return SOX_SUCCESS; +} + +/* When writing, the header is supposed to contain the number of + data bytes written, unless it is written to a pipe. + Since we don't know how many bytes will follow until we're done, + we first write the header with an unspecified number of bytes, + and at the end we rewind the file and write the header again + with the right size. This only works if the file is seekable; + if it is not, the unspecified size remains in the header + (this is illegal). */ + +static int startwrite(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + + if (ft->encoding.encoding == SOX_ENCODING_ALAW) { + if (lsx_rawstartwrite(ft)) + return SOX_EOF; + } else if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { + if (lsx_adpcm_ima_start(ft, &p->adpcm)) + return SOX_EOF; + } + + p->nsamp = 0; + p->nbytes = 0; + if (p->repeats == 0) + p->repeats = 1; + + prcwriteheader(ft); + + p->data_start = lsx_tell(ft); + + return SOX_SUCCESS; +} + +static void write_cardinal(sox_format_t * ft, unsigned a) +{ + uint8_t byte; + + if (a < 0x80) { + byte = a << 1; + lsx_debug_more("Cardinal byte 1: %x", byte); + lsx_writeb(ft, byte); + } else if (a < 0x8000) { + byte = (a << 2) | 1; + lsx_debug_more("Cardinal byte 1: %x", byte); + lsx_writeb(ft, byte); + byte = a >> 6; + lsx_debug_more("Cardinal byte 2: %x", byte); + lsx_writeb(ft, byte); + } else { + byte = (a << 3) | 3; + lsx_debug_more("Cardinal byte 1: %x", byte); + lsx_writeb(ft, byte); + byte = a >> 5; + lsx_debug_more("Cardinal byte 2: %x", byte); + lsx_writeb(ft, byte); + byte = a >> 13; + lsx_debug_more("Cardinal byte 3: %x", byte); + lsx_writeb(ft, byte); + byte = a >> 21; + lsx_debug_more("Cardinal byte 4: %x", byte); + lsx_writeb(ft, byte); + } +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp) +{ + priv_t * p = (priv_t *)ft->priv; + /* Psion Record seems not to be able to handle frames > 800 samples */ + size_t written = 0; + lsx_debug_more("length now = %d", p->nsamp); + if (ft->encoding.encoding == SOX_ENCODING_IMA_ADPCM) { + while (written < nsamp) { + size_t written1, samp = min(nsamp - written, 800); + + write_cardinal(ft, (unsigned) samp); + /* Write compressed length */ + write_cardinal(ft, (unsigned) ((samp / 2) + (samp % 2) + 4)); + /* Write length again (seems to be a BListL) */ + lsx_debug_more("list length %lu", (unsigned long)samp); + lsx_writedw(ft, (unsigned) samp); + lsx_adpcm_reset(&p->adpcm, ft->encoding.encoding); + written1 = lsx_adpcm_write(ft, &p->adpcm, buf + written, samp); + if (written1 != samp) + break; + lsx_adpcm_flush(ft, &p->adpcm); + written += written1; + } + } else + written = lsx_rawwrite(ft, buf, nsamp); + p->nsamp += written; + return written; +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + + p->nbytes = lsx_tell(ft) - p->data_start; + + if (!ft->seekable) { + lsx_warn("Header will have invalid file length since file is not seekable"); + return SOX_SUCCESS; + } + + if (lsx_seeki(ft, (off_t)0, 0) != 0) { + lsx_fail_errno(ft,errno,"Can't rewind output file to rewrite Psion header."); + return(SOX_EOF); + } + prcwriteheader(ft); + return SOX_SUCCESS; +} + +static void prcwriteheader(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + + lsx_writebuf(ft, prc_header, sizeof(prc_header)); + lsx_writes(ft, "\x2arecord.app"); + + lsx_debug("Number of samples: %d",p->nsamp); + lsx_writedw(ft, p->nsamp); + + if (ft->encoding.encoding == SOX_ENCODING_ALAW) + lsx_writedw(ft, 0); + else + lsx_writedw(ft, 0x100001a1); /* ADPCM */ + + lsx_writew(ft, 0); /* Number of repeats */ + lsx_writeb(ft, 3); /* Volume: use default value of Record.app */ + lsx_writeb(ft, 0); /* Unused and seems always zero */ + lsx_writedw(ft, 0); /* Time between repeats in usec */ + + lsx_debug("Number of bytes: %d", p->nbytes); + lsx_writedw(ft, p->nbytes); /* Number of bytes of data */ +} + +LSX_FORMAT_HANDLER(prc) +{ + static char const * const names[] = {"prc", NULL}; + static sox_rate_t const write_rates[] = {8000, 0}; + static unsigned const write_encodings[] = { + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_IMA_ADPCM, 4, 0, + 0}; + static sox_format_handler_t const handler = { + SOX_LIB_VERSION_CODE, + "Psion Record; used in EPOC devices (Series 5, Revo and similar)", + names, SOX_FILE_LIT_END | SOX_FILE_MONO, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + seek, write_encodings, write_rates, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/pulseaudio.c b/app/src/main/cpp/sox/pulseaudio.c new file mode 100644 index 0000000..7658947 --- /dev/null +++ b/app/src/main/cpp/sox/pulseaudio.c @@ -0,0 +1,172 @@ +/* Pulse Audio sound handler + * + * Copyright 2008 Chris Bagwell And Sundry Contributors + */ + +#include "sox_i.h" + +#include +#include + +typedef struct { + pa_simple *pasp; +} priv_t; + +static int setup(sox_format_t *ft, int is_input) +{ + priv_t *pa = (priv_t *)ft->priv; + char *server; + pa_stream_direction_t dir; + char *app_str; + char *dev; + pa_sample_spec spec; + int error; + + /* TODO: If user specified device of type "server:dev" then + * break up and override server. + */ + server = NULL; + + if (is_input) + { + dir = PA_STREAM_RECORD; + app_str = "record"; + } + else + { + dir = PA_STREAM_PLAYBACK; + app_str = "playback"; + } + + if (strncmp(ft->filename, "default", (size_t)7) == 0) + dev = NULL; + else + dev = ft->filename; + + /* If user doesn't specify, default to some reasonable values. + * Since this is mainly for recording case, default to typical + * 16-bit values to prevent saving larger files then average user + * wants. Power users can override to 32-bit if they wish. + */ + if (ft->signal.channels == 0) + ft->signal.channels = 2; + if (ft->signal.rate == 0) + ft->signal.rate = 44100; + if (ft->encoding.bits_per_sample == 0) + { + ft->encoding.bits_per_sample = 16; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + } + + spec.format = PA_SAMPLE_S32NE; + spec.rate = ft->signal.rate; + spec.channels = ft->signal.channels; + + pa->pasp = pa_simple_new(server, "SoX", dir, dev, app_str, &spec, + NULL, NULL, &error); + + if (pa->pasp == NULL) + { + lsx_fail_errno(ft, SOX_EPERM, "can not open audio device: %s", pa_strerror(error)); + return SOX_EOF; + } + + /* TODO: Is it better to convert format/rates in SoX or in + * always let Pulse Audio do it? Since we don't know what + * hardware prefers, assume it knows best and give it + * what user specifies. + */ + + return SOX_SUCCESS; +} + +static int startread(sox_format_t *ft) +{ + return setup(ft, 1); +} + +static int stopread(sox_format_t * ft) +{ + priv_t *pa = (priv_t *)ft->priv; + + pa_simple_free(pa->pasp); + + return SOX_SUCCESS; +} + +static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t nsamp) +{ + priv_t *pa = (priv_t *)ft->priv; + size_t len; + int rc, error; + + /* Pulse Audio buffer lengths are true buffer lengths and not + * count of samples. */ + len = nsamp * sizeof(sox_sample_t); + + rc = pa_simple_read(pa->pasp, buf, len, &error); + + if (rc < 0) + { + lsx_fail_errno(ft, SOX_EPERM, "error reading from pulse audio device: %s", pa_strerror(error)); + return SOX_EOF; + } + else + return nsamp; +} + +static int startwrite(sox_format_t * ft) +{ + return setup(ft, 0); +} + +static size_t write_samples(sox_format_t *ft, const sox_sample_t *buf, size_t nsamp) +{ + priv_t *pa = (priv_t *)ft->priv; + size_t len; + int rc, error; + + if (!nsamp) + return 0; + + /* Pulse Audio buffer lengths are true buffer lengths and not + * count of samples. */ + len = nsamp * sizeof(sox_sample_t); + + rc = pa_simple_write(pa->pasp, buf, len, &error); + + if (rc < 0) + { + lsx_fail_errno(ft, SOX_EPERM, "error writing to pulse audio device: %s", pa_strerror(error)); + return SOX_EOF; + } + + return nsamp; +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t *pa = (priv_t *)ft->priv; + int error; + + pa_simple_drain(pa->pasp, &error); + pa_simple_free(pa->pasp); + + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(pulseaudio) +{ + static char const *const names[] = { "pulseaudio", NULL }; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 32, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Pulse Audio client", + names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/pvf.c b/app/src/main/cpp/sox/pvf.c new file mode 100644 index 0000000..22a1e08 --- /dev/null +++ b/app/src/main/cpp/sox/pvf.c @@ -0,0 +1,30 @@ +/* libSoX file format: PVF Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(pvf) +{ + static char const * const names[] = {"pvf", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 32, 16, 8,0,0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = "Portable Voice Format"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/rate.c b/app/src/main/cpp/sox/rate.c new file mode 100644 index 0000000..0aea6db --- /dev/null +++ b/app/src/main/cpp/sox/rate.c @@ -0,0 +1,712 @@ +/* Effect: change sample rate Copyright (c) 2008,12 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Inspired by, and builds upon some of the ideas presented in: + * `The Quest For The Perfect Resampler' by Laurent De Soras; + * http://ldesoras.free.fr/doc/articles/resampler-en.pdf */ + +#ifdef NDEBUG /* Enable assert always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#define _GNU_SOURCE +#include "sox_i.h" +#include "fft4g.h" +#include "dft_filter.h" +#include +#include + +#define calloc lsx_calloc +#define malloc lsx_malloc +#define raw_coef_t double + +#if 0 /* For float32 version, as used in foobar */ + #define sample_t float + #define num_coefs4 ((num_coefs + 3) & ~3) /* align coefs for SSE */ + #define coefs4_check(i) ((i) < num_coefs) +#else + #define sample_t double + #define num_coefs4 num_coefs + #define coefs4_check(i) 1 +#endif + +#if defined M_PIl + #define hi_prec_clock_t long double /* __float128 is also a (slow) option */ +#else + #define hi_prec_clock_t double +#endif + +#define coef(coef_p, interp_order, fir_len, phase_num, coef_interp_num, fir_coef_num) coef_p[(fir_len) * ((interp_order) + 1) * (phase_num) + ((interp_order) + 1) * (fir_coef_num) + (interp_order - coef_interp_num)] + +static sample_t * prepare_coefs(raw_coef_t const * coefs, int num_coefs, + int num_phases, int interp_order, int multiplier) +{ + int i, j, length = num_coefs4 * num_phases; + sample_t * result = malloc(length * (interp_order + 1) * sizeof(*result)); + double fm1 = coefs[0], f1 = 0, f2 = 0; + + for (i = num_coefs4 - 1; i >= 0; --i) + for (j = num_phases - 1; j >= 0; --j) { + double f0 = fm1, b = 0, c = 0, d = 0; /* = 0 to kill compiler warning */ + int pos = i * num_phases + j - 1; + fm1 = coefs4_check(i) && pos > 0 ? coefs[pos - 1] * multiplier : 0; + switch (interp_order) { + case 1: b = f1 - f0; break; + case 2: b = f1 - (.5 * (f2+f0) - f1) - f0; c = .5 * (f2+f0) - f1; break; + case 3: c=.5*(f1+fm1)-f0;d=(1/6.)*(f2-f1+fm1-f0-4*c);b=f1-f0-d-c; break; + default: if (interp_order) assert(0); + } + #define coef_coef(x) \ + coef(result, interp_order, num_coefs4, j, x, num_coefs4 - 1 - i) + coef_coef(0) = f0; + if (interp_order > 0) coef_coef(1) = b; + if (interp_order > 1) coef_coef(2) = c; + if (interp_order > 2) coef_coef(3) = d; + #undef coef_coef + f2 = f1, f1 = f0; + } + return result; +} + +typedef struct { /* So generated filter coefs may be shared between channels */ + sample_t * poly_fir_coefs; + dft_filter_t dft_filter[2]; +} rate_shared_t; + +struct stage; +typedef void (* stage_fn_t)(struct stage * input, fifo_t * output); +typedef struct stage { + /* Common to all stage types: */ + stage_fn_t fn; + fifo_t fifo; + int pre; /* Number of past samples to store */ + int pre_post; /* pre + number of future samples to store */ + int preload; /* Number of zero samples to pre-load the fifo */ + double out_in_ratio; /* For buffer management. */ + + /* For a stage with variable (run-time generated) filter coefs: */ + rate_shared_t * shared; + int dft_filter_num; /* Which, if any, of the 2 DFT filters to use */ + + /* For a stage with variable L/M: */ + union { /* 32bit.32bit fixed point arithmetic */ + #if defined(WORDS_BIGENDIAN) + struct {int32_t integer; uint32_t fraction;} parts; + #else + struct {uint32_t fraction; int32_t integer;} parts; + #endif + int64_t all; + #define MULT32 (65536. * 65536.) + + hi_prec_clock_t hi_prec_clock; + } at, step; + sox_bool use_hi_prec_clock; + int L, remL, remM; + int n, phase_bits; +} stage_t; + +#define stage_occupancy(s) max(0, fifo_occupancy(&(s)->fifo) - (s)->pre_post) +#define stage_read_p(s) ((sample_t *)fifo_read_ptr(&(s)->fifo) + (s)->pre) + +static void cubic_stage_fn(stage_t * p, fifo_t * output_fifo) +{ + int i, num_in = stage_occupancy(p), max_num_out = 1 + num_in*p->out_in_ratio; + sample_t const * input = stage_read_p(p); + sample_t * output = fifo_reserve(output_fifo, max_num_out); + + for (i = 0; p->at.parts.integer < num_in; ++i, p->at.all += p->step.all) { + sample_t const * s = input + p->at.parts.integer; + sample_t x = p->at.parts.fraction * (1 / MULT32); + sample_t b = .5*(s[1]+s[-1])-*s, a = (1/6.)*(s[2]-s[1]+s[-1]-*s-4*b); + sample_t c = s[1]-*s-a-b; + output[i] = ((a*x + b)*x + c)*x + *s; + } + assert(max_num_out - i >= 0); + fifo_trim_by(output_fifo, max_num_out - i); + fifo_read(&p->fifo, p->at.parts.integer, NULL); + p->at.parts.integer = 0; +} + +static void dft_stage_fn(stage_t * p, fifo_t * output_fifo) +{ + sample_t * output, tmp; + int i, j, num_in = max(0, fifo_occupancy(&p->fifo)); + rate_shared_t const * s = p->shared; + dft_filter_t const * f = &s->dft_filter[p->dft_filter_num]; + int const overlap = f->num_taps - 1; + + while (p->remL + p->L * num_in >= f->dft_length) { + div_t divd = div(f->dft_length - overlap - p->remL + p->L - 1, p->L); + sample_t const * input = fifo_read_ptr(&p->fifo); + fifo_read(&p->fifo, divd.quot, NULL); + num_in -= divd.quot; + + output = fifo_reserve(output_fifo, f->dft_length); + if (lsx_is_power_of_2(p->L)) { /* F-domain */ + int portion = f->dft_length / p->L; + memcpy(output, input, (unsigned)portion * sizeof(*output)); + lsx_safe_rdft(portion, 1, output); + for (i = portion + 2; i < (portion << 1); i += 2) + output[i] = output[(portion << 1) - i], + output[i+1] = -output[(portion << 1) - i + 1]; + output[portion] = output[1]; + output[portion + 1] = 0; + output[1] = output[0]; + for (portion <<= 1; i < f->dft_length; i += portion, portion <<= 1) { + memcpy(output + i, output, portion * sizeof(*output)); + output[i + 1] = 0; + } + } else { + if (p->L == 1) + memcpy(output, input, f->dft_length * sizeof(*output)); + else { + memset(output, 0, f->dft_length * sizeof(*output)); + for (j = 0, i = p->remL; i < f->dft_length; ++j, i += p->L) + output[i] = input[j]; + p->remL = p->L - 1 - divd.rem; + } + lsx_safe_rdft(f->dft_length, 1, output); + } + output[0] *= f->coefs[0]; + if (p->step.parts.integer > 0) { + output[1] *= f->coefs[1]; + for (i = 2; i < f->dft_length; i += 2) { + tmp = output[i]; + output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1]; + output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1]; + } + lsx_safe_rdft(f->dft_length, -1, output); + if (p->step.parts.integer != 1) { + for (j = 0, i = p->remM; i < f->dft_length - overlap; ++j, + i += p->step.parts.integer) + output[j] = output[i]; + p->remM = i - (f->dft_length - overlap); + fifo_trim_by(output_fifo, f->dft_length - j); + } + else fifo_trim_by(output_fifo, overlap); + } + else { /* F-domain */ + int m = -p->step.parts.integer; + for (i = 2; i < (f->dft_length >> m); i += 2) { + tmp = output[i]; + output[i ] = f->coefs[i ] * tmp - f->coefs[i+1] * output[i+1]; + output[i+1] = f->coefs[i+1] * tmp + f->coefs[i ] * output[i+1]; + } + output[1] = f->coefs[i] * output[i] - f->coefs[i+1] * output[i+1]; + lsx_safe_rdft(f->dft_length >> m, -1, output); + fifo_trim_by(output_fifo, (((1 << m) - 1) * f->dft_length + overlap) >>m); + } + } +} + +static void dft_stage_init( + unsigned instance, double Fp, double Fs, double Fn, double att, + double phase, stage_t * stage, int L, int M) +{ + dft_filter_t * f = &stage->shared->dft_filter[instance]; + + if (!f->num_taps) { + int num_taps = 0, dft_length, i; + int k = phase == 50 && lsx_is_power_of_2(L) && Fn == L? L << 1 : 4; + double * h = lsx_design_lpf(Fp, Fs, Fn, att, &num_taps, -k, -1.); + + if (phase != 50) + lsx_fir_to_phase(&h, &num_taps, &f->post_peak, phase); + else f->post_peak = num_taps / 2; + + dft_length = lsx_set_dft_length(num_taps); + f->coefs = calloc(dft_length, sizeof(*f->coefs)); + for (i = 0; i < num_taps; ++i) + f->coefs[(i + dft_length - num_taps + 1) & (dft_length - 1)] + = h[i] / dft_length * 2 * L; + free(h); + f->num_taps = num_taps; + f->dft_length = dft_length; + lsx_safe_rdft(dft_length, 1, f->coefs); + lsx_debug("fir_len=%i dft_length=%i Fp=%g Fs=%g Fn=%g att=%g %i/%i", + num_taps, dft_length, Fp, Fs, Fn, att, L, M); + } + stage->fn = dft_stage_fn; + stage->preload = f->post_peak / L; + stage->remL = f->post_peak % L; + stage->L = L; + stage->step.parts.integer = abs(3-M) == 1 && Fs == 1? -M/2 : M; + stage->dft_filter_num = instance; +} + +#include "rate_filters.h" + +typedef struct { + double factor; + uint64_t samples_in, samples_out; + int num_stages; + stage_t * stages; +} rate_t; + +#define pre_stage p->stages[shift] +#define arb_stage p->stages[shift + have_pre_stage] +#define post_stage p->stages[shift + have_pre_stage + have_arb_stage] +#define have_pre_stage (preM * preL != 1) +#define have_arb_stage (arbM * arbL != 1) +#define have_post_stage (postM * postL != 1) + +#define TO_3dB(a) ((1.6e-6*a-7.5e-4)*a+.646) +#define LOW_Q_BW0_PC (67 + 5 / 8.) + +typedef enum { + rolloff_none, rolloff_small /* <= 0.01 dB */, rolloff_medium /* <= 0.35 dB */ +} rolloff_t; + +static void rate_init( + /* Private work areas (to be supplied by the client): */ + rate_t * p, /* Per audio channel. */ + rate_shared_t * shared, /* Between channels (undergoing same rate change)*/ + + /* Public parameters: Typically */ + double factor, /* Input rate divided by output rate. */ + double bits, /* Required bit-accuracy (pass + stop) 16|20|28 */ + double phase, /* Linear/minimum etc. filter phase. 50 */ + double bw_pc, /* Pass-band % (0dB pt.) to preserve. 91.3|98.4*/ + double anti_aliasing_pc, /* % bandwidth without aliasing 100 */ + rolloff_t rolloff, /* Pass-band roll-off small */ + sox_bool maintain_3dB_pt, /* true */ + + /* Primarily for test/development purposes: */ + sox_bool use_hi_prec_clock,/* Increase irrational ratio accuracy. false */ + int interpolator, /* Force a particular coef interpolator. -1 */ + int max_coefs_size, /* k bytes of coefs to try to keep below. 400 */ + sox_bool noSmallIntOpt) /* Disable small integer optimisations. false */ +{ + double att = (bits + 1) * linear_to_dB(2.), attArb = att; /* pass + stop */ + double tbw0 = 1 - bw_pc / 100, Fs_a = 2 - anti_aliasing_pc / 100; + double arbM = factor, tbw_tighten = 1; + int n = 0, i, preL = 1, preM = 1, shift = 0, arbL = 1, postL = 1, postM = 1; + sox_bool upsample = sox_false, rational = sox_false, iOpt = !noSmallIntOpt; + int mode = rolloff > rolloff_small? factor > 1 || bw_pc > LOW_Q_BW0_PC : + ceil(2 + (bits - 17) / 4); + stage_t * s; + + assert(factor > 0); + assert(!bits || (15 <= bits && bits <= 33)); + assert(0 <= phase && phase <= 100); + assert(53 <= bw_pc && bw_pc <= 100); + assert(85 <= anti_aliasing_pc && anti_aliasing_pc <= 100); + + p->factor = factor; + if (bits) while (!n++) { /* Determine stages: */ + int try, L, M, x, maxL = interpolator > 0? 1 : mode? 2048 : + ceil(max_coefs_size * 1000. / (U100_l * sizeof(sample_t))); + double d, epsilon = 0, frac; + upsample = arbM < 1; + for (i = arbM * .5, shift = 0; i >>= 1; arbM *= .5, ++shift); + preM = upsample || (arbM > 1.5 && arbM < 2); + postM = 1 + (arbM > 1 && preM), arbM /= postM; + preL = 1 + (!preM && arbM < 2) + (upsample && mode), arbM *= preL; + if ((frac = arbM - (int)arbM)) + epsilon = fabs((uint32_t)(frac * MULT32 + .5) / (frac * MULT32) - 1); + for (i = 1, rational = !frac; i <= maxL && !rational; ++i) { + d = frac * i, try = d + .5; + if ((rational = fabs(try / d - 1) <= epsilon)) { /* No long doubles! */ + if (try == i) + arbM = ceil(arbM), shift += arbM > 2, arbM /= 1 + (arbM > 2); + else arbM = i * (int)arbM + try, arbL = i; + } + } + L = preL * arbL, M = arbM * postM, x = (L|M)&1, L >>= !x, M >>= !x; + if (iOpt && postL == 1 && (d = preL * arbL / arbM) > 4 && d != 5) { + for (postL = 4, i = d / 16; i >>= 1; postL <<= 1); + arbM = arbM * postL / arbL / preL, arbL = 1, n = 0; + } else if (rational && (max(L, M) < 3 + 2 * iOpt || L * M < 6 * iOpt)) + preL = L, preM = M, arbM = arbL = postM = 1; + if (!mode && (!rational || !n)) + ++mode, n = 0; + } + + p->num_stages = shift + have_pre_stage + have_arb_stage + have_post_stage; + + if (!p->num_stages) + return; + + p->stages = calloc(p->num_stages + 1, sizeof(*p->stages)); + for (i = 0; i < p->num_stages; ++i) + p->stages[i].shared = shared; + + if ((n = p->num_stages) > 1) { /* Att. budget: */ + if (have_arb_stage) + att += linear_to_dB(2.), attArb = att, --n; + att += linear_to_dB((double)n); + } + + for (n = 0; n + 1u < array_length(half_firs) && att > half_firs[n].att; ++n); + for (i = 0, s = p->stages; i < shift; ++i, ++s) { + s->fn = half_firs[n].fn; + s->pre_post = 4 * half_firs[n].num_coefs; + s->preload = s->pre = s->pre_post >> 1; + } + + if (have_pre_stage) { + if (maintain_3dB_pt && have_post_stage) { /* Trans. bands overlapping. */ + double tbw3 = tbw0 * TO_3dB(att); /* TODO: consider Fs_a. */ + double x = ((2.1429e-4 - 5.2083e-7 * att) * att - .015863) * att + 3.95; + x = att * pow((tbw0 - tbw3) / (postM / (factor * postL) - 1 + tbw0), x); + if (x > .035) { + tbw_tighten = ((4.3074e-3 - 3.9121e-4 * x) * x - .040009) * x + 1.0014; + lsx_debug("x=%g tbw_tighten=%g", x, tbw_tighten); + } + } + dft_stage_init(0, 1 - tbw0 * tbw_tighten, Fs_a, preM? max(preL, preM) : + arbM / arbL, att, phase, &pre_stage, preL, max(preM, 1)); + } + + if (!bits) { /* Quick and dirty arb stage: */ + arb_stage.fn = cubic_stage_fn; + arb_stage.step.all = arbM * MULT32 + .5; + arb_stage.pre_post = max(3, arb_stage.step.parts.integer); + arb_stage.preload = arb_stage.pre = 1; + arb_stage.out_in_ratio = MULT32 * arbL / arb_stage.step.all; + } + else if (have_arb_stage) { /* Higher quality arb stage: */ + poly_fir_t const * f = &poly_firs[6*(upsample + !!preM) + mode - !upsample]; + int order, num_coefs = f->interp[0].scalar, phase_bits, phases, coefs_size; + double x = .5, at, Fp, Fs, Fn, mult = upsample? 1 : arbL / arbM; + poly_fir1_t const * f1; + + Fn = !upsample && preM? x = arbM / arbL : 1; + Fp = !preM? mult : mode? .5 : 1; + Fs = 2 - Fp; /* Ignore Fs_a; it would have little benefit here. */ + Fp *= 1 - tbw0; + if (rolloff > rolloff_small && mode) + Fp = !preM? mult * .5 - .125 : mult * .05 + .1; + else if (rolloff == rolloff_small) + Fp = Fs - (Fs - .148 * x - Fp * .852) * (.00813 * bits + .973); + + i = (interpolator < 0? !rational : max(interpolator, !rational)) - 1; + do { + f1 = &f->interp[++i]; + assert(f1->fn); + if (i) + arbM /= arbL, arbL = 1, rational = sox_false; + phase_bits = ceil(f1->scalar + log(mult)/log(2.)); + phases = !rational? (1 << phase_bits) : arbL; + if (!f->interp[0].scalar) { + int phases0 = max(phases, 19), n0 = 0; + lsx_design_lpf(Fp, Fs, -Fn, attArb, &n0, phases0, f->beta); + num_coefs = n0 / phases0 + 1, num_coefs += num_coefs & !preM; + } + if ((num_coefs & 1) && rational && (arbL & 1)) + phases <<= 1, arbL <<= 1, arbM *= 2; + at = arbL * .5 * (num_coefs & 1); + order = i + (i && mode > 4); + coefs_size = num_coefs4 * phases * (order + 1) * sizeof(sample_t); + } while (interpolator < 0 && i < 2 && f->interp[i+1].fn && + coefs_size / 1000 > max_coefs_size); + + if (!arb_stage.shared->poly_fir_coefs) { + int num_taps = num_coefs * phases - 1; + raw_coef_t * coefs = lsx_design_lpf( + Fp, Fs, Fn, attArb, &num_taps, phases, f->beta); + arb_stage.shared->poly_fir_coefs = prepare_coefs( + coefs, num_coefs, phases, order, 1); + lsx_debug("fir_len=%i phases=%i coef_interp=%i size=%s", + num_coefs, phases, order, lsx_sigfigs3((double)coefs_size)); + free(coefs); + } + arb_stage.fn = f1->fn; + arb_stage.pre_post = num_coefs4 - 1; + arb_stage.preload = (num_coefs - 1) >> 1; + arb_stage.n = num_coefs4; + arb_stage.phase_bits = phase_bits; + arb_stage.L = arbL; + arb_stage.use_hi_prec_clock = mode > 1 && use_hi_prec_clock && !rational; + if (arb_stage.use_hi_prec_clock) { + arb_stage.at.hi_prec_clock = at; + arb_stage.step.hi_prec_clock = arbM; + arb_stage.out_in_ratio = arbL / arb_stage.step.hi_prec_clock; + } else { + arb_stage.at.all = at * MULT32 + .5; + arb_stage.step.all = arbM * MULT32 + .5; + arb_stage.out_in_ratio = MULT32 * arbL / arb_stage.step.all; + } + } + + if (have_post_stage) + dft_stage_init(1, 1 - (1 - (1 - tbw0) * + (upsample? factor * postL / postM : 1)) * tbw_tighten, Fs_a, + (double)max(postL, postM), att, phase, &post_stage, postL, postM); + + for (i = 0, s = p->stages; i < p->num_stages; ++i, ++s) { + fifo_create(&s->fifo, (int)sizeof(sample_t)); + memset(fifo_reserve(&s->fifo, s->preload), 0, sizeof(sample_t)*s->preload); + lsx_debug("%5i|%-5i preload=%i remL=%i", + s->pre, s->pre_post - s->pre, s->preload, s->remL); + } + fifo_create(&s->fifo, (int)sizeof(sample_t)); +} + +static void rate_process(rate_t * p) +{ + stage_t * stage = p->stages; + int i; + + for (i = 0; i < p->num_stages; ++i, ++stage) + stage->fn(stage, &(stage+1)->fifo); +} + +static sample_t * rate_input(rate_t * p, sample_t const * samples, size_t n) +{ + p->samples_in += n; + return fifo_write(&p->stages[0].fifo, (int)n, samples); +} + +static sample_t const * rate_output(rate_t * p, sample_t * samples, size_t * n) +{ + fifo_t * fifo = &p->stages[p->num_stages].fifo; + p->samples_out += *n = min(*n, (size_t)fifo_occupancy(fifo)); + return fifo_read(fifo, (int)*n, samples); +} + +static void rate_flush(rate_t * p) +{ + fifo_t * fifo = &p->stages[p->num_stages].fifo; + uint64_t samples_out = p->samples_in / p->factor + .5; + size_t remaining = samples_out > p->samples_out ? + (size_t)(samples_out - p->samples_out) : 0; + sample_t * buff = calloc(1024, sizeof(*buff)); + + if (remaining > 0) { + while ((size_t)fifo_occupancy(fifo) < remaining) { + rate_input(p, buff, (size_t) 1024); + rate_process(p); + } + fifo_trim_to(fifo, (int)remaining); + p->samples_in = 0; + } + free(buff); +} + +static void rate_close(rate_t * p) +{ + rate_shared_t *shared; + int i; + + if (!p->num_stages) + return; + + shared = p->stages[0].shared; + + for (i = 0; i <= p->num_stages; ++i) + fifo_delete(&p->stages[i].fifo); + free(shared->dft_filter[0].coefs); + free(shared->dft_filter[1].coefs); + free(shared->poly_fir_coefs); + memset(shared, 0, sizeof(*shared)); + free(p->stages); +} + +/*------------------------------- SoX Wrapper --------------------------------*/ + +typedef struct { + sox_rate_t out_rate; + int rolloff, coef_interp, max_coefs_size; + double bit_depth, phase, bw_0dB_pc, anti_aliasing_pc; + sox_bool use_hi_prec_clock, noIOpt, given_0dB_pt; + rate_t rate; + rate_shared_t shared, * shared_ptr; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *) effp->priv; + int c, quality; + char * dummy_p, * found_at; + char const * opts = "+i:c:b:B:A:p:Q:R:d:MILafnost" "qlmghevu"; + char const * qopts = strchr(opts, 'q'); + double rej = 0, bw_3dB_pc = 0; + sox_bool allow_aliasing = sox_false; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_none, 1, &optstate); + + p->coef_interp = quality = -1; + p->rolloff = rolloff_small; + p->phase = 50; + p->max_coefs_size = 400; + p->shared_ptr = &p->shared; + + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + GETOPT_NUMERIC(optstate, 'i', coef_interp, -1, 2) + GETOPT_NUMERIC(optstate, 'c', max_coefs_size, 100, INT_MAX) + GETOPT_NUMERIC(optstate, 'p', phase, 0, 100) + GETOPT_NUMERIC(optstate, 'B', bw_0dB_pc, 53, 99.5) + GETOPT_NUMERIC(optstate, 'A', anti_aliasing_pc, 85, 100) + GETOPT_NUMERIC(optstate, 'd', bit_depth, 15, 33) + GETOPT_LOCAL_NUMERIC(optstate, 'b', bw_3dB_pc, 74, 99.7) + GETOPT_LOCAL_NUMERIC(optstate, 'R', rej, 90, 200) + GETOPT_LOCAL_NUMERIC(optstate, 'Q', quality, 0, 7) + case 'M': p->phase = 0; break; + case 'I': p->phase = 25; break; + case 'L': p->phase = 50; break; + case 'a': allow_aliasing = sox_true; break; + case 'f': p->rolloff = rolloff_none; break; + case 'n': p->noIOpt = sox_true; break; + case 's': bw_3dB_pc = 99; break; + case 't': p->use_hi_prec_clock = sox_true; break; + default: + if ((found_at = strchr(qopts, c))) + quality = found_at - qopts; + else { + lsx_fail("unknown option `-%c'", optstate.opt); + return lsx_usage(effp); + } + } + argc -= optstate.ind, argv += optstate.ind; + + if ((unsigned)quality < 2 && (p->bw_0dB_pc || bw_3dB_pc || p->phase != 50 || + allow_aliasing || rej || p->bit_depth || p->anti_aliasing_pc)) { + lsx_fail("override options not allowed with this quality level"); + return SOX_EOF; + } + if (quality < 0 && rej == 0 && p->bit_depth == 0) + quality = 4; + if (rej) + p->bit_depth = rej / linear_to_dB(2.); + else { + if (quality >= 0) { + p->bit_depth = quality? 16 + 4 * max(quality - 3, 0) : 0; + if (quality <= 2) + p->rolloff = rolloff_medium; + } + rej = p->bit_depth * linear_to_dB(2.); + } + + if (bw_3dB_pc && p->bw_0dB_pc) { + lsx_fail("conflicting bandwidth options"); + return SOX_EOF; + } + allow_aliasing |= p->anti_aliasing_pc != 0; + if (!bw_3dB_pc && !p->bw_0dB_pc) + p->bw_0dB_pc = quality == 1? LOW_Q_BW0_PC : 100 - 5 / TO_3dB(rej); + else if (bw_3dB_pc && bw_3dB_pc < 85 && allow_aliasing) { + lsx_fail("minimum allowed 3dB bandwidth with aliasing is %g%%", 85.); + return SOX_EOF; + } + else if (p->bw_0dB_pc && p->bw_0dB_pc < 74 && allow_aliasing) { + lsx_fail("minimum allowed bandwidth with aliasing is %g%%", 74.); + return SOX_EOF; + } + if (bw_3dB_pc) + p->bw_0dB_pc = 100 - (100 - bw_3dB_pc) / TO_3dB(rej); + else { + bw_3dB_pc = 100 - (100 - p->bw_0dB_pc) * TO_3dB(rej); + p->given_0dB_pt = sox_true; + } + p->anti_aliasing_pc = p->anti_aliasing_pc? p->anti_aliasing_pc : + allow_aliasing? bw_3dB_pc : 100; + + if (argc) { + if ((p->out_rate = lsx_parse_frequency(*argv, &dummy_p)) <= 0 || *dummy_p) + return lsx_usage(effp); + argc--; argv++; + effp->out_signal.rate = p->out_rate; + } + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + double out_rate = p->out_rate != 0 ? p->out_rate : effp->out_signal.rate; + + if (effp->in_signal.rate == out_rate) + return SOX_EFF_NULL; + + if (effp->in_signal.mult) + *effp->in_signal.mult *= .705; /* 1/(2/sinc(pi/3)-1); see De Soras 4.1.2 */ + + effp->out_signal.channels = effp->in_signal.channels; + effp->out_signal.rate = out_rate; + rate_init(&p->rate, p->shared_ptr, effp->in_signal.rate/out_rate,p->bit_depth, + p->phase, p->bw_0dB_pc, p->anti_aliasing_pc, p->rolloff, !p->given_0dB_pt, + p->use_hi_prec_clock, p->coef_interp, p->max_coefs_size, p->noIOpt); + + if (!p->rate.num_stages) { + lsx_warn("input and output rates too close, skipping resampling"); + return SOX_EFF_NULL; + } + + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t odone = *osamp; + + sample_t const * s = rate_output(&p->rate, NULL, &odone); + lsx_save_samples(obuf, s, odone, &effp->clips); + + if (*isamp && odone < *osamp) { + sample_t * t = rate_input(&p->rate, NULL, *isamp); + lsx_load_samples(t, ibuf, *isamp); + rate_process(&p->rate); + } + else *isamp = 0; + *osamp = odone; + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + static size_t isamp = 0; + rate_flush(&p->rate); + return flow(effp, 0, obuf, &isamp, osamp); +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + rate_close(&p->rate); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_rate_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "rate", 0, SOX_EFF_RATE, create, start, flow, drain, stop, 0, sizeof(priv_t) + }; + static char const * lines[] = { + "[-q|-l|-m|-h|-v] [override-options] RATE[k]", + " BAND-", + " QUALITY WIDTH REJ dB TYPICAL USE", + " -q quick n/a ~30 @ Fs/4 playback on ancient hardware", + " -l low 80% 100 playback on old hardware", + " -m medium 95% 100 audio playback", + " -h high (default) 95% 125 16-bit mastering (use with dither)", + " -v very high 95% 175 24-bit mastering", + " OVERRIDE OPTIONS (only with -m, -h, -v)", + " -M/-I/-L Phase response = minimum/intermediate/linear(default)", + " -s Steep filter (band-width = 99%)", + " -a Allow aliasing above the pass-band", + " -b 74-99.7 Any band-width %", + " -p 0-100 Any phase response (0 = minimum, 25 = intermediate,", + " 50 = linear, 100 = maximum)", + }; + static char * usage; + handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); + return &handler; +} diff --git a/app/src/main/cpp/sox/rate_filters.h b/app/src/main/cpp/sox/rate_filters.h new file mode 100644 index 0000000..842bf36 --- /dev/null +++ b/app/src/main/cpp/sox/rate_filters.h @@ -0,0 +1,187 @@ +/* Effect: change sample rate Copyright (c) 2008,12 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static const sample_t half_fir_coefs_8[] = { + 0.3115465451887802, -0.08734497241282892, 0.03681452335604365, + -0.01518925831569441, 0.005454118437408876, -0.001564400922162005, + 0.0003181701445034203, -3.48001341225749e-5, +}; +#define FUNCTION h8 +#define CONVOLVE _ _ _ _ _ _ _ _ +#define h8_l 8 +#define COEFS half_fir_coefs_8 +#include "rate_half_fir.h" + +static const sample_t half_fir_coefs_9[] = { + 0.3122703613711853, -0.08922155288172305, 0.03913974805854332, + -0.01725059723447163, 0.006858970092378141, -0.002304518467568703, + 0.0006096426006051062, -0.0001132393923815236, 1.119795386287666e-5, +}; +#define FUNCTION h9 +#define CONVOLVE _ _ _ _ _ _ _ _ _ +#define h9_l 9 +#define COEFS half_fir_coefs_9 +#include "rate_half_fir.h" + +static const sample_t half_fir_coefs_10[] = { + 0.3128545521327376, -0.09075671986104322, 0.04109637155154835, + -0.01906629512749895, 0.008184039342054333, -0.0030766775017262, + 0.0009639607022414314, -0.0002358552746579827, 4.025184282444155e-5, + -3.629779111541012e-6, +}; +#define FUNCTION h10 +#define CONVOLVE _ _ _ _ _ _ _ _ _ _ +#define h10_l 10 +#define COEFS half_fir_coefs_10 +#include "rate_half_fir.h" + +static const sample_t half_fir_coefs_11[] = { + 0.3133358837508807, -0.09203588680609488, 0.04276515428384758, + -0.02067356614745591, 0.00942253142371517, -0.003856330993895144, + 0.001363470684892284, -0.0003987400965541919, 9.058629923971627e-5, + -1.428553070915318e-5, 1.183455238783835e-6, +}; +#define FUNCTION h11 +#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ +#define h11_l 11 +#define COEFS half_fir_coefs_11 +#include "rate_half_fir.h" + +static const sample_t half_fir_coefs_12[] = { + 0.3137392991811407, -0.0931182192961332, 0.0442050575271454, + -0.02210391200618091, 0.01057473015666001, -0.00462766983973885, + 0.001793630226239453, -0.0005961819959665878, 0.0001631475979359577, + -3.45557865639653e-5, 5.06188341942088e-6, -3.877010943315563e-7, +}; +#define FUNCTION h12 +#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ +#define h12_l 12 +#define COEFS half_fir_coefs_12 +#include "rate_half_fir.h" + +static const sample_t half_fir_coefs_13[] = { + 0.3140822554324578, -0.0940458550886253, 0.04545990399121566, + -0.02338339450796002, 0.01164429409071052, -0.005380686021429845, + 0.002242915773871009, -0.000822047600000082, 0.0002572510962395222, + -6.607320708956279e-5, 1.309926399120154e-5, -1.790719575255006e-6, + 1.27504961098836e-7, +}; +#define FUNCTION h13 +#define CONVOLVE _ _ _ _ _ _ _ _ _ _ _ _ _ +#define h13_l 13 +#define COEFS half_fir_coefs_13 +#include "rate_half_fir.h" + +static struct {int num_coefs; stage_fn_t fn; float att;} const half_firs[] = { + { 8, h8 , 136.51}, + { 9, h9 , 152.32}, + {10, h10, 168.07}, + {11, h11, 183.78}, + {12, h12, 199.44}, + {13, h13, 212.75}, +}; + +#define HI_PREC_CLOCK + +#define VAR_LENGTH p->n +#define VAR_CONVOLVE while (j < FIR_LENGTH) _ +#define VAR_POLY_PHASE_BITS p->phase_bits + +#define FUNCTION vpoly0 +#define FIR_LENGTH VAR_LENGTH +#define CONVOLVE VAR_CONVOLVE +#include "rate_poly_fir0.h" + +#define FUNCTION vpoly1 +#define COEF_INTERP 1 +#define PHASE_BITS VAR_POLY_PHASE_BITS +#define FIR_LENGTH VAR_LENGTH +#define CONVOLVE VAR_CONVOLVE +#include "rate_poly_fir.h" + +#define FUNCTION vpoly2 +#define COEF_INTERP 2 +#define PHASE_BITS VAR_POLY_PHASE_BITS +#define FIR_LENGTH VAR_LENGTH +#define CONVOLVE VAR_CONVOLVE +#include "rate_poly_fir.h" + +#define FUNCTION vpoly3 +#define COEF_INTERP 3 +#define PHASE_BITS VAR_POLY_PHASE_BITS +#define FIR_LENGTH VAR_LENGTH +#define CONVOLVE VAR_CONVOLVE +#include "rate_poly_fir.h" + +#undef HI_PREC_CLOCK + +#define U100_l 42 +#define poly_fir_convolve_U100 _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ +#define FUNCTION U100_0 +#define FIR_LENGTH U100_l +#define CONVOLVE poly_fir_convolve_U100 +#include "rate_poly_fir0.h" + +#define u100_l 11 +#define poly_fir_convolve_u100 _ _ _ _ _ _ _ _ _ _ _ +#define FUNCTION u100_0 +#define FIR_LENGTH u100_l +#define CONVOLVE poly_fir_convolve_u100 +#include "rate_poly_fir0.h" + +#define FUNCTION u100_1 +#define COEF_INTERP 1 +#define PHASE_BITS 8 +#define FIR_LENGTH u100_l +#define CONVOLVE poly_fir_convolve_u100 +#include "rate_poly_fir.h" +#define u100_1_b 8 + +#define FUNCTION u100_2 +#define COEF_INTERP 2 +#define PHASE_BITS 6 +#define FIR_LENGTH u100_l +#define CONVOLVE poly_fir_convolve_u100 +#include "rate_poly_fir.h" +#define u100_2_b 6 + +typedef struct {float scalar; stage_fn_t fn;} poly_fir1_t; +typedef struct {float beta; poly_fir1_t interp[3];} poly_fir_t; + +static poly_fir_t const poly_firs[] = { + {-1, {{0, vpoly0}, { 7.2, vpoly1}, {5.0, vpoly2}}}, + {-1, {{0, vpoly0}, { 9.4, vpoly1}, {6.7, vpoly2}}}, + {-1, {{0, vpoly0}, {12.4, vpoly1}, {7.8, vpoly2}}}, + {-1, {{0, vpoly0}, {13.6, vpoly1}, {9.3, vpoly2}}}, + {-1, {{0, vpoly0}, {10.5, vpoly2}, {8.4, vpoly3}}}, + {-1, {{0, vpoly0}, {11.85,vpoly2}, {9.0, vpoly3}}}, + + {-1, {{0, vpoly0}, { 8.0, vpoly1}, {5.3, vpoly2}}}, + {-1, {{0, vpoly0}, { 8.6, vpoly1}, {5.7, vpoly2}}}, + {-1, {{0, vpoly0}, {10.6, vpoly1}, {6.75,vpoly2}}}, + {-1, {{0, vpoly0}, {12.6, vpoly1}, {8.6, vpoly2}}}, + {-1, {{0, vpoly0}, { 9.6, vpoly2}, {7.6, vpoly3}}}, + {-1, {{0, vpoly0}, {11.4, vpoly2}, {8.65,vpoly3}}}, + + {10.62, {{U100_l, U100_0}, {0, 0}, {0, 0}}}, + {11.28, {{u100_l, u100_0}, {u100_1_b, u100_1}, {u100_2_b, u100_2}}}, + {-1, {{0, vpoly0}, { 9, vpoly1}, { 6, vpoly2}}}, + {-1, {{0, vpoly0}, { 11, vpoly1}, { 7, vpoly2}}}, + {-1, {{0, vpoly0}, { 13, vpoly1}, { 8, vpoly2}}}, + {-1, {{0, vpoly0}, { 10, vpoly2}, { 8, vpoly3}}}, + {-1, {{0, vpoly0}, { 12, vpoly2}, { 9, vpoly3}}}, +}; diff --git a/app/src/main/cpp/sox/rate_half_fir.h b/app/src/main/cpp/sox/rate_half_fir.h new file mode 100644 index 0000000..4327e61 --- /dev/null +++ b/app/src/main/cpp/sox/rate_half_fir.h @@ -0,0 +1,39 @@ +/* Effect: change sample rate Copyright (c) 2008,12 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Down-sample by a factor of 2 using a FIR with odd length (LEN).*/ +/* Input must be preceded and followed by LEN >> 1 samples. */ + +#define _ sum += (input[-(2*j +1)] + input[(2*j +1)]) * COEFS[j], ++j; +static void FUNCTION(stage_t * p, fifo_t * output_fifo) +{ + sample_t const * input = stage_read_p(p); + int i, num_out = (stage_occupancy(p) + 1) / 2; + sample_t * output = fifo_reserve(output_fifo, num_out); + + for (i = 0; i < num_out; ++i, input += 2) { + int j = 0; + sample_t sum = input[0] * .5; + CONVOLVE + output[i] = sum; + } + fifo_read(&p->fifo, 2 * num_out, NULL); +} +#undef _ +#undef COEFS +#undef CONVOLVE +#undef FUNCTION diff --git a/app/src/main/cpp/sox/rate_poly_fir.h b/app/src/main/cpp/sox/rate_poly_fir.h new file mode 100644 index 0000000..deca303 --- /dev/null +++ b/app/src/main/cpp/sox/rate_poly_fir.h @@ -0,0 +1,91 @@ +/* Effect: change sample rate Copyright (c) 2008,12 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Resample using an interpolated poly-phase FIR with length LEN.*/ +/* Input must be followed by LEN-1 samples. */ + +#define a (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 0,j)) +#define b (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 1,j)) +#define c (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 2,j)) +#define d (coef(p->shared->poly_fir_coefs, COEF_INTERP, FIR_LENGTH, phase, 3,j)) +#if COEF_INTERP == 0 + #define _ sum += a *in[j], ++j; +#elif COEF_INTERP == 1 + #define _ sum += (b *x + a)*in[j], ++j; +#elif COEF_INTERP == 2 + #define _ sum += ((c *x + b)*x + a)*in[j], ++j; +#elif COEF_INTERP == 3 + #define _ sum += (((d*x + c)*x + b)*x + a)*in[j], ++j; +#else + #error COEF_INTERP +#endif + +static void FUNCTION(stage_t * p, fifo_t * output_fifo) +{ + sample_t const * input = stage_read_p(p); + int i, num_in = stage_occupancy(p), max_num_out = 1 + num_in*p->out_in_ratio; + sample_t * output = fifo_reserve(output_fifo, max_num_out); + +#if defined HI_PREC_CLOCK + if (p->use_hi_prec_clock) { + hi_prec_clock_t at = p->at.hi_prec_clock; + for (i = 0; (int)at < num_in; ++i, at += p->step.hi_prec_clock) { + sample_t const * in = input + (int)at; + hi_prec_clock_t fraction = at - (int)at; + int phase = fraction * (1 << PHASE_BITS); +#if COEF_INTERP > 0 + sample_t x = fraction * (1 << PHASE_BITS) - phase; +#endif + sample_t sum = 0; + int j = 0; + CONVOLVE + output[i] = sum; + } + fifo_read(&p->fifo, (int)at, NULL); + p->at.hi_prec_clock = at - (int)at; + } else +#endif + { + for (i = 0; p->at.parts.integer < num_in; ++i, p->at.all += p->step.all) { + sample_t const * in = input + p->at.parts.integer; + uint32_t fraction = p->at.parts.fraction; + int phase = fraction >> (32 - PHASE_BITS); /* high-order bits */ +#if COEF_INTERP > 0 /* low-order bits, scaled to [0,1) */ + sample_t x = (sample_t) (fraction << PHASE_BITS) * (1 / MULT32); +#endif + sample_t sum = 0; + int j = 0; + CONVOLVE + output[i] = sum; + } + fifo_read(&p->fifo, p->at.parts.integer, NULL); + p->at.parts.integer = 0; + } + assert(max_num_out - i >= 0); + fifo_trim_by(output_fifo, max_num_out - i); +} + +#undef _ +#undef a +#undef b +#undef c +#undef d +#undef COEF_INTERP +#undef CONVOLVE +#undef FIR_LENGTH +#undef FUNCTION +#undef PHASE_BITS diff --git a/app/src/main/cpp/sox/rate_poly_fir0.h b/app/src/main/cpp/sox/rate_poly_fir0.h new file mode 100644 index 0000000..38790f6 --- /dev/null +++ b/app/src/main/cpp/sox/rate_poly_fir0.h @@ -0,0 +1,48 @@ +/* Effect: change sample rate Copyright (c) 2008,12 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Resample using a non-interpolated poly-phase FIR with length LEN.*/ +/* Input must be followed by LEN-1 samples. */ + +#define _ sum += (coef(p->shared->poly_fir_coefs, 0, FIR_LENGTH, divided.rem, 0, j)) *at[j], ++j; + +static void FUNCTION(stage_t * p, fifo_t * output_fifo) +{ + sample_t const * input = stage_read_p(p); + int i, num_in = stage_occupancy(p), max_num_out = 1 + num_in*p->out_in_ratio; + sample_t * output = fifo_reserve(output_fifo, max_num_out); + div_t divided2; + + for (i = 0; p->at.parts.integer < num_in * p->L; ++i, p->at.parts.integer += p->step.parts.integer) { + div_t divided = div(p->at.parts.integer, p->L); + sample_t const * at = input + divided.quot; + sample_t sum = 0; + int j = 0; + CONVOLVE + output[i] = sum; + } + assert(max_num_out - i >= 0); + fifo_trim_by(output_fifo, max_num_out - i); + divided2 = div(p->at.parts.integer, p->L); + fifo_read(&p->fifo, divided2.quot, NULL); + p->at.parts.integer = divided2.rem; +} + +#undef _ +#undef CONVOLVE +#undef FIR_LENGTH +#undef FUNCTION diff --git a/app/src/main/cpp/sox/raw-fmt.c b/app/src/main/cpp/sox/raw-fmt.c new file mode 100644 index 0000000..15768db --- /dev/null +++ b/app/src/main/cpp/sox/raw-fmt.c @@ -0,0 +1,61 @@ +/* libSoX file formats: raw (c) 2007-11 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +static int raw_start(sox_format_t * ft) { + return lsx_rawstart(ft, sox_false, sox_false, sox_true, SOX_ENCODING_UNKNOWN, 0); +} + +LSX_FORMAT_HANDLER(raw) +{ + static char const * const names[] = {"raw", NULL}; + static unsigned const encodings[] = { + SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, + SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0, + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_FLOAT, 64, 32, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Raw PCM, mu-law, or A-law", names, 0, + raw_start, lsx_rawread , NULL, + raw_start, lsx_rawwrite, NULL, + lsx_rawseek, encodings, NULL, 0 + }; + return &handler; +} + +static int sln_start(sox_format_t * ft) +{ + return lsx_check_read_params(ft, 1, 8000., SOX_ENCODING_SIGN2, 16, (uint64_t)0, sox_false); +} + +LSX_FORMAT_HANDLER(sln) +{ + static char const * const names[] = {"sln", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0}; + static sox_rate_t const write_rates[] = {8000, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Asterisk PBX headerless format", + names, SOX_FILE_LIT_END|SOX_FILE_MONO, + sln_start, lsx_rawread, NULL, + NULL, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, write_rates, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/raw.c b/app/src/main/cpp/sox/raw.c new file mode 100644 index 0000000..6c0eaa1 --- /dev/null +++ b/app/src/main/cpp/sox/raw.c @@ -0,0 +1,196 @@ +/* libSoX raw I/O + * + * Copyright 1991-2007 Lance Norskog And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" +#include "g711.h" + +typedef sox_uint16_t sox_uint14_t; +typedef sox_uint16_t sox_uint13_t; +typedef sox_int16_t sox_int14_t; +typedef sox_int16_t sox_int13_t; +#define SOX_ULAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_ulaw2linear16(d),clips) +#define SOX_ALAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_alaw2linear16(d),clips) +#define SOX_SAMPLE_TO_ULAW_BYTE(d,c) sox_14linear2ulaw(SOX_SAMPLE_TO_UNSIGNED(14,d,c) - 0x2000) +#define SOX_SAMPLE_TO_ALAW_BYTE(d,c) sox_13linear2alaw(SOX_SAMPLE_TO_UNSIGNED(13,d,c) - 0x1000) + +int lsx_rawseek(sox_format_t * ft, uint64_t offset) +{ + return lsx_offset_seek(ft, (off_t)ft->data_start, (off_t)offset); +} + +/* Works nicely for starting read and write; lsx_rawstart{read,write} + * are #defined in sox_i.h */ +int lsx_rawstart(sox_format_t * ft, sox_bool default_rate, + sox_bool default_channels, sox_bool default_length, + sox_encoding_t encoding, unsigned size) +{ + if (default_rate && ft->signal.rate == 0) { + lsx_warn("`%s': sample rate not specified; trying 8kHz", ft->filename); + ft->signal.rate = 8000; + } + + if (default_channels && ft->signal.channels == 0) { + lsx_warn("`%s': # channels not specified; trying mono", ft->filename); + ft->signal.channels = 1; + } + + if (encoding != SOX_ENCODING_UNKNOWN) { + if (ft->mode == 'r' && ft->encoding.encoding != SOX_ENCODING_UNKNOWN && + ft->encoding.encoding != encoding) + lsx_report("`%s': Format options overriding file-type encoding", + ft->filename); + else + ft->encoding.encoding = encoding; + } + + if (size != 0) { + if (ft->mode == 'r' && ft->encoding.bits_per_sample != 0 && + ft->encoding.bits_per_sample != size) + lsx_report("`%s': Format options overriding file-type sample-size", + ft->filename); + else + ft->encoding.bits_per_sample = size; + } + + if (!ft->signal.length && ft->mode == 'r' && default_length && + ft->encoding.bits_per_sample) + ft->signal.length = + div_bits(lsx_filelength(ft), ft->encoding.bits_per_sample); + + return SOX_SUCCESS; +} + +#define READ_SAMPLES_FUNC(type, size, sign, ctype, uctype, cast) \ + static size_t sox_read_ ## sign ## type ## _samples( \ + sox_format_t * ft, sox_sample_t *buf, size_t len) \ + { \ + size_t n, nread; \ + SOX_SAMPLE_LOCALS; \ + ctype *data = lsx_malloc(sizeof(ctype) * len); \ + LSX_USE_VAR(sox_macro_temp_sample), LSX_USE_VAR(sox_macro_temp_double); \ + nread = lsx_read_ ## type ## _buf(ft, (uctype *)data, len); \ + for (n = 0; n < nread; n++) \ + *buf++ = cast(data[n], ft->clips); \ + free(data); \ + return nread; \ + } + +READ_SAMPLES_FUNC(b, 1, u, uint8_t, uint8_t, SOX_UNSIGNED_8BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(b, 1, s, int8_t, uint8_t, SOX_SIGNED_8BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(b, 1, ulaw, uint8_t, uint8_t, SOX_ULAW_BYTE_TO_SAMPLE) +READ_SAMPLES_FUNC(b, 1, alaw, uint8_t, uint8_t, SOX_ALAW_BYTE_TO_SAMPLE) +READ_SAMPLES_FUNC(w, 2, u, uint16_t, uint16_t, SOX_UNSIGNED_16BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(w, 2, s, int16_t, uint16_t, SOX_SIGNED_16BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(3, 3, u, sox_uint24_t, sox_uint24_t, SOX_UNSIGNED_24BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(3, 3, s, sox_int24_t, sox_uint24_t, SOX_SIGNED_24BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(dw, 4, u, uint32_t, uint32_t, SOX_UNSIGNED_32BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(dw, 4, s, int32_t, uint32_t, SOX_SIGNED_32BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(f, sizeof(float), su, float, float, SOX_FLOAT_32BIT_TO_SAMPLE) +READ_SAMPLES_FUNC(df, sizeof(double), su, double, double, SOX_FLOAT_64BIT_TO_SAMPLE) + +#define WRITE_SAMPLES_FUNC(type, size, sign, ctype, uctype, cast) \ + static size_t sox_write_ ## sign ## type ## _samples( \ + sox_format_t * ft, sox_sample_t const * buf, size_t len) \ + { \ + SOX_SAMPLE_LOCALS; \ + size_t n, nwritten; \ + ctype *data = lsx_malloc(sizeof(ctype) * len); \ + LSX_USE_VAR(sox_macro_temp_sample), LSX_USE_VAR(sox_macro_temp_double); \ + for (n = 0; n < len; n++) \ + data[n] = cast(buf[n], ft->clips); \ + nwritten = lsx_write_ ## type ## _buf(ft, (uctype *)data, len); \ + free(data); \ + return nwritten; \ + } + + +WRITE_SAMPLES_FUNC(b, 1, u, uint8_t, uint8_t, SOX_SAMPLE_TO_UNSIGNED_8BIT) +WRITE_SAMPLES_FUNC(b, 1, s, int8_t, uint8_t, SOX_SAMPLE_TO_SIGNED_8BIT) +WRITE_SAMPLES_FUNC(b, 1, ulaw, uint8_t, uint8_t, SOX_SAMPLE_TO_ULAW_BYTE) +WRITE_SAMPLES_FUNC(b, 1, alaw, uint8_t, uint8_t, SOX_SAMPLE_TO_ALAW_BYTE) +WRITE_SAMPLES_FUNC(w, 2, u, uint16_t, uint16_t, SOX_SAMPLE_TO_UNSIGNED_16BIT) +WRITE_SAMPLES_FUNC(w, 2, s, int16_t, uint16_t, SOX_SAMPLE_TO_SIGNED_16BIT) +WRITE_SAMPLES_FUNC(3, 3, u, sox_uint24_t, sox_uint24_t, SOX_SAMPLE_TO_UNSIGNED_24BIT) +WRITE_SAMPLES_FUNC(3, 3, s, sox_int24_t, sox_uint24_t, SOX_SAMPLE_TO_SIGNED_24BIT) +WRITE_SAMPLES_FUNC(dw, 4, u, uint32_t, uint32_t, SOX_SAMPLE_TO_UNSIGNED_32BIT) +WRITE_SAMPLES_FUNC(dw, 4, s, int32_t, uint32_t, SOX_SAMPLE_TO_SIGNED_32BIT) +WRITE_SAMPLES_FUNC(f, sizeof(float), su, float, float, SOX_SAMPLE_TO_FLOAT_32BIT) +WRITE_SAMPLES_FUNC(df, sizeof (double), su, double, double, SOX_SAMPLE_TO_FLOAT_64BIT) + +#define GET_FORMAT(type) \ +static ft_##type##_fn * type##_fn(sox_format_t * ft) { \ + switch (ft->encoding.bits_per_sample) { \ + case 8: \ + switch (ft->encoding.encoding) { \ + case SOX_ENCODING_SIGN2: return sox_##type##_sb_samples; \ + case SOX_ENCODING_UNSIGNED: return sox_##type##_ub_samples; \ + case SOX_ENCODING_ULAW: return sox_##type##_ulawb_samples; \ + case SOX_ENCODING_ALAW: return sox_##type##_alawb_samples; \ + default: break; } \ + break; \ + case 16: \ + switch (ft->encoding.encoding) { \ + case SOX_ENCODING_SIGN2: return sox_##type##_sw_samples; \ + case SOX_ENCODING_UNSIGNED: return sox_##type##_uw_samples; \ + default: break; } \ + break; \ + case 24: \ + switch (ft->encoding.encoding) { \ + case SOX_ENCODING_SIGN2: return sox_##type##_s3_samples; \ + case SOX_ENCODING_UNSIGNED: return sox_##type##_u3_samples; \ + default: break; } \ + break; \ + case 32: \ + switch (ft->encoding.encoding) { \ + case SOX_ENCODING_SIGN2: return sox_##type##_sdw_samples; \ + case SOX_ENCODING_UNSIGNED: return sox_##type##_udw_samples; \ + case SOX_ENCODING_FLOAT: return sox_##type##_suf_samples; \ + default: break; } \ + break; \ + case 64: \ + switch (ft->encoding.encoding) { \ + case SOX_ENCODING_FLOAT: return sox_##type##_sudf_samples; \ + default: break; } \ + break; \ + default: \ + lsx_fail_errno(ft, SOX_EFMT, "this handler does not support this data size"); \ + return NULL; } \ + lsx_fail_errno(ft, SOX_EFMT, "this encoding is not supported for this data size"); \ + return NULL; } + +typedef size_t(ft_read_fn) + (sox_format_t * ft, sox_sample_t * buf, size_t len); + +GET_FORMAT(read) + +/* Read a stream of some type into SoX's internal buffer format. */ +size_t lsx_rawread(sox_format_t * ft, sox_sample_t * buf, size_t nsamp) +{ + ft_read_fn * read_buf = read_fn(ft); + + if (read_buf && nsamp) + return read_buf(ft, buf, nsamp); + return 0; +} + +typedef size_t(ft_write_fn) + (sox_format_t * ft, sox_sample_t const * buf, size_t len); + +GET_FORMAT(write) + +/* Writes SoX's internal buffer format to buffer of various data types. */ +size_t lsx_rawwrite( + sox_format_t * ft, sox_sample_t const * buf, size_t nsamp) +{ + ft_write_fn * write_buf = write_fn(ft); + + if (write_buf && nsamp) + return write_buf(ft, buf, nsamp); + return 0; +} diff --git a/app/src/main/cpp/sox/raw.h b/app/src/main/cpp/sox/raw.h new file mode 100644 index 0000000..6a5c4a5 --- /dev/null +++ b/app/src/main/cpp/sox/raw.h @@ -0,0 +1,54 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define RAW_FORMAT0(id, size, flags, encoding) \ +static int id ## _start(sox_format_t * ft) { \ + return lsx_rawstart(ft, sox_true, sox_true, sox_true, SOX_ENCODING_ ## encoding, size); \ +} \ +const sox_format_handler_t *lsx_ ## id ## _format_fn(void); \ +const sox_format_handler_t *lsx_ ## id ## _format_fn(void) { \ + static unsigned const write_encodings[] = { \ + SOX_ENCODING_ ## encoding, size, 0, 0}; \ + static sox_format_handler_t handler = { \ + SOX_LIB_VERSION_CODE, "Raw audio", \ + names, flags, \ + id ## _start, lsx_rawread , NULL, \ + id ## _start, lsx_rawwrite, NULL, \ + NULL, write_encodings, NULL, 0 \ + }; \ + return &handler; \ +} + +#define RAW_FORMAT(id, size, flags, encoding) \ + static char const *names[] = {#id, NULL}; \ + RAW_FORMAT0(id, size, flags, encoding) + +#define RAW_FORMAT1(id, alt, size, flags, encoding) \ + static char const *names[] = {#id, alt, NULL}; \ + RAW_FORMAT0(id, size, flags, encoding) + +#define RAW_FORMAT2(id, alt1, alt2, size, flags, encoding) \ + static char const *names[] = {#id, alt1, alt2, NULL}; \ + RAW_FORMAT0(id, size, flags, encoding) + +#define RAW_FORMAT3(id, alt1, alt2, alt3, size, flags, encoding) \ + static char const *names[] = {#id, alt1, alt2, alt3, NULL}; \ + RAW_FORMAT0(id, size, flags, encoding) + +#define RAW_FORMAT4(id, alt1, alt2, alt3, alt4, size, flags, encoding) \ + static char const *names[] = {#id, alt1, alt2, alt3, alt4, NULL}; \ + RAW_FORMAT0(id, size, flags, encoding) diff --git a/app/src/main/cpp/sox/remix.c b/app/src/main/cpp/sox/remix.c new file mode 100644 index 0000000..ffef0e8 --- /dev/null +++ b/app/src/main/cpp/sox/remix.c @@ -0,0 +1,284 @@ +/* libSoX effect: remix Copyright (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +typedef struct { + enum {semi, automatic, manual} mode; + sox_bool mix_power; + unsigned num_out_channels, min_in_channels; + struct { + char * str; /* Command-line argument to parse for this out_spec */ + unsigned num_in_channels; + struct in_spec { + unsigned channel_num; + double multiplier; + } * in_specs; + } * out_specs; +} priv_t; + +#define PARSE(SEP, SCAN, VAR, MIN, SEPARATORS) do {\ + end = strpbrk(text, SEPARATORS); \ + if (end == text) \ + SEP = *text++; \ + else { \ + SEP = (SEPARATORS)[strlen(SEPARATORS) - 1]; \ + n = sscanf(text, SCAN"%c", &VAR, &SEP); \ + if (n == 0 || VAR < MIN || (n == 2 && !strchr(SEPARATORS, SEP))) \ + return lsx_usage(effp); \ + text = end? end + 1 : text + strlen(text); \ + } \ +} while (0) + +static int parse(sox_effect_t * effp, char * * argv, unsigned channels) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i, j; + double mult; + + p->min_in_channels = 0; + for (i = 0; i < p->num_out_channels; ++i) { + sox_bool mul_spec = sox_false; + char * text, * end; + if (argv) /* 1st parse only */ + p->out_specs[i].str = lsx_strdup(argv[i]); + for (j = 0, text = p->out_specs[i].str; *text;) { + static char const separators[] = "-vpi,"; + char sep1, sep2; + int chan1 = 1, chan2 = channels, n; + double multiplier = HUGE_VAL; + + PARSE(sep1, "%i", chan1, 0, separators); + if (!chan1) { + if (j || *text) + return lsx_usage(effp); + continue; + } + if (sep1 == '-') + PARSE(sep1, "%i", chan2, 0, separators + 1); + else chan2 = chan1; + if (sep1 != ',') { + multiplier = sep1 == 'v' ? 1 : 0; + PARSE(sep2, "%lf", multiplier, -HUGE_VAL, separators + 4); + if (sep1 != 'v') + multiplier = (sep1 == 'p'? 1 : -1) * dB_to_linear(multiplier); + mul_spec = sox_true; + } + if (chan2 < chan1) {int t = chan1; chan1 = chan2; chan2 = t;} + p->out_specs[i].in_specs = lsx_realloc(p->out_specs[i].in_specs, + (j + chan2 - chan1 + 1) * sizeof(*p->out_specs[i].in_specs)); + while (chan1 <= chan2) { + p->out_specs[i].in_specs[j].channel_num = chan1++ - 1; + p->out_specs[i].in_specs[j++].multiplier = multiplier; + } + p->min_in_channels = max(p->min_in_channels, (unsigned)chan2); + } + p->out_specs[i].num_in_channels = j; + mult = 1. / (p->mix_power? sqrt((double)j) : j); + for (j = 0; j < p->out_specs[i].num_in_channels; ++j) + if (p->out_specs[i].in_specs[j].multiplier == HUGE_VAL) + p->out_specs[i].in_specs[j].multiplier = (p->mode == automatic || (p->mode == semi && !mul_spec)) ? mult : 1; + } + effp->out_signal.channels = p->num_out_channels; + return SOX_SUCCESS; +} + +static int show(priv_t *p) +{ + unsigned i, j; + + for (j = 0; j < p->num_out_channels; j++) { + lsx_debug("%i: ", j); + for (i = 0; i < p->out_specs[j].num_in_channels; i++) + lsx_debug("\t%i %g", p->out_specs[j].in_specs[i].channel_num, p->out_specs[j].in_specs[i].multiplier); + } + return SOX_SUCCESS; +} + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + --argc, ++argv; + if (argc && !strcmp(*argv, "-m")) p->mode = manual , ++argv, --argc; + if (argc && !strcmp(*argv, "-a")) p->mode = automatic, ++argv, --argc; + if (argc && !strcmp(*argv, "-p")) p->mix_power = sox_true, ++argv, --argc; + if (!argc) { + lsx_fail("must specify at least one output channel"); + return SOX_EOF; + } + p->num_out_channels = argc; + p->out_specs = lsx_calloc(p->num_out_channels, sizeof(*p->out_specs)); + return parse(effp, argv, 1); /* No channels yet; parse with dummy */ +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + double max_sum = 0; + unsigned i, j; + int non_integer = 0; + + parse(effp, NULL, effp->in_signal.channels); + if (effp->in_signal.channels < p->min_in_channels) { + lsx_fail("too few input channels"); + return SOX_EOF; + } + + for (j = 0; j < effp->out_signal.channels; j++) { + double sum = 0; + for (i = 0; i < p->out_specs[j].num_in_channels; i++) { + double mult = p->out_specs[j].in_specs[i].multiplier; + sum += fabs(mult); + non_integer += floor(mult) != mult; + } + max_sum = max(max_sum, sum); + } + if (effp->in_signal.mult && max_sum > 1) + *effp->in_signal.mult /= max_sum; + if (!non_integer) + effp->out_signal.precision = effp->in_signal.precision; + else + effp->out_signal.precision = SOX_SAMPLE_PRECISION; + show(p); + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i, j, len; + len = min(*isamp / effp->in_signal.channels, *osamp / effp->out_signal.channels); + *isamp = len * effp->in_signal.channels; + *osamp = len * effp->out_signal.channels; + + for (; len--; ibuf += effp->in_signal.channels) for (j = 0; j < effp->out_signal.channels; j++) { + double out = 0; + for (i = 0; i < p->out_specs[j].num_in_channels; i++) + out += ibuf[p->out_specs[j].in_specs[i].channel_num] * p->out_specs[j].in_specs[i].multiplier; + *obuf++ = SOX_ROUND_CLIP_COUNT(out, effp->clips); + } + return SOX_SUCCESS; +} + +static int closedown(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + for (i = 0; i < p->num_out_channels; ++i) { + free(p->out_specs[i].str); + free(p->out_specs[i].in_specs); + } + free(p->out_specs); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_remix_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "remix", "[-m|-a] [-p] <0|in-chan[v|p|i volume]{,in-chan[v|p|i volume]}>", + SOX_EFF_MCHAN | SOX_EFF_CHAN | SOX_EFF_GAIN | SOX_EFF_PREC, + create, start, flow, NULL, NULL, closedown, sizeof(priv_t) + }; + return &handler; +} + +/*----------------------- The `channels' effect alias ------------------------*/ + +static int channels_create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + char dummy; /* To check for extraneous chars. */ + + if (argc == 2) { + if (sscanf(argv[1], "%d %c", (int *)&p->num_out_channels, + &dummy) != 1 || (int)p->num_out_channels <= 0) + return lsx_usage(effp); + effp->out_signal.channels = p->num_out_channels; + } + else if (argc != 1) + return lsx_usage(effp); + return SOX_SUCCESS; +} + +static int channels_start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned num_out_channels = p->num_out_channels != 0 ? + p->num_out_channels : effp->out_signal.channels; + unsigned i, j; + + p->out_specs = lsx_calloc(num_out_channels, sizeof(*p->out_specs)); + if (effp->in_signal.channels == num_out_channels) + return SOX_EFF_NULL; + + if (effp->in_signal.channels > num_out_channels) { + for (j = 0; j < num_out_channels; j++) { + unsigned in_per_out = (effp->in_signal.channels + + num_out_channels - 1 - j) / num_out_channels; + lsx_valloc(p->out_specs[j].in_specs, in_per_out); + p->out_specs[j].num_in_channels = in_per_out; + for (i = 0; i < in_per_out; ++i) { + p->out_specs[j].in_specs[i].channel_num = i * num_out_channels + j; + p->out_specs[j].in_specs[i].multiplier = 1. / in_per_out; + } + } + } + else for (j = 0; j < num_out_channels; j++) { + lsx_valloc(p->out_specs[j].in_specs, 1); + p->out_specs[j].num_in_channels = 1; + p->out_specs[j].in_specs[0].channel_num = j % effp->in_signal.channels; + p->out_specs[j].in_specs[0].multiplier = 1; + } + effp->out_signal.channels = p->num_out_channels = num_out_channels; + effp->out_signal.precision = (effp->in_signal.channels > num_out_channels) ? + SOX_SAMPLE_PRECISION : effp->in_signal.precision; + show(p); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_channels_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_remix_effect_fn(); + handler.name = "channels"; + handler.usage = "number"; + handler.flags &= ~SOX_EFF_GAIN; + handler.getopts = channels_create; + handler.start = channels_start; + return &handler; +} + +/*------------------------- The `oops' effect alias --------------------------*/ + +static int oops_getopts(sox_effect_t *effp, int argc, char **argv) +{ + char *args[] = {0, "1,2i", "1,2i"}; + args[0] = argv[0]; + return --argc? lsx_usage(effp) : create(effp, 3, args); +} + +sox_effect_handler_t const * lsx_oops_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_remix_effect_fn(); + handler.name = "oops"; + handler.usage = NULL; + handler.getopts = oops_getopts; + return &handler; +} diff --git a/app/src/main/cpp/sox/repeat.c b/app/src/main/cpp/sox/repeat.c new file mode 100644 index 0000000..76c77b3 --- /dev/null +++ b/app/src/main/cpp/sox/repeat.c @@ -0,0 +1,114 @@ +/* libSoX repeat effect Copyright (c) 2004 Jan Paul Schmidt + * Re-write (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct { + unsigned num_repeats, remaining_repeats; + uint64_t num_samples, remaining_samples; + FILE * tmp_file; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + p->num_repeats = 1; + --argc, ++argv; + if (argc == 1 && !strcmp(*argv, "-")) { + p->num_repeats = UINT_MAX; + return SOX_SUCCESS; + } + do {NUMERIC_PARAMETER(num_repeats, 0, UINT_MAX - 1)} while (0); + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + if (!p->num_repeats) + return SOX_EFF_NULL; + + if (!(p->tmp_file = lsx_tmpfile())) { + lsx_fail("can't create temporary file: %s", strerror(errno)); + return SOX_EOF; + } + p->num_samples = p->remaining_samples = 0; + p->remaining_repeats = p->num_repeats; + if (effp->in_signal.length != SOX_UNKNOWN_LEN && p->num_repeats != UINT_MAX) + effp->out_signal.length = effp->in_signal.length * (p->num_repeats + 1); + else + effp->out_signal.length = SOX_UNKNOWN_LEN; + + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len = min(*isamp, *osamp); + memcpy(obuf, ibuf, len * sizeof(*obuf)); + if (fwrite(ibuf, sizeof(*ibuf), len, p->tmp_file) != len) { + lsx_fail("error writing temporary file: %s", strerror(errno)); + return SOX_EOF; + } + p->num_samples += len; + *isamp = *osamp = len; + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t odone = 0, n; + + *osamp -= *osamp % effp->in_signal.channels; + + while ((p->remaining_samples || p->remaining_repeats) && odone < *osamp) { + if (!p->remaining_samples) { + p->remaining_samples = p->num_samples; + if (p->remaining_repeats != UINT_MAX) + --p->remaining_repeats; + rewind(p->tmp_file); + } + n = min(p->remaining_samples, *osamp - odone); + if ((fread(obuf + odone, sizeof(*obuf), n, p->tmp_file)) != n) { + lsx_fail("error reading temporary file: %s", strerror(errno)); + return SOX_EOF; + } + p->remaining_samples -= n; + odone += n; + } + *osamp = odone; + return p->remaining_samples || p->remaining_repeats? SOX_SUCCESS : SOX_EOF; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */ + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_repeat_effect_fn(void) +{ + static sox_effect_handler_t effect = {"repeat", "[count (1)]", + SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY, + create, start, flow, drain, stop, NULL, sizeof(priv_t)}; + return &effect; +} diff --git a/app/src/main/cpp/sox/reverb.c b/app/src/main/cpp/sox/reverb.c new file mode 100644 index 0000000..c34995a --- /dev/null +++ b/app/src/main/cpp/sox/reverb.c @@ -0,0 +1,277 @@ +/* libSoX effect: stereo reverberation + * Copyright (c) 2007 robs@users.sourceforge.net + * Filter design based on freeverb by Jezar at Dreampoint. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "fifo.h" + +#define lsx_zalloc(var, n) var = lsx_calloc(n, sizeof(*var)) +#define filter_advance(p) if (--(p)->ptr < (p)->buffer) (p)->ptr += (p)->size +#define filter_delete(p) free((p)->buffer) + +typedef struct { + size_t size; + float * buffer, * ptr; + float store; +} filter_t; + +static float comb_process(filter_t * p, /* gcc -O2 will inline this */ + float const * input, float const * feedback, float const * hf_damping) +{ + float output = *p->ptr; + p->store = output + (p->store - output) * *hf_damping; + *p->ptr = *input + p->store * *feedback; + filter_advance(p); + return output; +} + +static float allpass_process(filter_t * p, /* gcc -O2 will inline this */ + float const * input) +{ + float output = *p->ptr; + *p->ptr = *input + output * .5; + filter_advance(p); + return output - *input; +} + +static const size_t /* Filter delay lengths in samples (44100Hz sample-rate) */ + comb_lengths[] = {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617}, + allpass_lengths[] = {225, 341, 441, 556}; +#define stereo_adjust 12 + +typedef struct { + filter_t comb [array_length(comb_lengths)]; + filter_t allpass[array_length(allpass_lengths)]; +} filter_array_t; + +static void filter_array_create(filter_array_t * p, double rate, + double scale, double offset) +{ + size_t i; + double r = rate * (1 / 44100.); /* Compensate for actual sample-rate */ + + for (i = 0; i < array_length(comb_lengths); ++i, offset = -offset) + { + filter_t * pcomb = &p->comb[i]; + pcomb->size = (size_t)(scale * r * (comb_lengths[i] + stereo_adjust * offset) + .5); + pcomb->ptr = lsx_zalloc(pcomb->buffer, pcomb->size); + } + for (i = 0; i < array_length(allpass_lengths); ++i, offset = -offset) + { + filter_t * pallpass = &p->allpass[i]; + pallpass->size = (size_t)(r * (allpass_lengths[i] + stereo_adjust * offset) + .5); + pallpass->ptr = lsx_zalloc(pallpass->buffer, pallpass->size); + } +} + +static void filter_array_process(filter_array_t * p, + size_t length, float const * input, float * output, + float const * feedback, float const * hf_damping, float const * gain) +{ + while (length--) { + float out = 0, in = *input++; + + size_t i = array_length(comb_lengths) - 1; + do out += comb_process(p->comb + i, &in, feedback, hf_damping); + while (i--); + + i = array_length(allpass_lengths) - 1; + do out = allpass_process(p->allpass + i, &out); + while (i--); + + *output++ = out * *gain; + } +} + +static void filter_array_delete(filter_array_t * p) +{ + size_t i; + + for (i = 0; i < array_length(allpass_lengths); ++i) + filter_delete(&p->allpass[i]); + for (i = 0; i < array_length(comb_lengths); ++i) + filter_delete(&p->comb[i]); +} + +typedef struct { + float feedback; + float hf_damping; + float gain; + fifo_t input_fifo; + filter_array_t chan[2]; + float * out[2]; +} reverb_t; + +static void reverb_create(reverb_t * p, double sample_rate_Hz, + double wet_gain_dB, + double room_scale, /* % */ + double reverberance, /* % */ + double hf_damping, /* % */ + double pre_delay_ms, + double stereo_depth, + size_t buffer_size, + float * * out) +{ + size_t i, delay = pre_delay_ms / 1000 * sample_rate_Hz + .5; + double scale = room_scale / 100 * .9 + .1; + double depth = stereo_depth / 100; + double a = -1 / log(1 - /**/.3 /**/); /* Set minimum feedback */ + double b = 100 / (log(1 - /**/.98/**/) * a + 1); /* Set maximum feedback */ + + memset(p, 0, sizeof(*p)); + p->feedback = 1 - exp((reverberance - b) / (a * b)); + p->hf_damping = hf_damping / 100 * .3 + .2; + p->gain = dB_to_linear(wet_gain_dB) * .015; + fifo_create(&p->input_fifo, sizeof(float)); + memset(fifo_write(&p->input_fifo, delay, 0), 0, delay * sizeof(float)); + for (i = 0; i <= ceil(depth); ++i) { + filter_array_create(p->chan + i, sample_rate_Hz, scale, i * depth); + out[i] = lsx_zalloc(p->out[i], buffer_size); + } +} + +static void reverb_process(reverb_t * p, size_t length) +{ + size_t i; + for (i = 0; i < 2 && p->out[i]; ++i) + filter_array_process(p->chan + i, length, (float *) fifo_read_ptr(&p->input_fifo), p->out[i], &p->feedback, &p->hf_damping, &p->gain); + fifo_read(&p->input_fifo, length, NULL); +} + +static void reverb_delete(reverb_t * p) +{ + size_t i; + for (i = 0; i < 2 && p->out[i]; ++i) { + free(p->out[i]); + filter_array_delete(p->chan + i); + } + fifo_delete(&p->input_fifo); +} + +/*------------------------------- SoX Wrapper --------------------------------*/ + +typedef struct { + double reverberance, hf_damping, pre_delay_ms; + double stereo_depth, wet_gain_dB, room_scale; + sox_bool wet_only; + + size_t ichannels, ochannels; + struct { + reverb_t reverb; + float * dry, * wet[2]; + } chan[2]; +} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *)effp->priv; + p->reverberance = p->hf_damping = 50; /* Set non-zero defaults */ + p->stereo_depth = p->room_scale = 100; + + --argc, ++argv; + p->wet_only = argc && (!strcmp(*argv, "-w") || !strcmp(*argv, "--wet-only")) + && (--argc, ++argv, sox_true); + do { /* break-able block */ + NUMERIC_PARAMETER(reverberance, 0, 100) + NUMERIC_PARAMETER(hf_damping, 0, 100) + NUMERIC_PARAMETER(room_scale, 0, 100) + NUMERIC_PARAMETER(stereo_depth, 0, 100) + NUMERIC_PARAMETER(pre_delay_ms, 0, 500) + NUMERIC_PARAMETER(wet_gain_dB, -10, 10) + } while (0); + + return argc ? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i; + + p->ichannels = p->ochannels = 1; + effp->out_signal.rate = effp->in_signal.rate; + if (effp->in_signal.channels > 2 && p->stereo_depth) { + lsx_warn("stereo-depth not applicable with >2 channels"); + p->stereo_depth = 0; + } + if (effp->in_signal.channels == 1 && p->stereo_depth) + effp->out_signal.channels = p->ochannels = 2; + else effp->out_signal.channels = effp->in_signal.channels; + if (effp->in_signal.channels == 2 && p->stereo_depth) + p->ichannels = p->ochannels = 2; + else effp->flows = effp->in_signal.channels; + for (i = 0; i < p->ichannels; ++i) reverb_create( + &p->chan[i].reverb, effp->in_signal.rate, p->wet_gain_dB, p->room_scale, + p->reverberance, p->hf_damping, p->pre_delay_ms, p->stereo_depth, + effp->global_info->global_info->bufsiz / p->ochannels, p->chan[i].wet); + + if (effp->in_signal.mult) + *effp->in_signal.mult /= !p->wet_only + 2 * dB_to_linear(max(0,p->wet_gain_dB)); + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t c, i, w, len = min(*isamp / p->ichannels, *osamp / p->ochannels); + SOX_SAMPLE_LOCALS; + + *isamp = len * p->ichannels, *osamp = len * p->ochannels; + for (c = 0; c < p->ichannels; ++c) + p->chan[c].dry = fifo_write(&p->chan[c].reverb.input_fifo, len, 0); + for (i = 0; i < len; ++i) for (c = 0; c < p->ichannels; ++c) + p->chan[c].dry[i] = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips); + for (c = 0; c < p->ichannels; ++c) + reverb_process(&p->chan[c].reverb, len); + if (p->ichannels == 2) for (i = 0; i < len; ++i) for (w = 0; w < 2; ++w) { + float out = (1 - p->wet_only) * p->chan[w].dry[i] + + .5 * (p->chan[0].wet[w][i] + p->chan[1].wet[w][i]); + *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(out, effp->clips); + } + else for (i = 0; i < len; ++i) for (w = 0; w < p->ochannels; ++w) { + float out = (1 - p->wet_only) * p->chan[0].dry[i] + p->chan[0].wet[w][i]; + *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(out, effp->clips); + } + return SOX_SUCCESS; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i; + for (i = 0; i < p->ichannels; ++i) + reverb_delete(&p->chan[i].reverb); + return SOX_SUCCESS; +} + +sox_effect_handler_t const *lsx_reverb_effect_fn(void) +{ + static sox_effect_handler_t handler = {"reverb", + "[-w|--wet-only]" + " [reverberance (50%)" + " [HF-damping (50%)" + " [room-scale (100%)" + " [stereo-depth (100%)" + " [pre-delay (0ms)" + " [wet-gain (0dB)" + "]]]]]]", + SOX_EFF_MCHAN, getopts, start, flow, NULL, stop, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/reverse.c b/app/src/main/cpp/sox/reverse.c new file mode 100644 index 0000000..869de84 --- /dev/null +++ b/app/src/main/cpp/sox/reverse.c @@ -0,0 +1,86 @@ +/* June 1, 1992 + * Copyright 1992 Guido van Rossum And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Guido van Rossum And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +/* + * "reverse" effect, uses a temporary file created by lsx_tmpfile(). + */ + +#include "sox_i.h" +#include + +typedef struct { + off_t pos; + FILE * tmp_file; +} priv_t; + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + p->pos = 0; + p->tmp_file = lsx_tmpfile(); + if (p->tmp_file == NULL) { + lsx_fail("can't create temporary file: %s", strerror(errno)); + return SOX_EOF; + } + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + if (fwrite(ibuf, sizeof(*ibuf), *isamp, p->tmp_file) != *isamp) { + lsx_fail("error writing temporary file: %s", strerror(errno)); + return SOX_EOF; + } + (void)obuf, *osamp = 0; /* samples not output until drain */ + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * p = (priv_t *)effp->priv; + int i, j; + + if (p->pos == 0) { + fflush(p->tmp_file); + p->pos = ftello(p->tmp_file); + if (p->pos % sizeof(sox_sample_t) != 0) { + lsx_fail("temporary file has incorrect size"); + return SOX_EOF; + } + p->pos /= sizeof(sox_sample_t); + } + p->pos -= *osamp = min((off_t)*osamp, p->pos); + fseeko(p->tmp_file, (off_t)(p->pos * sizeof(sox_sample_t)), SEEK_SET); + if (fread(obuf, sizeof(sox_sample_t), *osamp, p->tmp_file) != *osamp) { + lsx_fail("error reading temporary file: %s", strerror(errno)); + return SOX_EOF; + } + for (i = 0, j = *osamp - 1; i < j; ++i, --j) { /* reverse the samples */ + sox_sample_t temp = obuf[i]; + obuf[i] = obuf[j]; + obuf[j] = temp; + } + return p->pos? SOX_SUCCESS : SOX_EOF; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + fclose(p->tmp_file); /* auto-deleted by lsx_tmpfile */ + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_reverse_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "reverse", NULL, SOX_EFF_MODIFY, NULL, start, flow, drain, stop, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/s1-fmt.c b/app/src/main/cpp/sox/s1-fmt.c new file mode 100644 index 0000000..a7a3fec --- /dev/null +++ b/app/src/main/cpp/sox/s1-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT2(s1, "s8", "sb", 8, 0, SIGN2) diff --git a/app/src/main/cpp/sox/s2-fmt.c b/app/src/main/cpp/sox/s2-fmt.c new file mode 100644 index 0000000..77e11ce --- /dev/null +++ b/app/src/main/cpp/sox/s2-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT2(s2, "s16", "sw", 16, 0, SIGN2) diff --git a/app/src/main/cpp/sox/s3-fmt.c b/app/src/main/cpp/sox/s3-fmt.c new file mode 100644 index 0000000..9782592 --- /dev/null +++ b/app/src/main/cpp/sox/s3-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT1(s3, "s24", 24, 0, SIGN2) diff --git a/app/src/main/cpp/sox/s4-fmt.c b/app/src/main/cpp/sox/s4-fmt.c new file mode 100644 index 0000000..e288804 --- /dev/null +++ b/app/src/main/cpp/sox/s4-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT2(s4, "s32", "sl", 32, 0, SIGN2) diff --git a/app/src/main/cpp/sox/sd2.c b/app/src/main/cpp/sox/sd2.c new file mode 100644 index 0000000..fef712c --- /dev/null +++ b/app/src/main/cpp/sox/sd2.c @@ -0,0 +1,30 @@ +/* libSoX file format: SD2 Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(sd2) +{ + static char const * const names[] = {"sd2", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 24, 16, 8,0,0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = "Sound Designer II"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/sf.c b/app/src/main/cpp/sox/sf.c new file mode 100644 index 0000000..f4fec45 --- /dev/null +++ b/app/src/main/cpp/sox/sf.c @@ -0,0 +1,154 @@ +/* libSoX file format: IRCAM SoundFile (c) 2008 robs@users.sourceforge.net + * + * See http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/IRCAM/IRCAM.html + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +/* Magic numbers used in IRCAM audio files */ +static struct {char str[4]; sox_bool reverse_bytes; char const * desc;} id[] = { + {"\144\243\001\0", MACHINE_IS_BIGENDIAN , "little-endian VAX (native)"}, + {"\0\001\243\144", MACHINE_IS_LITTLEENDIAN, "big-endian VAX"}, + {"\144\243\002\0", MACHINE_IS_LITTLEENDIAN, "big-endian Sun (native)"}, + {"\0\002\243\144", MACHINE_IS_BIGENDIAN , "little-endian Sun"}, + {"\144\243\003\0", MACHINE_IS_BIGENDIAN , "little-endian MIPS (DEC)"}, + {"\0\003\243\144", MACHINE_IS_LITTLEENDIAN, "big-endian MIPS (SGI)"}, + {"\144\243\004\0", MACHINE_IS_LITTLEENDIAN, "big-endian NeXT"}, + {" ", 0, NULL} +}; +#define FIXED_HDR 1024 +#define SF_COMMENT 2 /* code for "comment line" */ + +typedef enum {Unspecified, + Linear_8 = 0x00001, Alaw_8 = 0x10001, Mulaw_8 = 0x20001, Linear_16 = 0x00002, + Linear_24 = 0x00003, Linear_32 = 0x40004, Float = 0x00004, Double = 0x00008 +} ft_encoding_t; + +static ft_encoding_t ft_enc(unsigned size, sox_encoding_t encoding) +{ + if (encoding == SOX_ENCODING_ULAW && size == 8) return Mulaw_8; + if (encoding == SOX_ENCODING_ALAW && size == 8) return Alaw_8; + if (encoding == SOX_ENCODING_SIGN2 && size == 8) return Linear_8; + if (encoding == SOX_ENCODING_SIGN2 && size == 16) return Linear_16; + if (encoding == SOX_ENCODING_SIGN2 && size == 24) return Linear_24; + if (encoding == SOX_ENCODING_SIGN2 && size == 32) return Linear_32; + if (encoding == SOX_ENCODING_FLOAT && size == 32) return Float; + if (encoding == SOX_ENCODING_FLOAT && size == 64) return Double; + return Unspecified; +} + +static sox_encoding_t sox_enc(uint32_t ft_encoding, unsigned * size) +{ + switch (ft_encoding) { + case Mulaw_8 : *size = 8; return SOX_ENCODING_ULAW; + case Alaw_8 : *size = 8; return SOX_ENCODING_ALAW; + case Linear_8 : *size = 8; return SOX_ENCODING_SIGN2; + case Linear_16 : *size = 16; return SOX_ENCODING_SIGN2; + case Linear_24 : *size = 24; return SOX_ENCODING_SIGN2; + case Linear_32 : *size = 32; return SOX_ENCODING_SIGN2; + case Float : *size = 32; return SOX_ENCODING_FLOAT; + case Double : *size = 64; return SOX_ENCODING_FLOAT; + default: return SOX_ENCODING_UNKNOWN; + } +} + +static int startread(sox_format_t * ft) +{ + char magic[4]; + float rate; + uint32_t channels, ft_encoding; + unsigned i, bits_per_sample; + sox_encoding_t encoding; + uint16_t code, size; + + if (lsx_readchars(ft, magic, sizeof(magic))) + return SOX_EOF; + + for (i = 0; id[i].desc && memcmp(magic, id[i].str, sizeof(magic)); ++i); + if (!id[i].desc) { + lsx_fail_errno(ft, SOX_EHDR, "sf: can't find IRCAM identifier"); + return SOX_EOF; + } + lsx_report("found %s identifier", id[i].desc); + ft->encoding.reverse_bytes = id[i].reverse_bytes; + + if (lsx_readf(ft, &rate) || lsx_readdw(ft, &channels) || lsx_readdw(ft, &ft_encoding)) + return SOX_EOF; + + if (!(encoding = sox_enc(ft_encoding, &bits_per_sample))) { + lsx_fail_errno(ft, SOX_EFMT, "sf: unsupported encoding %#x)", ft_encoding); + return SOX_EOF; + } + do { + if (lsx_readw(ft, &code) || lsx_readw(ft, &size)) + return SOX_EOF; + if (code == SF_COMMENT) { + char * buf = lsx_calloc(1, (size_t)size + 1); /* +1 ensures null-terminated */ + if (lsx_readchars(ft, buf, (size_t) size) != SOX_SUCCESS) { + free(buf); + return SOX_EOF; + } + sox_append_comments(&ft->oob.comments, buf); + free(buf); + } + else if (lsx_skipbytes(ft, (size_t) size)) + return SOX_EOF; + } while (code); + if (lsx_skipbytes(ft, FIXED_HDR - (size_t)lsx_tell(ft))) + return SOX_EOF; + + return lsx_check_read_params(ft, channels, rate, encoding, bits_per_sample, (uint64_t)0, sox_true); +} + +static int write_header(sox_format_t * ft) +{ + char * comment = lsx_cat_comments(ft->oob.comments); + size_t len = min(FIXED_HDR - 26, strlen(comment)) + 1; /* null-terminated */ + size_t info_len = max(4, (len + 3) & ~3u); /* Minimum & multiple of 4 bytes */ + int i = ft->encoding.reverse_bytes == MACHINE_IS_BIGENDIAN? 0 : 2; + sox_bool error = sox_false + ||lsx_writechars(ft, id[i].str, sizeof(id[i].str)) + ||lsx_writef(ft, ft->signal.rate) + ||lsx_writedw(ft, ft->signal.channels) + ||lsx_writedw(ft, ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding)) + ||lsx_writew(ft, SF_COMMENT) + ||lsx_writew(ft, (unsigned) info_len) + ||lsx_writechars(ft, comment, len) + ||lsx_padbytes(ft, FIXED_HDR - 20 - len); + free(comment); + return error? SOX_EOF: SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(sf) +{ + static char const * const names[] = {"sf", "ircam", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Institut de Recherche et Coordination Acoustique/Musique", + names, SOX_FILE_LIT_END, + startread, lsx_rawread, NULL, + write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/silence.c b/app/src/main/cpp/sox/silence.c new file mode 100644 index 0000000..1db3aec --- /dev/null +++ b/app/src/main/cpp/sox/silence.c @@ -0,0 +1,690 @@ +/* Silence effect for SoX + * by Heikki Leinonen (heilei@iki.fi) 25.03.2001 + * Major Modifications by Chris Bagwell 06.08.2001 + * Minor addition by Donnie Smith 13.08.2003 + * + * This effect can delete samples from the start of a sound file + * until it sees a specified count of samples exceed a given threshold + * (any of the channels). + * This effect can also delete samples from the end of a sound file + * when it sees a specified count of samples below a given threshold + * (all channels). + * It may also be used to delete samples anywhere in a sound file. + * Thesholds can be given as either a percentage or in decibels. + */ + +#include "sox_i.h" + +#include + +/* Private data for silence effect. */ + +#define SILENCE_TRIM 0 +#define SILENCE_TRIM_FLUSH 1 +#define SILENCE_COPY 2 +#define SILENCE_COPY_FLUSH 3 +#define SILENCE_STOP 4 + +typedef struct { + char start; + int start_periods; + char *start_duration_str; + size_t start_duration; + double start_threshold; + char start_unit; /* "d" for decibels or "%" for percent. */ + int restart; + + sox_sample_t *start_holdoff; + size_t start_holdoff_offset; + size_t start_holdoff_end; + int start_found_periods; + + char stop; + int stop_periods; + char *stop_duration_str; + size_t stop_duration; + double stop_threshold; + char stop_unit; + + sox_sample_t *stop_holdoff; + size_t stop_holdoff_offset; + size_t stop_holdoff_end; + int stop_found_periods; + + double *window; + double *window_current; + double *window_end; + size_t window_size; + double rms_sum; + + char leave_silence; + + /* State Machine */ + char mode; +} priv_t; + +static void clear_rms(sox_effect_t * effp) + +{ + priv_t * silence = (priv_t *) effp->priv; + + memset(silence->window, 0, + silence->window_size * sizeof(double)); + + silence->window_current = silence->window; + silence->window_end = silence->window + silence->window_size; + silence->rms_sum = 0; +} + +static int sox_silence_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * silence = (priv_t *) effp->priv; + int parse_count; + uint64_t temp; + const char *n; + --argc, ++argv; + + /* check for option switches */ + silence->leave_silence = sox_false; + if (argc > 0) + { + if (!strcmp("-l", *argv)) { + argc--; argv++; + silence->leave_silence = sox_true; + } + } + + if (argc < 1) + return lsx_usage(effp); + + /* Parse data related to trimming front side */ + silence->start = sox_false; + if (sscanf(argv[0], "%d", &silence->start_periods) != 1) + return lsx_usage(effp); + if (silence->start_periods < 0) + { + lsx_fail("Periods must not be negative"); + return(SOX_EOF); + } + argv++; + argc--; + + if (silence->start_periods > 0) + { + silence->start = sox_true; + if (argc < 2) + return lsx_usage(effp); + + /* We do not know the sample rate so we can not fully + * parse the duration info yet. So save argument off + * for future processing. + */ + silence->start_duration_str = lsx_strdup(argv[0]); + /* Perform a fake parse to do error checking */ + n = lsx_parsesamples(0.,silence->start_duration_str,&temp,'s'); + if (!n || *n) + return lsx_usage(effp); + silence->start_duration = temp; + + parse_count = sscanf(argv[1], "%lf%c", &silence->start_threshold, + &silence->start_unit); + if (parse_count < 1) + return lsx_usage(effp); + else if (parse_count < 2) + silence->start_unit = '%'; + + argv++; argv++; + argc--; argc--; + } + + silence->stop = sox_false; + /* Parse data needed for trimming of backside */ + if (argc > 0) + { + if (argc < 3) + return lsx_usage(effp); + if (sscanf(argv[0], "%d", &silence->stop_periods) != 1) + return lsx_usage(effp); + if (silence->stop_periods < 0) + { + silence->stop_periods = -silence->stop_periods; + silence->restart = 1; + } + else + silence->restart = 0; + silence->stop = sox_true; + argv++; + argc--; + + /* We do not know the sample rate so we can not fully + * parse the duration info yet. So save argument off + * for future processing. + */ + silence->stop_duration_str = lsx_strdup(argv[0]); + /* Perform a fake parse to do error checking */ + n = lsx_parsesamples(0.,silence->stop_duration_str,&temp,'s'); + if (!n || *n) + return lsx_usage(effp); + silence->stop_duration = temp; + + parse_count = sscanf(argv[1], "%lf%c", &silence->stop_threshold, + &silence->stop_unit); + if (parse_count < 1) + return lsx_usage(effp); + else if (parse_count < 2) + silence->stop_unit = '%'; + + argv++; argv++; + argc--; argc--; + } + + /* Error checking */ + if (silence->start) + { + if ((silence->start_unit != '%') && (silence->start_unit != 'd')) + { + lsx_fail("Invalid unit specified"); + return lsx_usage(effp); + } + if ((silence->start_unit == '%') && ((silence->start_threshold < 0.0) + || (silence->start_threshold > 100.0))) + { + lsx_fail("silence threshold should be between 0.0 and 100.0 %%"); + return (SOX_EOF); + } + if ((silence->start_unit == 'd') && (silence->start_threshold >= 0.0)) + { + lsx_fail("silence threshold should be less than 0.0 dB"); + return(SOX_EOF); + } + } + + if (silence->stop) + { + if ((silence->stop_unit != '%') && (silence->stop_unit != 'd')) + { + lsx_fail("Invalid unit specified"); + return(SOX_EOF); + } + if ((silence->stop_unit == '%') && ((silence->stop_threshold < 0.0) || + (silence->stop_threshold > 100.0))) + { + lsx_fail("silence threshold should be between 0.0 and 100.0 %%"); + return (SOX_EOF); + } + if ((silence->stop_unit == 'd') && (silence->stop_threshold >= 0.0)) + { + lsx_fail("silence threshold should be less than 0.0 dB"); + return(SOX_EOF); + } + } + return(SOX_SUCCESS); +} + +static int sox_silence_start(sox_effect_t * effp) +{ + priv_t *silence = (priv_t *)effp->priv; + uint64_t temp; + + /* When you want to remove silence, small window sizes are + * better or else RMS will look like non-silence at + * aburpt changes from load to silence. + */ + silence->window_size = (effp->in_signal.rate / 50) * + effp->in_signal.channels; + silence->window = lsx_malloc(silence->window_size * sizeof(double)); + + clear_rms(effp); + + /* Now that we know sample rate, reparse duration. */ + if (silence->start) + { + if (lsx_parsesamples(effp->in_signal.rate, silence->start_duration_str, + &temp, 's') == NULL) + return lsx_usage(effp); + silence->start_duration = temp * effp->in_signal.channels; + } + if (silence->stop) + { + if (lsx_parsesamples(effp->in_signal.rate,silence->stop_duration_str, + &temp,'s') == NULL) + return lsx_usage(effp); + silence->stop_duration = temp * effp->in_signal.channels; + } + + if (silence->start) + silence->mode = SILENCE_TRIM; + else + silence->mode = SILENCE_COPY; + + silence->start_holdoff = lsx_malloc(sizeof(sox_sample_t)*silence->start_duration); + silence->start_holdoff_offset = 0; + silence->start_holdoff_end = 0; + silence->start_found_periods = 0; + + silence->stop_holdoff = lsx_malloc(sizeof(sox_sample_t)*silence->stop_duration); + silence->stop_holdoff_offset = 0; + silence->stop_holdoff_end = 0; + silence->stop_found_periods = 0; + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* depends on input data */ + + return(SOX_SUCCESS); +} + +static sox_bool aboveThreshold(sox_effect_t const * effp, + sox_sample_t value /* >= 0 */, double threshold, int unit) +{ + /* When scaling low bit data, noise values got scaled way up */ + /* Only consider the original bits when looking for silence */ + sox_sample_t masked_value = value & (-1 << (32 - effp->in_signal.precision)); + + double scaled_value = (double)masked_value / SOX_SAMPLE_MAX; + + if (unit == '%') + scaled_value *= 100; + else if (unit == 'd') + scaled_value = linear_to_dB(scaled_value); + + return scaled_value > threshold; +} + +static sox_sample_t compute_rms(sox_effect_t * effp, sox_sample_t sample) +{ + priv_t * silence = (priv_t *) effp->priv; + double new_sum; + sox_sample_t rms; + + new_sum = silence->rms_sum; + new_sum -= *silence->window_current; + new_sum += ((double)sample * (double)sample); + + rms = sqrt(new_sum / silence->window_size); + + return (rms); +} + +static void update_rms(sox_effect_t * effp, sox_sample_t sample) +{ + priv_t * silence = (priv_t *) effp->priv; + + silence->rms_sum -= *silence->window_current; + *silence->window_current = ((double)sample * (double)sample); + silence->rms_sum += *silence->window_current; + + silence->window_current++; + if (silence->window_current >= silence->window_end) + silence->window_current = silence->window; +} + +/* Process signed long samples from ibuf to obuf. */ +/* Return number of samples processed in isamp and osamp. */ +static int sox_silence_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * silence = (priv_t *) effp->priv; + int threshold; + size_t i, j; + size_t nrOfTicks, /* sometimes wide, sometimes non-wide samples */ + nrOfInSamplesRead, nrOfOutSamplesWritten; /* non-wide samples */ + + nrOfInSamplesRead = 0; + nrOfOutSamplesWritten = 0; + + switch (silence->mode) + { + case SILENCE_TRIM: + /* Reads and discards all input data until it detects a + * sample that is above the specified threshold. Turns on + * copy mode when detected. + * Need to make sure and copy input in groups of "channels" to + * prevent getting buffers out of sync. + * nrOfTicks counts wide samples here. + */ +silence_trim: + nrOfTicks = min((*isamp-nrOfInSamplesRead), + (*osamp-nrOfOutSamplesWritten)) / + effp->in_signal.channels; + for(i = 0; i < nrOfTicks; i++) + { + threshold = 0; + for (j = 0; j < effp->in_signal.channels; j++) + { + threshold |= aboveThreshold(effp, + compute_rms(effp, ibuf[j]), + silence->start_threshold, + silence->start_unit); + } + + if (threshold) + { + /* Add to holdoff buffer */ + for (j = 0; j < effp->in_signal.channels; j++) + { + update_rms(effp, *ibuf); + silence->start_holdoff[ + silence->start_holdoff_end++] = *ibuf++; + nrOfInSamplesRead++; + } + + if (silence->start_holdoff_end >= + silence->start_duration) + { + if (++silence->start_found_periods >= + silence->start_periods) + { + silence->mode = SILENCE_TRIM_FLUSH; + goto silence_trim_flush; + } + /* Trash holdoff buffer since its not + * needed. Start looking again. + */ + silence->start_holdoff_offset = 0; + silence->start_holdoff_end = 0; + } + } + else /* !above Threshold */ + { + silence->start_holdoff_end = 0; + for (j = 0; j < effp->in_signal.channels; j++) + { + update_rms(effp, ibuf[j]); + } + ibuf += effp->in_signal.channels; + nrOfInSamplesRead += effp->in_signal.channels; + } + } /* for nrOfTicks */ + break; + + case SILENCE_TRIM_FLUSH: + /* nrOfTicks counts non-wide samples here. */ +silence_trim_flush: + nrOfTicks = min((silence->start_holdoff_end - + silence->start_holdoff_offset), + (*osamp-nrOfOutSamplesWritten)); + nrOfTicks -= nrOfTicks % effp->in_signal.channels; + for(i = 0; i < nrOfTicks; i++) + { + *obuf++ = silence->start_holdoff[silence->start_holdoff_offset++]; + nrOfOutSamplesWritten++; + } + + /* If fully drained holdoff then switch to copy mode */ + if (silence->start_holdoff_offset == silence->start_holdoff_end) + { + silence->start_holdoff_offset = 0; + silence->start_holdoff_end = 0; + silence->mode = SILENCE_COPY; + goto silence_copy; + } + break; + + case SILENCE_COPY: + /* Attempts to copy samples into output buffer. + * + * Case B: + * If not looking for silence to terminate copy then + * blindly copy data into output buffer. + * + * Case A: + * + * Case 1a: + * If previous silence was detect then see if input sample is + * above threshold. If found then flush out hold off buffer + * and copy over to output buffer. + * + * Case 1b: + * If no previous silence detect then see if input sample + * is above threshold. If found then copy directly + * to output buffer. + * + * Case 2: + * If not above threshold then silence is detect so + * store in hold off buffer and do not write to output + * buffer. Even though it wasn't put in output + * buffer, inform user that input was consumed. + * + * If hold off buffer is full after this then stop + * copying data and discard data in hold off buffer. + * + * Special leave_silence logic: + * + * During this mode, go ahead and copy input + * samples to output buffer instead of holdoff buffer + * Then also short ciruit any flushes that would occur + * when non-silence is detect since samples were already + * copied. This has the effect of always leaving + * holdoff[] amount of silence but deleting any + * beyond that amount. + * + * nrOfTicks counts wide samples here. + */ +silence_copy: + nrOfTicks = min((*isamp-nrOfInSamplesRead), + (*osamp-nrOfOutSamplesWritten)) / + effp->in_signal.channels; + if (silence->stop) + { + /* Case A */ + for(i = 0; i < nrOfTicks; i++) + { + threshold = 1; + for (j = 0; j < effp->in_signal.channels; j++) + { + threshold &= aboveThreshold(effp, + compute_rms(effp, ibuf[j]), + silence->stop_threshold, + silence->stop_unit); + } + + /* Case 1a + * If above threshold, check to see if we where holding + * off previously. If so then flush this buffer. + * We haven't incremented any pointers yet so nothing + * is lost. + * + * If user wants to leave_silence, then we + * were already copying the data and so no + * need to flush the old data. Just resume + * copying as if we were not holding off. + */ + if (threshold && silence->stop_holdoff_end + && !silence->leave_silence) + { + silence->mode = SILENCE_COPY_FLUSH; + goto silence_copy_flush; + } + /* Case 1b */ + else if (threshold) + { + /* Not holding off so copy into output buffer */ + for (j = 0; j < effp->in_signal.channels; j++) + { + update_rms(effp, *ibuf); + *obuf++ = *ibuf++; + nrOfInSamplesRead++; + nrOfOutSamplesWritten++; + } + } + /* Case 2 */ + else if (!threshold) + { + /* Add to holdoff buffer */ + for (j = 0; j < effp->in_signal.channels; j++) + { + update_rms(effp, *ibuf); + if (silence->leave_silence) { + *obuf++ = *ibuf; + nrOfOutSamplesWritten++; + } + silence->stop_holdoff[ + silence->stop_holdoff_end++] = *ibuf++; + nrOfInSamplesRead++; + } + + /* Check if holdoff buffer is greater than duration + */ + if (silence->stop_holdoff_end >= + silence->stop_duration) + { + /* Increment found counter and see if this + * is the last period. If so then exit. + */ + if (++silence->stop_found_periods >= + silence->stop_periods) + { + silence->stop_holdoff_offset = 0; + silence->stop_holdoff_end = 0; + if (!silence->restart) + { + *isamp = nrOfInSamplesRead; + *osamp = nrOfOutSamplesWritten; + silence->mode = SILENCE_STOP; + /* Return SOX_EOF since no more processing */ + return (SOX_EOF); + } + else + { + silence->stop_found_periods = 0; + silence->start_found_periods = 0; + silence->start_holdoff_offset = 0; + silence->start_holdoff_end = 0; + clear_rms(effp); + silence->mode = SILENCE_TRIM; + + goto silence_trim; + } + } + else + { + /* Flush this buffer and start + * looking again. + */ + silence->mode = SILENCE_COPY_FLUSH; + goto silence_copy_flush; + } + break; + } /* Filled holdoff buffer */ + } /* Detected silence */ + } /* For # of samples */ + } /* Trimming off backend */ + else /* !(silence->stop) */ + { + /* Case B */ + memcpy(obuf, ibuf, sizeof(sox_sample_t)*nrOfTicks* + effp->in_signal.channels); + nrOfInSamplesRead += (nrOfTicks*effp->in_signal.channels); + nrOfOutSamplesWritten += (nrOfTicks*effp->in_signal.channels); + } + break; + + case SILENCE_COPY_FLUSH: + /* nrOfTicks counts non-wide samples here. */ +silence_copy_flush: + nrOfTicks = min((silence->stop_holdoff_end - + silence->stop_holdoff_offset), + (*osamp-nrOfOutSamplesWritten)); + nrOfTicks -= nrOfTicks % effp->in_signal.channels; + + for(i = 0; i < nrOfTicks; i++) + { + *obuf++ = silence->stop_holdoff[silence->stop_holdoff_offset++]; + nrOfOutSamplesWritten++; + } + + /* If fully drained holdoff then return to copy mode */ + if (silence->stop_holdoff_offset == silence->stop_holdoff_end) + { + silence->stop_holdoff_offset = 0; + silence->stop_holdoff_end = 0; + silence->mode = SILENCE_COPY; + goto silence_copy; + } + break; + + case SILENCE_STOP: + /* This code can't be reached. */ + nrOfInSamplesRead = *isamp; + break; + } + + *isamp = nrOfInSamplesRead; + *osamp = nrOfOutSamplesWritten; + + return (SOX_SUCCESS); +} + +static int sox_silence_drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * silence = (priv_t *) effp->priv; + size_t i; + size_t nrOfTicks, nrOfOutSamplesWritten = 0; /* non-wide samples */ + + /* Only if in flush mode will there be possible samples to write + * out during drain() call. + */ + if (silence->mode == SILENCE_COPY_FLUSH || + silence->mode == SILENCE_COPY) + { + nrOfTicks = min((silence->stop_holdoff_end - + silence->stop_holdoff_offset), *osamp); + nrOfTicks -= nrOfTicks % effp->in_signal.channels; + for(i = 0; i < nrOfTicks; i++) + { + *obuf++ = silence->stop_holdoff[silence->stop_holdoff_offset++]; + nrOfOutSamplesWritten++; + } + + /* If fully drained holdoff then stop */ + if (silence->stop_holdoff_offset == silence->stop_holdoff_end) + { + silence->stop_holdoff_offset = 0; + silence->stop_holdoff_end = 0; + silence->mode = SILENCE_STOP; + } + } + + *osamp = nrOfOutSamplesWritten; + if (silence->mode == SILENCE_STOP || *osamp == 0) + return SOX_EOF; + else + return SOX_SUCCESS; +} + +static int sox_silence_stop(sox_effect_t * effp) +{ + priv_t * silence = (priv_t *) effp->priv; + + free(silence->window); + free(silence->start_holdoff); + free(silence->stop_holdoff); + + return(SOX_SUCCESS); +} + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * silence = (priv_t *) effp->priv; + + free(silence->start_duration_str); + free(silence->stop_duration_str); + + return SOX_SUCCESS; +} + +static sox_effect_handler_t sox_silence_effect = { + "silence", + "[ -l ] above_periods [ duration threshold[d|%] ] [ below_periods duration threshold[d|%] ]", + SOX_EFF_MCHAN | SOX_EFF_MODIFY | SOX_EFF_LENGTH, + sox_silence_getopts, + sox_silence_start, + sox_silence_flow, + sox_silence_drain, + sox_silence_stop, + lsx_kill, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_silence_effect_fn(void) +{ + return &sox_silence_effect; +} diff --git a/app/src/main/cpp/sox/sinc.c b/app/src/main/cpp/sox/sinc.c new file mode 100644 index 0000000..a4da3eb --- /dev/null +++ b/app/src/main/cpp/sox/sinc.c @@ -0,0 +1,157 @@ +/* Effect: sinc filters Copyright (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "dft_filter.h" +#include + +typedef struct { + dft_filter_priv_t base; + double att, beta, phase, Fc0, Fc1, tbw0, tbw1; + int num_taps[2]; + sox_bool round; +} priv_t; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + dft_filter_priv_t * b = &p->base; + char * parse_ptr = argv[0]; + int i = 0; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, "+ra:b:p:MILt:n:", NULL, lsx_getopt_flag_none, 1, &optstate); + + b->filter_ptr = &b->filter; + p->phase = 50; + p->beta = -1; + while (i < 2) { + int c = 1; + while (c && (c = lsx_getopt(&optstate)) != -1) switch (c) { + char * parse_ptr2; + case 'r': p->round = sox_true; break; + GETOPT_NUMERIC(optstate, 'a', att, 40 , 180) + GETOPT_NUMERIC(optstate, 'b', beta, 0 , 256) + GETOPT_NUMERIC(optstate, 'p', phase, 0, 100) + case 'M': p->phase = 0; break; + case 'I': p->phase = 25; break; + case 'L': p->phase = 50; break; + GETOPT_NUMERIC(optstate, 'n', num_taps[1], 11, 32767) + case 't': p->tbw1 = lsx_parse_frequency(optstate.arg, &parse_ptr2); + if (p->tbw1 < 1 || *parse_ptr2) return lsx_usage(effp); + break; + default: c = 0; + } + if ((p->att && p->beta >= 0) || (p->tbw1 && p->num_taps[1])) + return lsx_usage(effp); + if (!i || !p->Fc1) + p->tbw0 = p->tbw1, p->num_taps[0] = p->num_taps[1]; + if (!i++ && optstate.ind < argc) { + if (*(parse_ptr = argv[optstate.ind++]) != '-') + p->Fc0 = lsx_parse_frequency(parse_ptr, &parse_ptr); + if (*parse_ptr == '-') + p->Fc1 = lsx_parse_frequency(parse_ptr + 1, &parse_ptr); + } + } + return optstate.ind != argc || p->Fc0 < 0 || p->Fc1 < 0 || *parse_ptr ? + lsx_usage(effp) : SOX_SUCCESS; +} + +static void invert(double * h, int n) +{ + int i; + for (i = 0; i < n; ++i) + h[i] = -h[i]; + h[(n - 1) / 2] += 1; +} + +static double * lpf(double Fn, double Fc, double tbw, int * num_taps, double att, double * beta, sox_bool round) +{ + int n = *num_taps; + if ((Fc /= Fn) <= 0 || Fc >= 1) { + *num_taps = 0; + return NULL; + } + att = att? att : 120; + lsx_kaiser_params(att, Fc, (tbw? tbw / Fn : .05) * .5, beta, num_taps); + if (!n) { + n = *num_taps; + *num_taps = range_limit(n, 11, 32767); + if (round) + *num_taps = 1 + 2 * (int)((int)((*num_taps / 2) * Fc + .5) / Fc + .5); + lsx_report("num taps = %i (from %i)", *num_taps, n); + } + return lsx_make_lpf(*num_taps |= 1, Fc, *beta, 0., 1., sox_false); +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + dft_filter_t * f = p->base.filter_ptr; + + if (!f->num_taps) { + double Fn = effp->in_signal.rate * .5; + double * h[2]; + int i, n, post_peak, longer; + + if (p->Fc0 >= Fn || p->Fc1 >= Fn) { + lsx_fail("filter frequency must be less than sample-rate / 2"); + return SOX_EOF; + } + h[0] = lpf(Fn, p->Fc0, p->tbw0, &p->num_taps[0], p->att, &p->beta,p->round); + h[1] = lpf(Fn, p->Fc1, p->tbw1, &p->num_taps[1], p->att, &p->beta,p->round); + if (h[0]) + invert(h[0], p->num_taps[0]); + + longer = p->num_taps[1] > p->num_taps[0]; + n = p->num_taps[longer]; + if (h[0] && h[1]) { + for (i = 0; i < p->num_taps[!longer]; ++i) + h[longer][i + (n - p->num_taps[!longer])/2] += h[!longer][i]; + + if (p->Fc0 < p->Fc1) + invert(h[longer], n); + + free(h[!longer]); + } + if (p->phase != 50) + lsx_fir_to_phase(&h[longer], &n, &post_peak, p->phase); + else post_peak = n >> 1; + + if (effp->global_info->plot != sox_plot_off) { + char title[100]; + sprintf(title, "SoX effect: sinc filter freq=%g-%g", + p->Fc0, p->Fc1? p->Fc1 : Fn); + lsx_plot_fir(h[longer], n, effp->in_signal.rate, + effp->global_info->plot, title, -p->beta * 10 - 25, 5.); + return SOX_EOF; + } + lsx_set_dft_filter(f, h[longer], n, post_peak); + } + return lsx_dft_filter_effect_fn()->start(effp); +} + +sox_effect_handler_t const * lsx_sinc_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_dft_filter_effect_fn(); + handler.name = "sinc"; + handler.usage = "[-a att|-b beta] [-p phase|-M|-I|-L] [-t tbw|-n taps] [freqHP][-freqLP [-t tbw|-n taps]]"; + handler.getopts = create; + handler.start = start; + handler.priv_size = sizeof(priv_t); + return &handler; +} diff --git a/app/src/main/cpp/sox/skeleff.c b/app/src/main/cpp/sox/skeleff.c new file mode 100644 index 0000000..ad27df9 --- /dev/null +++ b/app/src/main/cpp/sox/skeleff.c @@ -0,0 +1,141 @@ +/* libSoX effect: Skeleton effect used as sample for creating new effects. + * + * Copyright 1999-2008 Chris Bagwell And SoX Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +/* Private data for effect */ +typedef struct { + int localdata; +} priv_t; + +/* + * Process command-line options but don't do other + * initialization now: effp->in_signal & effp->out_signal are not + * yet filled in. + */ +static int getopts(sox_effect_t * effp, int argc, char UNUSED **argv) +{ + priv_t * UNUSED p = (priv_t *)effp->priv; + + if (argc != 2) + return lsx_usage(effp); + + p->localdata = atoi(argv[1]); + + return p->localdata > 0 ? SOX_SUCCESS : SOX_EOF; +} + +/* + * Prepare processing. + * Do all initializations. + */ +static int start(sox_effect_t * effp) +{ + if (effp->out_signal.channels == 1) { + lsx_fail("Can't run on mono data."); + return SOX_EOF; + } + + return SOX_SUCCESS; +} + +/* + * Process up to *isamp samples from ibuf and produce up to *osamp samples + * in obuf. Write back the actual numbers of samples to *isamp and *osamp. + * Return SOX_SUCCESS or, if error occurs, SOX_EOF. + */ +static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * UNUSED p = (priv_t *)effp->priv; + size_t len, done; + + switch (effp->out_signal.channels) { + case 2: + /* Length to process will be buffer length / 2 since we + * work with two samples at a time. + */ + len = min(*isamp, *osamp) / 2; + for (done = 0; done < len; done++) + { + obuf[0] = ibuf[0]; + obuf[1] = ibuf[1]; + /* Advance buffer by 2 samples */ + ibuf += 2; + obuf += 2; + } + + *isamp = len * 2; + *osamp = len * 2; + + break; + } + + return SOX_SUCCESS; +} + +/* + * Drain out remaining samples if the effect generates any. + */ +static int drain(sox_effect_t UNUSED * effp, sox_sample_t UNUSED *obuf, size_t *osamp) +{ + *osamp = 0; + /* Return SOX_EOF when drain + * will not output any more samples. + * *osamp == 0 also indicates that. + */ + return SOX_EOF; +} + +/* + * Do anything required when you stop reading samples. + */ +static int stop(sox_effect_t UNUSED * effp) +{ + return SOX_SUCCESS; +} + +/* + * Do anything required when you kill an effect. + * (free allocated memory, etc.) + */ +static int lsx_kill(sox_effect_t UNUSED * effp) +{ + return SOX_SUCCESS; +} + +/* + * Function returning effect descriptor. This should be the only + * externally visible object. + */ +const sox_effect_handler_t *lsx_skel_effect_fn(void); +const sox_effect_handler_t *lsx_skel_effect_fn(void) +{ + /* + * Effect descriptor. + * If no specific processing is needed for any of + * the 6 functions, then the function above can be deleted + * and NULL used in place of the its name below. + */ + static sox_effect_handler_t sox_skel_effect = { + "skel", "[OPTION]", SOX_EFF_MCHAN, + getopts, start, flow, drain, stop, lsx_kill, sizeof(priv_t) + }; + return &sox_skel_effect; +} diff --git a/app/src/main/cpp/sox/skelform.c b/app/src/main/cpp/sox/skelform.c new file mode 100644 index 0000000..793c767 --- /dev/null +++ b/app/src/main/cpp/sox/skelform.c @@ -0,0 +1,218 @@ +/* libSoX skeleton file format handler. + * + * Copyright 1999 Chris Bagwell And Sundry Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include + +/* Private data for SKEL file */ +typedef struct { + size_t remaining_samples; +} priv_t; + +/* Note that if any of your methods doesn't need to do anything, you + can instead use the relevant sox_*_nothing* method */ + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int startread(sox_format_t * ft) +{ + priv_t * sk = (priv_t *)ft->priv; + size_t samples_in_file; + + /* If you need to seek around the input file. */ + if (!ft->seekable) { + lsx_fail_errno(ft, SOX_EOF, "skel inputfile must be a file"); + return SOX_EOF; + } + + /* + * If your format is headerless and has fixed values for + * the following items, you can hard code them here (see cdr.c). + * If your format contains a header with format information + * then you should set it here. + */ + ft->signal.rate = 44100; /* or 8000, 16000, 32000, 48000, ... */ + ft->signal.channels = 1; /* or 2 or 3 ... */ + ft->encoding.bits_per_sample = 8; /* or 16 ... */ + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; /* or SIGN2 ... */ + sox_append_comment(&ft->oob.comments, "any comment in file header."); + + /* If your format doesn't have a header then samples_in_file + * can be determined by the file size. + */ + samples_in_file = lsx_filelength(ft) / (ft->encoding.bits_per_sample >> 3); + + /* If you can detect the length of your file, record it here. */ + ft->signal.length = samples_in_file; + sk->remaining_samples = samples_in_file; + + return SOX_SUCCESS; +} + +/* + * Read up to len samples of type sox_sample_t from file into buf[]. + * Return number of samples read, or 0 if at end of file. + */ +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t * UNUSED sk = (priv_t *)ft->priv; + size_t done; + unsigned char sample; + + for (done = 0; done < len; done++) { + if (lsx_eof(ft) || lsx_readb(ft, &sample)) /* no more samples */ + break; + switch (ft->encoding.bits_per_sample) { + case 8: + switch (ft->encoding.encoding) { + case SOX_ENCODING_UNSIGNED: + *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(sample,); + break; + default: + lsx_fail("Undetected sample encoding in read!"); + return 0; + } + break; + default: + lsx_fail("Undetected bad sample size in read!"); + return 0; + } + } + + return done; +} + +/* + * Do anything required when you stop reading samples. + * Don't close input file! + */ +static int stopread(sox_format_t UNUSED * ft) +{ + return SOX_SUCCESS; +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * UNUSED sk = (priv_t *)ft->priv; + + /* If you have to seek around the output file. */ + /* If header contains a length value then seeking will be + * required. Instead of failing, it's sometimes nice to + * just set the length to max value and not fail. + */ + if (!ft->seekable) { + lsx_fail("Output .skel file must be a file, not a pipe"); + return SOX_EOF; + } + + if (ft->signal.rate != 44100) + lsx_fail("Output .skel file must have a sample rate of 44100Hz"); + + if (ft->encoding.bits_per_sample == 0) { + lsx_fail("Did not specify a size for .skel output file"); + return SOX_EOF; + } + + /* error check ft->encoding.encoding */ + /* error check ft->signal.channels */ + + /* Write file header, if any */ + /* Write comment field, if any */ + + return SOX_SUCCESS; + +} + +/* + * Write len samples of type sox_sample_t from buf[] to file. + * Return number of samples written. + */ +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * sk = (priv_t *)ft->priv; + size_t done = 0; + + (void)sk; + switch (ft->encoding.bits_per_sample) { + case 8: + switch (ft->encoding.encoding) { + SOX_SAMPLE_LOCALS; + case SOX_ENCODING_UNSIGNED: + while (done < len && lsx_writeb(ft, SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips)) == SOX_SUCCESS) + ++done; + break; + default: + lsx_fail("Undetected bad sample encoding in write!"); + return 0; + } + break; + default: + lsx_fail("Undetected bad sample size in write!"); + return 0; + } + return done; +} + +static int stopwrite(sox_format_t UNUSED * ft) +{ + /* All samples are already written out. */ + /* If file header needs fixing up, for example it needs the number + of samples in a field, seek back and write them here. */ + return SOX_SUCCESS; +} + +static int seek(sox_format_t UNUSED * ft, uint64_t UNUSED offset) +{ + /* Seek relative to current position. */ + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(skel) +{ + /* Format file suffixes */ + static const char *names[] = {"skel",NULL }; + + /* Encoding types and sizes that this handler can write */ + static const unsigned encodings[] = { + SOX_ENCODING_SIGN2, 16, 0, + SOX_ENCODING_UNSIGNED, 8, 0, + 0}; + + /* Format descriptor + * If no specific processing is needed for any of + * the 7 functions, then the function above can be deleted + * and NULL used in place of the its name below. + */ + static sox_format_handler_t handler = { + SOX_LIB_VERSION_CODE, + "My first SoX format!", + names, 0, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + seek, encodings, NULL, sizeof(priv_t) + }; + + return &handler; +} diff --git a/app/src/main/cpp/sox/smp.c b/app/src/main/cpp/sox/smp.c new file mode 100644 index 0000000..bf8ac63 --- /dev/null +++ b/app/src/main/cpp/sox/smp.c @@ -0,0 +1,418 @@ +/* libSoX SampleVision file format handler. + * Output is always in little-endian (80x86/VAX) order. + * + * Derived from: libSoX skeleton handler file. + * + * Add: Loop point verbose info. It's a start, anyway. + */ + +/* + * June 30, 1992 + * Copyright 1992 Leigh Smith And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Leigh Smith And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" +#include +#include + +#define NAMELEN 30 /* Size of Samplevision name */ +#define COMMENTLEN 60 /* Size of Samplevision comment, not shared */ +#define MIDI_UNITY 60 /* MIDI note number to play sample at unity */ +#define MARKERLEN (size_t)10 /* Size of Marker name */ + +/* The header preceeding the sample data */ +struct smpheader { + char Id[18]; /* File identifier */ + char version[4]; /* File version */ + char comments[COMMENTLEN]; /* User comments */ + char name[NAMELEN + 1]; /* Sample Name, left justified */ +}; +#define HEADERSIZE (sizeof(struct smpheader) - 1) /* -1 for name's \0 */ + +/* Samplevision loop definition structure */ +struct loop { + uint32_t start; /* Sample count into sample data, not byte count */ + uint32_t end; /* end point */ + unsigned char type; /* 0 = loop off, 1 = forward, 2 = forw/back */ + unsigned short count; /* No of times to loop */ +}; + +/* Samplevision marker definition structure */ +struct marker { + char name[MARKERLEN + 1]; /* Ascii Marker name */ + uint32_t position; /* Sample Number, not byte number */ +}; + +/* The trailer following the sample data */ +struct smptrailer { + struct loop loops[8]; /* loops */ + struct marker markers[8]; /* markers */ + int8_t MIDInote; /* for unity pitch playback */ + uint32_t rate; /* in hertz */ + uint32_t SMPTEoffset; /* in subframes - huh? */ + uint32_t CycleSize; /* sample count in one cycle of the */ + /* sampled sound -1 if unknown */ +}; + +/* Private data for SMP file */ +typedef struct { + uint64_t NoOfSamps; /* Sample data count in words */ + uint64_t dataStart; + /* comment memory resides in private data because it's small */ + char comment[COMMENTLEN + NAMELEN + 3]; +} priv_t; + +static char const *SVmagic = "SOUND SAMPLE DATA ", *SVvers = "2.1 "; + +/* + * Read the SampleVision trailer structure. + * Returns 1 if everything was read ok, 0 if there was an error. + */ +static int readtrailer(sox_format_t * ft, struct smptrailer *trailer) +{ + int i; + uint16_t trash16; + + lsx_readw(ft, &trash16); /* read reserved word */ + for(i = 0; i < 8; i++) { /* read the 8 loops */ + lsx_readdw(ft, &(trailer->loops[i].start)); + ft->oob.loops[i].start = trailer->loops[i].start; + lsx_readdw(ft, &(trailer->loops[i].end)); + ft->oob.loops[i].length = + trailer->loops[i].end - trailer->loops[i].start; + lsx_readb(ft, &(trailer->loops[i].type)); + ft->oob.loops[i].type = trailer->loops[i].type; + lsx_readw(ft, &(trailer->loops[i].count)); + ft->oob.loops[i].count = trailer->loops[i].count; + } + for(i = 0; i < 8; i++) { /* read the 8 markers */ + if (lsx_readbuf(ft, trailer->markers[i].name, MARKERLEN) != MARKERLEN) + { + lsx_fail_errno(ft,SOX_EHDR,"EOF in SMP"); + return(SOX_EOF); + } + trailer->markers[i].name[MARKERLEN] = 0; + lsx_readdw(ft, &(trailer->markers[i].position)); + } + lsx_readsb(ft, &(trailer->MIDInote)); + lsx_readdw(ft, &(trailer->rate)); + lsx_readdw(ft, &(trailer->SMPTEoffset)); + lsx_readdw(ft, &(trailer->CycleSize)); + return(SOX_SUCCESS); +} + +/* + * set the trailer data - loops and markers, to reasonably benign values + */ +static void settrailer(sox_format_t * ft, struct smptrailer *trailer, sox_rate_t rate) +{ + int i; + + for(i = 0; i < 8; i++) { /* copy the 8 loops */ + if (ft->oob.loops[i].type != 0) { + trailer->loops[i].start = ft->oob.loops[i].start > UINT_MAX + ? UINT_MAX + : ft->oob.loops[i].start; + /* to mark it as not set */ + trailer->loops[i].end = ft->oob.loops[i].start + ft->oob.loops[i].length > UINT_MAX + ? UINT_MAX + : ft->oob.loops[i].start + ft->oob.loops[i].length; + trailer->loops[i].type = ft->oob.loops[i].type; + trailer->loops[i].count = ft->oob.loops[i].count; + } else { + /* set first loop start as FFFFFFFF */ + trailer->loops[i].start = ~0u; + /* to mark it as not set */ + trailer->loops[i].end = 0; + trailer->loops[i].type = 0; + trailer->loops[i].count = 0; + } + } + for(i = 0; i < 8; i++) { /* write the 8 markers */ + strcpy(trailer->markers[i].name, " "); + trailer->markers[i].position = ~0u; + } + trailer->MIDInote = MIDI_UNITY; /* Unity play back */ + trailer->rate = rate; + trailer->SMPTEoffset = 0; + trailer->CycleSize = ~0u; +} + +/* + * Write the SampleVision trailer structure. + * Returns 1 if everything was written ok, 0 if there was an error. + */ +static int writetrailer(sox_format_t * ft, struct smptrailer *trailer) +{ + int i; + + lsx_writew(ft, 0); /* write the reserved word */ + for(i = 0; i < 8; i++) { /* write the 8 loops */ + lsx_writedw(ft, trailer->loops[i].start); + lsx_writedw(ft, trailer->loops[i].end); + lsx_writeb(ft, trailer->loops[i].type); + lsx_writew(ft, trailer->loops[i].count); + } + for(i = 0; i < 8; i++) { /* write the 8 markers */ + if (lsx_writes(ft, trailer->markers[i].name) == SOX_EOF) + { + lsx_fail_errno(ft,SOX_EHDR,"EOF in SMP"); + return(SOX_EOF); + } + lsx_writedw(ft, trailer->markers[i].position); + } + lsx_writeb(ft, (uint8_t)(trailer->MIDInote)); + lsx_writedw(ft, trailer->rate); + lsx_writedw(ft, trailer->SMPTEoffset); + lsx_writedw(ft, trailer->CycleSize); + return(SOX_SUCCESS); +} + +static int sox_smpseek(sox_format_t * ft, uint64_t offset) +{ + uint64_t new_offset; + size_t channel_block, alignment; + priv_t * smp = (priv_t *) ft->priv; + + new_offset = offset * (ft->encoding.bits_per_sample >> 3); + /* Make sure request aligns to a channel block (ie left+right) */ + channel_block = ft->signal.channels * (ft->encoding.bits_per_sample >> 3); + alignment = new_offset % channel_block; + /* Most common mistaken is to compute something like + * "skip everthing upto and including this sample" so + * advance to next sample block in this case. + */ + if (alignment != 0) + new_offset += (channel_block - alignment); + new_offset += smp->dataStart; + + ft->sox_errno = lsx_seeki(ft, (off_t)new_offset, SEEK_SET); + + if( ft->sox_errno == SOX_SUCCESS ) + smp->NoOfSamps = ft->signal.length - (new_offset / (ft->encoding.bits_per_sample >> 3)); + + return(ft->sox_errno); +} +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int sox_smpstartread(sox_format_t * ft) +{ + priv_t * smp = (priv_t *) ft->priv; + int namelen, commentlen; + off_t samplestart; + size_t i; + unsigned dw; + struct smpheader header; + struct smptrailer trailer; + + /* If you need to seek around the input file. */ + if (! ft->seekable) + { + lsx_fail_errno(ft,SOX_EOF,"SMP input file must be a file, not a pipe"); + return(SOX_EOF); + } + + /* Read SampleVision header */ + if (lsx_readbuf(ft, &header, HEADERSIZE) != HEADERSIZE) + { + lsx_fail_errno(ft,SOX_EHDR,"unexpected EOF in SMP header"); + return(SOX_EOF); + } + if (strncmp(header.Id, SVmagic, (size_t)17) != 0) + { + lsx_fail_errno(ft,SOX_EHDR,"SMP header does not begin with magic word %s", SVmagic); + return(SOX_EOF); + } + if (strncmp(header.version, SVvers, (size_t)4) != 0) + { + lsx_fail_errno(ft,SOX_EHDR,"SMP header is not version %s", SVvers); + return(SOX_EOF); + } + + /* Format the sample name and comments to a single comment */ + /* string. We decrement the counters till we encounter non */ + /* padding space chars, so the *lengths* are low by one */ + for (namelen = NAMELEN-1; + namelen >= 0 && header.name[namelen] == ' '; namelen--) + ; + for (commentlen = COMMENTLEN-1; + commentlen >= 0 && header.comments[commentlen] == ' '; commentlen--) + ; + sprintf(smp->comment, "%.*s: %.*s", namelen+1, header.name, + commentlen+1, header.comments); + sox_append_comments(&ft->oob.comments, smp->comment); + + /* Extract out the sample size (always intel format) */ + lsx_readdw(ft, &dw); + smp->NoOfSamps = dw; + /* mark the start of the sample data */ + samplestart = lsx_tell(ft); + + /* seek from the current position (the start of sample data) by */ + /* NoOfSamps * sizeof(int16_t) */ + if (lsx_seeki(ft, (off_t)(smp->NoOfSamps * 2), 1) == -1) + { + lsx_fail_errno(ft,errno,"SMP unable to seek to trailer"); + return(SOX_EOF); + } + if (readtrailer(ft, &trailer)) + { + lsx_fail_errno(ft,SOX_EHDR,"unexpected EOF in SMP trailer"); + return(SOX_EOF); + } + + /* seek back to the beginning of the data */ + if (lsx_seeki(ft, (off_t)samplestart, 0) == -1) + { + lsx_fail_errno(ft,errno,"SMP unable to seek back to start of sample data"); + return(SOX_EOF); + } + + ft->signal.rate = (int) trailer.rate; + ft->encoding.bits_per_sample = 16; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + ft->signal.channels = 1; + smp->dataStart = samplestart; + ft->signal.length = smp->NoOfSamps; + + lsx_report("SampleVision trailer:"); + for(i = 0; i < 8; i++) if (1 || trailer.loops[i].count) { + lsx_report("Loop %lu: start: %6d", (unsigned long)i, trailer.loops[i].start); + lsx_report(" end: %6d", trailer.loops[i].end); + lsx_report(" count: %6d", trailer.loops[i].count); + switch(trailer.loops[i].type) { + case 0: lsx_report("type: off"); break; + case 1: lsx_report("type: forward"); break; + case 2: lsx_report("type: forward/backward"); break; + } + } + lsx_report("MIDI Note number: %d", trailer.MIDInote); + + ft->oob.instr.nloops = 0; + for(i = 0; i < 8; i++) + if (trailer.loops[i].type) + ft->oob.instr.nloops++; + for(i = 0; i < ft->oob.instr.nloops; i++) { + ft->oob.loops[i].type = trailer.loops[i].type; + ft->oob.loops[i].count = trailer.loops[i].count; + ft->oob.loops[i].start = trailer.loops[i].start; + ft->oob.loops[i].length = trailer.loops[i].end + - trailer.loops[i].start; + } + ft->oob.instr.MIDIlow = ft->oob.instr.MIDIhi = + ft->oob.instr.MIDInote = trailer.MIDInote; + if (ft->oob.instr.nloops > 0) + ft->oob.instr.loopmode = SOX_LOOP_8; + else + ft->oob.instr.loopmode = SOX_LOOP_NONE; + + return(SOX_SUCCESS); +} + +/* + * Read up to len samples from file. + * Convert to signed longs. + * Place in buf[]. + * Return number of samples read. + */ +static size_t sox_smpread(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t * smp = (priv_t *) ft->priv; + unsigned short datum; + size_t done = 0; + + for(; done < len && smp->NoOfSamps; done++, smp->NoOfSamps--) { + lsx_readw(ft, &datum); + /* scale signed up to long's range */ + *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(datum,); + } + return done; +} + +static int sox_smpstartwrite(sox_format_t * ft) +{ + priv_t * smp = (priv_t *) ft->priv; + struct smpheader header; + char * comment = lsx_cat_comments(ft->oob.comments); + + /* If you have to seek around the output file */ + if (! ft->seekable) + { + lsx_fail_errno(ft,SOX_EOF,"Output .smp file must be a file, not a pipe"); + return(SOX_EOF); + } + + memcpy(header.Id, SVmagic, sizeof(header.Id)); + memcpy(header.version, SVvers, sizeof(header.version)); + sprintf(header.comments, "%-*s", COMMENTLEN - 1, "Converted using Sox."); + sprintf(header.name, "%-*.*s", NAMELEN, NAMELEN, comment); + free(comment); + + /* Write file header */ + if(lsx_writebuf(ft, &header, HEADERSIZE) != HEADERSIZE) + { + lsx_fail_errno(ft,errno,"SMP: Can't write header completely"); + return(SOX_EOF); + } + lsx_writedw(ft, 0); /* write as zero length for now, update later */ + smp->NoOfSamps = 0; + + return(SOX_SUCCESS); +} + +static size_t sox_smpwrite(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * smp = (priv_t *) ft->priv; + int datum; + size_t done = 0; + + while(done < len) { + SOX_SAMPLE_LOCALS; + datum = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips); + lsx_writew(ft, (uint16_t)datum); + smp->NoOfSamps++; + done++; + } + + return(done); +} + +static int sox_smpstopwrite(sox_format_t * ft) +{ + priv_t * smp = (priv_t *) ft->priv; + struct smptrailer trailer; + + /* Assign the trailer data */ + settrailer(ft, &trailer, ft->signal.rate); + writetrailer(ft, &trailer); + if (lsx_seeki(ft, (off_t)112, 0) == -1) + { + lsx_fail_errno(ft,errno,"SMP unable to seek back to save size"); + return(SOX_EOF); + } + lsx_writedw(ft, smp->NoOfSamps > UINT_MAX ? UINT_MAX : (unsigned)smp->NoOfSamps); + + return(SOX_SUCCESS); +} + +LSX_FORMAT_HANDLER(smp) +{ + static char const * const names[] = {"smp", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 16, 0, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Turtle Beach SampleVision", names, SOX_FILE_LIT_END | SOX_FILE_MONO, + sox_smpstartread, sox_smpread, NULL, + sox_smpstartwrite, sox_smpwrite, sox_smpstopwrite, + sox_smpseek, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/sndfile.c b/app/src/main/cpp/sox/sndfile.c new file mode 100644 index 0000000..1eda79c --- /dev/null +++ b/app/src/main/cpp/sox/sndfile.c @@ -0,0 +1,532 @@ +/* libSoX libsndfile formats. + * + * Copyright 2007 Reuben Thomas + * Copyright 1999-2005 Erik de Castro Lopo + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include +#include +#include +#include +#include + +#define LOG_MAX 2048 /* As per the SFC_GET_LOG_INFO example */ + +static const char* const sndfile_library_names[] = +{ +#ifdef DL_LIBSNDFILE + "libsndfile", + "libsndfile-1", + "cygsndfile-1", +#endif + NULL +}; + +#ifdef DL_LIBSNDFILE + #define SNDFILE_FUNC LSX_DLENTRY_DYNAMIC + #define SNDFILE_FUNC_STOP LSX_DLENTRY_STUB +#else + #define SNDFILE_FUNC LSX_DLENTRY_STATIC +#ifdef HACKED_LSF + #define SNDFILE_FUNC_STOP LSX_DLENTRY_STATIC +#else + #define SNDFILE_FUNC_STOP LSX_DLENTRY_STUB +#endif +#endif /* DL_LIBSNDFILE */ + +#define SNDFILE_FUNC_OPEN(f,x) \ + SNDFILE_FUNC(f,x, SNDFILE*, sf_open_virtual, (SF_VIRTUAL_IO *sfvirtual, int mode, SF_INFO *sfinfo, void *user_data)) + +#define SNDFILE_FUNC_ENTRIES(f,x) \ + SNDFILE_FUNC_OPEN(f,x) \ + SNDFILE_FUNC_STOP(f,x, int, sf_stop, (SNDFILE *sndfile)) \ + SNDFILE_FUNC(f,x, int, sf_close, (SNDFILE *sndfile)) \ + SNDFILE_FUNC(f,x, int, sf_format_check, (const SF_INFO *info)) \ + SNDFILE_FUNC(f,x, int, sf_command, (SNDFILE *sndfile, int command, void *data, int datasize)) \ + SNDFILE_FUNC(f,x, sf_count_t, sf_read_int, (SNDFILE *sndfile, int *ptr, sf_count_t items)) \ + SNDFILE_FUNC(f,x, sf_count_t, sf_write_int, (SNDFILE *sndfile, const int *ptr, sf_count_t items)) \ + SNDFILE_FUNC(f,x, sf_count_t, sf_seek, (SNDFILE *sndfile, sf_count_t frames, int whence)) \ + SNDFILE_FUNC(f,x, const char*, sf_strerror, (SNDFILE *sndfile)) + +/* Private data for sndfile files */ +typedef struct { + SNDFILE *sf_file; + SF_INFO *sf_info; + char * log_buffer; + char const * log_buffer_ptr; + LSX_DLENTRIES_TO_PTRS(SNDFILE_FUNC_ENTRIES, sndfile_dl); +} priv_t; + +/* + * Drain LSF's wonderful log buffer + */ +static void drain_log_buffer(sox_format_t * ft) +{ + priv_t * sf = (priv_t *)ft->priv; + sf->sf_command(sf->sf_file, SFC_GET_LOG_INFO, sf->log_buffer, LOG_MAX); + while (*sf->log_buffer_ptr) { + static char const warning_prefix[] = "*** Warning : "; + char const * end = strchr(sf->log_buffer_ptr, '\n'); + if (!end) + end = strchr(sf->log_buffer_ptr, '\0'); + if (!strncmp(sf->log_buffer_ptr, warning_prefix, strlen(warning_prefix))) { + sf->log_buffer_ptr += strlen(warning_prefix); + lsx_warn("`%s': %.*s", + ft->filename, (int)(end - sf->log_buffer_ptr), sf->log_buffer_ptr); + } else + lsx_debug("`%s': %.*s", + ft->filename, (int)(end - sf->log_buffer_ptr), sf->log_buffer_ptr); + sf->log_buffer_ptr = end; + if (*sf->log_buffer_ptr == '\n') + ++sf->log_buffer_ptr; + } +} + +/* Make libsndfile subtype from sample encoding and size */ +static int ft_enc(unsigned size, sox_encoding_t e) +{ + if (e == SOX_ENCODING_ULAW && size == 8) return SF_FORMAT_ULAW; + if (e == SOX_ENCODING_ALAW && size == 8) return SF_FORMAT_ALAW; + if (e == SOX_ENCODING_SIGN2 && size == 8) return SF_FORMAT_PCM_S8; + if (e == SOX_ENCODING_SIGN2 && size == 16) return SF_FORMAT_PCM_16; + if (e == SOX_ENCODING_SIGN2 && size == 24) return SF_FORMAT_PCM_24; + if (e == SOX_ENCODING_SIGN2 && size == 32) return SF_FORMAT_PCM_32; + if (e == SOX_ENCODING_UNSIGNED && size == 8) return SF_FORMAT_PCM_U8; + if (e == SOX_ENCODING_FLOAT && size == 32) return SF_FORMAT_FLOAT; + if (e == SOX_ENCODING_FLOAT && size == 64) return SF_FORMAT_DOUBLE; + if (e == SOX_ENCODING_G721 && size == 4) return SF_FORMAT_G721_32; + if (e == SOX_ENCODING_G723 && size == 3) return SF_FORMAT_G723_24; + if (e == SOX_ENCODING_G723 && size == 5) return SF_FORMAT_G723_40; + if (e == SOX_ENCODING_MS_ADPCM && size == 4) return SF_FORMAT_MS_ADPCM; + if (e == SOX_ENCODING_IMA_ADPCM && size == 4) return SF_FORMAT_IMA_ADPCM; + if (e == SOX_ENCODING_OKI_ADPCM && size == 4) return SF_FORMAT_VOX_ADPCM; + if (e == SOX_ENCODING_DPCM && size == 8) return SF_FORMAT_DPCM_8; + if (e == SOX_ENCODING_DPCM && size == 16) return SF_FORMAT_DPCM_16; + if (e == SOX_ENCODING_DWVW && size == 12) return SF_FORMAT_DWVW_12; + if (e == SOX_ENCODING_DWVW && size == 16) return SF_FORMAT_DWVW_16; + if (e == SOX_ENCODING_DWVW && size == 24) return SF_FORMAT_DWVW_24; + if (e == SOX_ENCODING_DWVWN && size == 0) return SF_FORMAT_DWVW_N; + if (e == SOX_ENCODING_GSM && size == 0) return SF_FORMAT_GSM610; + if (e == SOX_ENCODING_FLAC && size == 8) return SF_FORMAT_PCM_S8; + if (e == SOX_ENCODING_FLAC && size == 16) return SF_FORMAT_PCM_16; + if (e == SOX_ENCODING_FLAC && size == 24) return SF_FORMAT_PCM_24; + if (e == SOX_ENCODING_FLAC && size == 32) return SF_FORMAT_PCM_32; + return 0; /* Bad encoding */ +} + +/* Convert format's encoding type to libSoX encoding type & size. */ +static sox_encoding_t sox_enc(int ft_encoding, unsigned * size) +{ + int sub = ft_encoding & SF_FORMAT_SUBMASK; + int type = ft_encoding & SF_FORMAT_TYPEMASK; + + if (type == SF_FORMAT_FLAC) switch (sub) { + case SF_FORMAT_PCM_S8 : *size = 8; return SOX_ENCODING_FLAC; + case SF_FORMAT_PCM_16 : *size = 16; return SOX_ENCODING_FLAC; + case SF_FORMAT_PCM_24 : *size = 24; return SOX_ENCODING_FLAC; + } + switch (sub) { + case SF_FORMAT_ULAW : *size = 8; return SOX_ENCODING_ULAW; + case SF_FORMAT_ALAW : *size = 8; return SOX_ENCODING_ALAW; + case SF_FORMAT_PCM_S8 : *size = 8; return SOX_ENCODING_SIGN2; + case SF_FORMAT_PCM_16 : *size = 16; return SOX_ENCODING_SIGN2; + case SF_FORMAT_PCM_24 : *size = 24; return SOX_ENCODING_SIGN2; + case SF_FORMAT_PCM_32 : *size = 32; return SOX_ENCODING_SIGN2; + case SF_FORMAT_PCM_U8 : *size = 8; return SOX_ENCODING_UNSIGNED; + case SF_FORMAT_FLOAT : *size = 32; return SOX_ENCODING_FLOAT; + case SF_FORMAT_DOUBLE : *size = 64; return SOX_ENCODING_FLOAT; + case SF_FORMAT_G721_32 : *size = 4; return SOX_ENCODING_G721; + case SF_FORMAT_G723_24 : *size = 3; return SOX_ENCODING_G723; + case SF_FORMAT_G723_40 : *size = 5; return SOX_ENCODING_G723; + case SF_FORMAT_MS_ADPCM : *size = 4; return SOX_ENCODING_MS_ADPCM; + case SF_FORMAT_IMA_ADPCM: *size = 4; return SOX_ENCODING_IMA_ADPCM; + case SF_FORMAT_VOX_ADPCM: *size = 4; return SOX_ENCODING_OKI_ADPCM; + case SF_FORMAT_DPCM_8 : *size = 8; return SOX_ENCODING_DPCM; + case SF_FORMAT_DPCM_16 : *size = 16; return SOX_ENCODING_DPCM; + case SF_FORMAT_DWVW_12 : *size = 12; return SOX_ENCODING_DWVW; + case SF_FORMAT_DWVW_16 : *size = 16; return SOX_ENCODING_DWVW; + case SF_FORMAT_DWVW_24 : *size = 24; return SOX_ENCODING_DWVW; + case SF_FORMAT_DWVW_N : *size = 0; return SOX_ENCODING_DWVWN; + case SF_FORMAT_GSM610 : *size = 0; return SOX_ENCODING_GSM; + default : *size = 0; return SOX_ENCODING_UNKNOWN; + } +} + +static struct { + const char *ext; + int format; +} format_map[] = +{ + { "aif", SF_FORMAT_AIFF }, + { "aiff", SF_FORMAT_AIFF }, + { "wav", SF_FORMAT_WAV }, + { "au", SF_FORMAT_AU }, + { "snd", SF_FORMAT_AU }, + { "caf", SF_FORMAT_CAF }, + { "flac", SF_FORMAT_FLAC }, + { "wve", SF_FORMAT_WVE }, + { "ogg", SF_FORMAT_OGG }, + { "svx", SF_FORMAT_SVX }, + { "8svx", SF_FORMAT_SVX }, + { "paf", SF_ENDIAN_BIG | SF_FORMAT_PAF }, + { "fap", SF_ENDIAN_LITTLE | SF_FORMAT_PAF }, + { "gsm", SF_FORMAT_RAW | SF_FORMAT_GSM610 }, + { "nist", SF_FORMAT_NIST }, + { "sph", SF_FORMAT_NIST }, + { "ircam", SF_FORMAT_IRCAM }, + { "sf", SF_FORMAT_IRCAM }, + { "voc", SF_FORMAT_VOC }, + { "w64", SF_FORMAT_W64 }, + { "raw", SF_FORMAT_RAW }, + { "mat4", SF_FORMAT_MAT4 }, + { "mat5", SF_FORMAT_MAT5 }, + { "mat", SF_FORMAT_MAT4 }, + { "pvf", SF_FORMAT_PVF }, + { "sds", SF_FORMAT_SDS }, + { "sd2", SF_FORMAT_SD2 }, + { "vox", SF_FORMAT_RAW | SF_FORMAT_VOX_ADPCM }, + { "xi", SF_FORMAT_XI } +}; + +static int sf_stop_stub(SNDFILE *sndfile UNUSED) +{ + return 1; +} + +static sf_count_t vio_get_filelen(void *user_data) +{ + sox_format_t *ft = (sox_format_t *)user_data; + + /* lsf excepts unbuffered I/O behavior for get_filelen() so force that */ + lsx_flush(ft); + + return (sf_count_t)lsx_filelength((sox_format_t *)user_data); +} + +static sf_count_t vio_seek(sf_count_t offset, int whence, void *user_data) +{ + return lsx_seeki((sox_format_t *)user_data, (off_t)offset, whence); +} + +static sf_count_t vio_read(void *ptr, sf_count_t count, void *user_data) +{ + return lsx_readbuf((sox_format_t *)user_data, ptr, (size_t)count); +} + +static sf_count_t vio_write(const void *ptr, sf_count_t count, void *user_data) +{ + return lsx_writebuf((sox_format_t *)user_data, ptr, (size_t)count); +} + +static sf_count_t vio_tell(void *user_data) +{ + return lsx_tell((sox_format_t *)user_data); +} + +static SF_VIRTUAL_IO vio = +{ + vio_get_filelen, + vio_seek, + vio_read, + vio_write, + vio_tell +}; + +/* Convert file name or type to libsndfile format */ +static int name_to_format(const char *name) +{ + int k; +#define FILE_TYPE_BUFLEN (size_t)15 + char buffer[FILE_TYPE_BUFLEN + 1], *cptr; + + if ((cptr = strrchr(name, '.')) != NULL) { + strncpy(buffer, cptr + 1, FILE_TYPE_BUFLEN); + buffer[FILE_TYPE_BUFLEN] = '\0'; + + for (k = 0; buffer[k]; k++) + buffer[k] = tolower((buffer[k])); + } else { + strncpy(buffer, name, FILE_TYPE_BUFLEN); + buffer[FILE_TYPE_BUFLEN] = '\0'; + } + + for (k = 0; k < (int)(sizeof(format_map) / sizeof(format_map [0])); k++) { + if (strcmp(buffer, format_map[k].ext) == 0) + return format_map[k].format; + } + + return 0; +} + +static int start(sox_format_t * ft) +{ + priv_t * sf = (priv_t *)ft->priv; + int subtype = ft_enc(ft->encoding.bits_per_sample? ft->encoding.bits_per_sample : ft->signal.precision, ft->encoding.encoding); + int open_library_result; + + LSX_DLLIBRARY_OPEN( + sf, + sndfile_dl, + SNDFILE_FUNC_ENTRIES, + "libsndfile library", + sndfile_library_names, + open_library_result); + if (open_library_result) + return SOX_EOF; + + sf->log_buffer_ptr = sf->log_buffer = lsx_malloc((size_t)LOG_MAX); + sf->sf_info = lsx_calloc(1, sizeof(SF_INFO)); + + /* Copy format info */ + if (subtype) { + if (strcmp(ft->filetype, "sndfile") == 0) + sf->sf_info->format = name_to_format(ft->filename) | subtype; + else + sf->sf_info->format = name_to_format(ft->filetype) | subtype; + } + sf->sf_info->samplerate = (int)ft->signal.rate; + sf->sf_info->channels = ft->signal.channels; + if (ft->signal.channels) + sf->sf_info->frames = ft->signal.length / ft->signal.channels; + + return SOX_SUCCESS; +} + +static int check_read_params(sox_format_t * ft, unsigned channels, + sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample, uint64_t length) +{ + ft->signal.length = length; + + if (channels && ft->signal.channels && ft->signal.channels != channels) + lsx_warn("`%s': overriding number of channels", ft->filename); + else ft->signal.channels = channels; + + if (rate && ft->signal.rate && ft->signal.rate != rate) + lsx_warn("`%s': overriding sample rate", ft->filename); + else ft->signal.rate = rate; + + if (encoding && ft->encoding.encoding && ft->encoding.encoding != encoding) + lsx_warn("`%s': overriding encoding type", ft->filename); + else ft->encoding.encoding = encoding; + + if (bits_per_sample && ft->encoding.bits_per_sample && ft->encoding.bits_per_sample != bits_per_sample) + lsx_warn("`%s': overriding encoding size", ft->filename); + ft->encoding.bits_per_sample = bits_per_sample; + + if (sox_precision(ft->encoding.encoding, ft->encoding.bits_per_sample)) + return SOX_SUCCESS; + lsx_fail_errno(ft, EINVAL, "invalid format for this file type"); + return SOX_EOF; +} + +/* + * Open file in sndfile. + */ +static int startread(sox_format_t * ft) +{ + priv_t * sf = (priv_t *)ft->priv; + unsigned bits_per_sample; + sox_encoding_t encoding; + sox_rate_t rate; + + if (start(ft) == SOX_EOF) + return SOX_EOF; + + sf->sf_file = sf->sf_open_virtual(&vio, SFM_READ, sf->sf_info, ft); + drain_log_buffer(ft); + + if (sf->sf_file == NULL) { + memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr)); + strncpy(ft->sox_errstr, sf->sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1); + free(sf->sf_file); + return SOX_EOF; + } + + if (!(encoding = sox_enc(sf->sf_info->format, &bits_per_sample))) { + lsx_fail_errno(ft, SOX_EFMT, "unsupported sndfile encoding %#x", sf->sf_info->format); + return SOX_EOF; + } + + /* Don't believe LSF's rate for raw files */ + if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) == SF_FORMAT_RAW && !ft->signal.rate) { + lsx_warn("`%s': sample rate not specified; trying 8kHz", ft->filename); + rate = 8000; + } + else rate = sf->sf_info->samplerate; + + if ((sf->sf_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) { + sf->sf_command(sf->sf_file, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE); + sf->sf_command(sf->sf_file, SFC_SET_CLIPPING, NULL, SF_TRUE); + } + +#if 0 /* FIXME */ + sox_append_comments(&ft->oob.comments, buf); +#endif + + return check_read_params(ft, (unsigned)sf->sf_info->channels, rate, + encoding, bits_per_sample, (uint64_t)(sf->sf_info->frames * sf->sf_info->channels)); +} + +/* + * Read up to len samples of type sox_sample_t from file into buf[]. + * Return number of samples read. + */ +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t * sf = (priv_t *)ft->priv; + /* FIXME: We assume int == sox_sample_t here */ + return (size_t)sf->sf_read_int(sf->sf_file, (int *)buf, (sf_count_t)len); +} + +/* + * Close file for libsndfile (this doesn't close the file handle) + */ +static int stopread(sox_format_t * ft) +{ + priv_t * sf = (priv_t *)ft->priv; + sf->sf_stop(sf->sf_file); + drain_log_buffer(ft); + sf->sf_close(sf->sf_file); + LSX_DLLIBRARY_CLOSE(sf, sndfile_dl); + return SOX_SUCCESS; +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * sf = (priv_t *)ft->priv; + + if (start(ft) == SOX_EOF) + return SOX_EOF; + + /* If output format is invalid, try to find a sensible default */ + if (!sf->sf_format_check(sf->sf_info)) { + SF_FORMAT_INFO format_info; + int i, count; + + sf->sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT_COUNT, &count, (int) sizeof(int)); + for (i = 0; i < count; i++) { + format_info.format = i; + sf->sf_command(sf->sf_file, SFC_GET_SIMPLE_FORMAT, &format_info, (int) sizeof(format_info)); + if ((format_info.format & SF_FORMAT_TYPEMASK) == (sf->sf_info->format & SF_FORMAT_TYPEMASK)) { + sf->sf_info->format = format_info.format; + /* FIXME: Print out exactly what we chose, needs sndfile -> + sox encoding conversion functions */ + break; + } + } + + if (!sf->sf_format_check(sf->sf_info)) { + lsx_fail("cannot find a usable output encoding"); + return SOX_EOF; + } + if ((sf->sf_info->format & SF_FORMAT_TYPEMASK) != SF_FORMAT_RAW) + lsx_warn("cannot use desired output encoding, choosing default"); + } + + sf->sf_file = sf->sf_open_virtual(&vio, SFM_WRITE, sf->sf_info, ft); + drain_log_buffer(ft); + + if (sf->sf_file == NULL) { + memset(ft->sox_errstr, 0, sizeof(ft->sox_errstr)); + strncpy(ft->sox_errstr, sf->sf_strerror(sf->sf_file), sizeof(ft->sox_errstr)-1); + free(sf->sf_file); + return SOX_EOF; + } + + if ((sf->sf_info->format & SF_FORMAT_SUBMASK) == SF_FORMAT_FLOAT) + sf->sf_command(sf->sf_file, SFC_SET_SCALE_INT_FLOAT_WRITE, NULL, SF_TRUE); + + return SOX_SUCCESS; +} + +/* + * Write len samples of type sox_sample_t from buf[] to file. + * Return number of samples written. + */ +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * sf = (priv_t *)ft->priv; + /* FIXME: We assume int == sox_sample_t here */ + return (size_t)sf->sf_write_int(sf->sf_file, (int *)buf, (sf_count_t)len); +} + +/* + * Close file for libsndfile (this doesn't close the file handle) + */ +static int stopwrite(sox_format_t * ft) +{ + priv_t * sf = (priv_t *)ft->priv; + sf->sf_stop(sf->sf_file); + drain_log_buffer(ft); + sf->sf_close(sf->sf_file); + LSX_DLLIBRARY_CLOSE(sf, sndfile_dl); + return SOX_SUCCESS; +} + +static int seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * sf = (priv_t *)ft->priv; + sf->sf_seek(sf->sf_file, (sf_count_t)(offset / ft->signal.channels), SEEK_CUR); + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(sndfile) +{ + static char const * const names[] = { + "sndfile", /* Special type to force use of sndfile for the following: */ + /* LSF implementation of formats built in to SoX: */ + /* "aif", */ + /* "au", */ + /* "gsm", */ + /* "nist", */ + /* "raw", */ + /* "sf", "ircam", */ + /* "snd", */ + /* "svx", */ + /* "voc", */ + /* "vox", */ + /* "wav", */ + /* LSF wrappers of formats already wrapped in SoX: */ + /* "flac", */ + + "sds", /* ?? */ + NULL + }; + + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 24, 32, 8, 0, + SOX_ENCODING_UNSIGNED, 8, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_IMA_ADPCM, 4, 0, + SOX_ENCODING_MS_ADPCM, 4, 0, + SOX_ENCODING_OKI_ADPCM, 4, 0, + SOX_ENCODING_GSM, 0, + 0}; + + static sox_format_handler_t const format = {SOX_LIB_VERSION_CODE, + "Pseudo format to use libsndfile", names, 0, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + seek, write_encodings, NULL, sizeof(priv_t) + }; + + return &format; +} diff --git a/app/src/main/cpp/sox/sndio.c b/app/src/main/cpp/sox/sndio.c new file mode 100644 index 0000000..77785ce --- /dev/null +++ b/app/src/main/cpp/sox/sndio.c @@ -0,0 +1,246 @@ +/* + * libsndio sound handler + * + * Copyright (c) 2009 Alexandre Ratchov + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "sox_i.h" +#include +#include + +struct sndio_priv { + struct sio_hdl *hdl; /* handle to speak to libsndio */ + struct sio_par par; /* current device parameters */ +#define SNDIO_BUFSZ 0x1000 + unsigned char buf[SNDIO_BUFSZ]; /* temp buffer for converions */ +}; + +/* + * convert ``count'' samples from sox encoding to sndio encoding + */ +static void encode(struct sio_par *par, + sox_sample_t const *idata, unsigned char *odata, unsigned count) +{ + int obnext, osnext, s, osigbit; + unsigned oshift, obps, i; + + obps = par->bps; + osigbit = par->sig ? 0 : 1 << (par->bits - 1); + oshift = 32 - (par->msb ? par->bps * 8 : par->bits); + if (par->le) { + obnext = 1; + osnext = 0; + } else { + odata += par->bps - 1; + obnext = -1; + osnext = 2 * par->bps; + } + for (; count > 0; count--) { + s = (*idata++ >> oshift) ^ osigbit; + for (i = obps; i > 0; i--) { + *odata = (unsigned char)s; + s >>= 8; + odata += obnext; + } + odata += osnext; + } +} + +/* + * convert ``count'' samples from sndio encoding to sox encoding + */ +static void decode(struct sio_par *par, + unsigned char *idata, sox_sample_t *odata, unsigned count) +{ + unsigned ishift, ibps, i; + int s = 0xdeadbeef, ibnext, isnext, isigbit; + + ibps = par->bps; + isigbit = par->sig ? 0 : 1 << (par->bits - 1); + ishift = 32 - (par->msb ? par->bps * 8 : par->bits); + if (par->le) { + idata += par->bps - 1; + ibnext = -1; + isnext = 2 * par->bps; + } else { + ibnext = 1; + isnext = 0; + } + for (; count > 0; count--) { + for (i = ibps; i > 0; i--) { + s <<= 8; + s |= *idata; + idata += ibnext; + } + idata += isnext; + *odata++ = (s ^ isigbit) << ishift; + } +} + +static int startany(sox_format_t *ft, unsigned mode) +{ + struct sndio_priv *p = (struct sndio_priv *)ft->priv; + struct sio_par reqpar; + char *device; + + device = ft->filename; + if (strcmp("default", device) == 0) + device = NULL; + + p->hdl = sio_open(device, mode, 0); + if (p->hdl == NULL) + return SOX_EOF; + /* + * set specified parameters, leaving others to the defaults + */ + sio_initpar(&reqpar); + if (ft->signal.rate > 0) + reqpar.rate = ft->signal.rate; + if (ft->signal.channels > 0) { + if (mode == SIO_PLAY) + reqpar.pchan = ft->signal.channels; + else + reqpar.rchan = ft->signal.channels; + } + switch (ft->encoding.encoding) { + case SOX_ENCODING_SIGN2: + reqpar.sig = 1; + break; + case SOX_ENCODING_UNSIGNED: + reqpar.sig = 0; + break; + default: + break; /* use device default */ + } + if (ft->encoding.bits_per_sample > 0) + reqpar.bits = ft->encoding.bits_per_sample; + else if (ft->signal.precision > 0) + reqpar.bits = ft->signal.precision; + else + reqpar.bits = SOX_DEFAULT_PRECISION; + reqpar.bps = (reqpar.bits + 7) / 8; + reqpar.msb = 1; + if (ft->encoding.reverse_bytes != sox_option_default) { + reqpar.le = SIO_LE_NATIVE; + if (ft->encoding.reverse_bytes) + reqpar.le = !reqpar.le; + } + if (!sio_setpar(p->hdl, &reqpar) || + !sio_getpar(p->hdl, &p->par)) + goto failed; + ft->signal.channels = (mode == SIO_PLAY) ? p->par.pchan : p->par.rchan; + ft->signal.precision = p->par.bits; + ft->signal.rate = p->par.rate; + ft->encoding.encoding = p->par.sig ? SOX_ENCODING_SIGN2 : SOX_ENCODING_UNSIGNED; + ft->encoding.bits_per_sample = p->par.bps * 8; + ft->encoding.reverse_bytes = SIO_LE_NATIVE ? !p->par.le : p->par.le; + ft->encoding.reverse_nibbles = sox_option_no; + ft->encoding.reverse_bits = sox_option_no; + + if (!sio_start(p->hdl)) + goto failed; + return SOX_SUCCESS; + failed: + sio_close(p->hdl); + return SOX_EOF; +} + +static int stopany(sox_format_t *ft) +{ + sio_close(((struct sndio_priv *)ft->priv)->hdl); + return SOX_SUCCESS; +} + +static int startread(sox_format_t *ft) +{ + return startany(ft, SIO_REC); +} + +static int startwrite(sox_format_t *ft) +{ + return startany(ft, SIO_PLAY); +} + +static size_t readsamples(sox_format_t *ft, sox_sample_t *buf, size_t len) +{ + struct sndio_priv *p = (struct sndio_priv *)ft->priv; + unsigned char partial[4]; + unsigned cpb, cc, pc; + size_t todo, n; + + pc = 0; + todo = len * p->par.bps; + cpb = SNDIO_BUFSZ - (SNDIO_BUFSZ % p->par.bps); + while (todo > 0) { + memcpy(p->buf, partial, (size_t)pc); + cc = cpb - pc; + if (cc > todo) + cc = todo; + n = sio_read(p->hdl, p->buf + pc, (size_t)cc); + if (n == 0 && sio_eof(p->hdl)) + break; + n += pc; + pc = n % p->par.bps; + n -= pc; + memcpy(partial, p->buf + n, (size_t)pc); + decode(&p->par, p->buf, buf, (unsigned)(n / p->par.bps)); + buf += n / p->par.bps; + todo -= n; + } + return len - todo / p->par.bps; +} + +static size_t writesamples(sox_format_t *ft, const sox_sample_t *buf, size_t len) +{ + struct sndio_priv *p = (struct sndio_priv *)ft->priv; + unsigned sc, spb; + size_t n, todo; + + todo = len; + spb = SNDIO_BUFSZ / p->par.bps; + while (todo > 0) { + sc = spb; + if (sc > todo) + sc = todo; + encode(&p->par, buf, p->buf, sc); + n = sio_write(p->hdl, p->buf, (size_t)(sc * p->par.bps)); + if (n == 0 && sio_eof(p->hdl)) + break; + n /= p->par.bps; + todo -= n; + buf += n; + } + return len - todo; +} + +LSX_FORMAT_HANDLER(sndio) +{ + static char const * const names[] = {"sndio", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, + SOX_ENCODING_UNSIGNED, 32, 24, 16, 8, 0, + 0 + }; + static sox_format_handler_t const handler = { + SOX_LIB_VERSION_CODE, + "libsndio device driver", + names, + SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + startread, readsamples, stopany, + startwrite, writesamples, stopany, + NULL, write_encodings, NULL, + sizeof(struct sndio_priv) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/sounder.c b/app/src/main/cpp/sox/sounder.c new file mode 100644 index 0000000..678d99e --- /dev/null +++ b/app/src/main/cpp/sox/sounder.c @@ -0,0 +1,55 @@ +/* libSoX Sounder format handler (c) 2008 robs@users.sourceforge.net + * See description in soundr3b.zip on the net. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +static int start_read(sox_format_t * ft) +{ + uint16_t type, rate; + + if (lsx_readw(ft, &type) || lsx_readw(ft, &rate) || lsx_skipbytes(ft, (size_t) 4)) + return SOX_EOF; + if (type) { + lsx_fail_errno(ft, SOX_EHDR, "invalid Sounder header"); + return SOX_EOF; + } + return lsx_check_read_params(ft, 1, (sox_rate_t)rate, SOX_ENCODING_UNSIGNED, 8, (uint64_t)0, sox_true); +} + +static int write_header(sox_format_t * ft) +{ + return lsx_writew(ft, 0) /* sample type */ + || lsx_writew(ft, min(65535, (unsigned)(ft->signal.rate + .5))) + || lsx_writew(ft, 10) /* speaker driver volume */ + || lsx_writew(ft, 4)? /* speaker driver DC shift */ + SOX_EOF : SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(sounder) +{ + static char const * const names[] = {"sndr", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_UNSIGNED, 8, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "8-bit linear audio as used by Aaron Wallace's `Sounder' of 1991", + names, SOX_FILE_LIT_END | SOX_FILE_MONO, + start_read, lsx_rawread, NULL, + write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/soundtool.c b/app/src/main/cpp/sox/soundtool.c new file mode 100644 index 0000000..8a83df3 --- /dev/null +++ b/app/src/main/cpp/sox/soundtool.c @@ -0,0 +1,78 @@ +/* libSoX SoundTool format handler (c) 2008 robs@users.sourceforge.net + * See description in sndtl26.zip on the net. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +static char const ID1[6] = "SOUND\x1a"; +#define text_field_len (size_t)96 /* Includes null-terminator */ + +static int start_read(sox_format_t * ft) +{ + char id1[sizeof(ID1)], comments[text_field_len + 1]; + uint32_t nsamples; + uint16_t rate; + + if (lsx_readchars(ft, id1, sizeof(ID1)) || + lsx_skipbytes(ft, (size_t) 10) || lsx_readdw(ft, &nsamples) || + lsx_readw(ft, &rate) || lsx_skipbytes(ft, (size_t) 6) || + lsx_readchars(ft, comments, text_field_len)) + return SOX_EOF; + if (memcmp(ID1, id1, sizeof(id1))) { + lsx_fail_errno(ft, SOX_EHDR, "soundtool: can't find SoundTool identifier"); + return SOX_EOF; + } + comments[text_field_len] = '\0'; /* Be defensive against incorrect files */ + sox_append_comments(&ft->oob.comments, comments); + return lsx_check_read_params(ft, 1, (sox_rate_t)rate, SOX_ENCODING_UNSIGNED, 8, (uint64_t)nsamples, sox_true); +} + +static int write_header(sox_format_t * ft) +{ + char * comment = lsx_cat_comments(ft->oob.comments); + char text_buf[text_field_len]; + uint64_t length = ft->olength? ft->olength:ft->signal.length; + + memset(text_buf, 0, sizeof(text_buf)); + strncpy(text_buf, comment, text_field_len - 1); + free(comment); + return lsx_writechars(ft, ID1, sizeof(ID1)) + || lsx_writew (ft, 0) /* GSound: not used */ + || lsx_writedw (ft, (unsigned) length) /* length of complete sample */ + || lsx_writedw (ft, 0) /* first byte to play from sample */ + || lsx_writedw (ft, (unsigned) length) /* first byte NOT to play from sample */ + || lsx_writew (ft, min(65535, (unsigned)(ft->signal.rate + .5))) + || lsx_writew (ft, 0) /* sample size/type */ + || lsx_writew (ft, 10) /* speaker driver volume */ + || lsx_writew (ft, 4) /* speaker driver DC shift */ + || lsx_writechars(ft, text_buf, sizeof(text_buf))? SOX_EOF:SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(soundtool) +{ + static char const * const names[] = {"sndt", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_UNSIGNED, 8, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "8-bit linear audio as used by Martin Hepperle's `SoundTool' of 1991/2", + names, SOX_FILE_LIT_END | SOX_FILE_MONO | SOX_FILE_REWIND, + start_read, lsx_rawread, NULL, + write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/sox-fmt.c b/app/src/main/cpp/sox/sox-fmt.c new file mode 100644 index 0000000..11c8877 --- /dev/null +++ b/app/src/main/cpp/sox/sox-fmt.c @@ -0,0 +1,108 @@ +/* libSoX file format: SoX native (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +static char const magic[2][4] = {".SoX", "XoS."}; +#define FIXED_HDR (4 + 8 + 8 + 4 + 4) /* Without magic */ + +static int startread(sox_format_t * ft) +{ + char magic_[sizeof(magic[0])]; + uint32_t headers_bytes, num_channels, comments_bytes; + uint64_t num_samples; + double rate; + + if (lsx_readdw(ft, (uint32_t *)&magic_)) + return SOX_EOF; + + if (memcmp(magic[MACHINE_IS_BIGENDIAN], magic_, sizeof(magic_))) { + if (memcmp(magic[MACHINE_IS_LITTLEENDIAN], magic_, sizeof(magic_))) { + lsx_fail_errno(ft, SOX_EHDR, "can't find sox file format identifier"); + return SOX_EOF; + } + ft->encoding.reverse_bytes = !ft->encoding.reverse_bytes; + lsx_report("file is opposite endian"); + } + if (lsx_readdw(ft, &headers_bytes) || + lsx_readqw(ft, &num_samples) || + lsx_readdf(ft, &rate) || + lsx_readdw(ft, &num_channels) || + lsx_readdw(ft, &comments_bytes)) + return SOX_EOF; + + if (((headers_bytes + 4) & 7) || + comments_bytes > 0x40000000 || /* max 1 GB */ + headers_bytes < FIXED_HDR + comments_bytes || + (num_channels > 65535)) /* Reserve top 16 bits */ { + lsx_fail_errno(ft, SOX_EHDR, "invalid sox file format header"); + return SOX_EOF; + } + + if (comments_bytes) { + char * buf = lsx_calloc(1, (size_t)comments_bytes + 1); /* ensure nul-terminated */ + if (lsx_readchars(ft, buf, (size_t)comments_bytes) != SOX_SUCCESS) { + free(buf); + return SOX_EOF; + } + sox_append_comments(&ft->oob.comments, buf); + free(buf); + } + + /* Consume any bytes after the comments and before the start of the audio + * block. These may include comment padding up to a multiple of 8 bytes, + * and further header information that might be defined in future. */ + lsx_seeki(ft, (off_t)(headers_bytes - FIXED_HDR - comments_bytes), SEEK_CUR); + + return lsx_check_read_params( + ft, num_channels, rate, SOX_ENCODING_SIGN2, 32, num_samples, sox_true); +} + +static int write_header(sox_format_t * ft) +{ + char * comments = lsx_cat_comments(ft->oob.comments); + size_t comments_len = strlen(comments); + size_t comments_bytes = (comments_len + 7) & ~7u; /* Multiple of 8 bytes */ + uint64_t size = ft->olength? ft->olength : ft->signal.length; + int error; + uint32_t header; + memcpy(&header, magic[MACHINE_IS_BIGENDIAN], sizeof(header)); + error = 0 + ||lsx_writedw(ft, header) + ||lsx_writedw(ft, FIXED_HDR + (unsigned)comments_bytes) + ||lsx_writeqw(ft, size) + ||lsx_writedf(ft, ft->signal.rate) + ||lsx_writedw(ft, ft->signal.channels) + ||lsx_writedw(ft, (unsigned)comments_len) + ||lsx_writechars(ft, comments, comments_len) + ||lsx_padbytes(ft, comments_bytes - comments_len); + free(comments); + return error? SOX_EOF: SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(sox) +{ + static char const * const names[] = {"sox", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 32, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "SoX native intermediate format", names, SOX_FILE_REWIND, + startread, lsx_rawread, NULL, write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/sox.c b/app/src/main/cpp/sox/sox.c new file mode 100644 index 0000000..9e59a60 --- /dev/null +++ b/app/src/main/cpp/sox/sox.c @@ -0,0 +1,3036 @@ +/* SoX - The Swiss Army Knife of Audio Manipulation. + * + * This is the main function for the SoX command line programs: + * sox, play, rec, soxi. + * + * Copyright 1998-2009 Chris Bagwell and SoX contributors + * Copyright 1991 Lance Norskog And Sundry Contributors + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "soxconfig.h" +#include "sox.h" +#include "util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(HAVE_GLOB_H) + #include +#endif + +#ifdef HAVE_IO_H + #include +#endif + +#ifdef HAVE_SYS_TIME_H + #include +#endif + +#ifdef HAVE_SYS_TIMEB_H + #include +#endif + +#ifdef HAVE_SYS_UTSNAME_H + #include +#endif + +#ifdef HAVE_UNISTD_H + #include +#endif + +#ifdef HAVE_SYS_IOCTL_H + #include +#endif + +#ifdef HAVE_GETTIMEOFDAY + #define TIME_FRAC 1e6 +#else + #define timeval timeb + #define gettimeofday(a,b) ftime(a) + #define tv_sec time + #define tv_usec millitm + #define TIME_FRAC 1e3 +#endif + +#if !defined(HAVE_CONIO_H) && !defined(HAVE_TERMIOS_H) && (defined(_MSC_VER) || defined(__MINGW32__)) +#define HAVE_CONIO_H 1 +#endif + +#ifdef HAVE_CONIO_H +/* _kbhit and _getch */ +#include +#undef HAVE_TERMIOS_H +#endif + +/*#define MORE_INTERACTIVE 1*/ + +#define SOX_OPTS "SOX_OPTS" +static lsx_getopt_t optstate; + +/* argv[0] options */ + +static char const * myname = NULL; +static enum {sox_sox, sox_play, sox_rec, sox_soxi} sox_mode; + + +/* gopts */ + +static enum { + sox_sequence, sox_concatenate, sox_mix, sox_mix_power, + sox_merge, sox_multiply, sox_default +} combine_method = sox_default; +static enum { sox_single, sox_multiple } output_method = sox_single; +#define is_serial(m) ((m) <= sox_concatenate) +#define is_parallel(m) (!is_serial(m)) +static sox_bool no_clobber = sox_false, interactive = sox_false; +static sox_bool uservolume = sox_false; +typedef enum {RG_off, RG_track, RG_album, RG_default} rg_mode; +static lsx_enum_item const rg_modes[] = { + LSX_ENUM_ITEM(RG_,off) + LSX_ENUM_ITEM(RG_,track) + LSX_ENUM_ITEM(RG_,album) + {0, 0}}; +static rg_mode replay_gain_mode = RG_default; +static sox_option_t show_progress = sox_option_default; + + +/* Input & output files */ + +typedef struct { + char * filename; + + /* fopts */ + char const * filetype; + sox_signalinfo_t signal; + sox_encodinginfo_t encoding; + double volume; + double replay_gain; + sox_oob_t oob; + sox_bool no_glob; + + sox_format_t * ft; /* libSoX file descriptor */ + uint64_t volume_clips; + rg_mode replay_gain_mode; +} file_t; + +static file_t * * files = NULL; /* Array tracking input and output files */ +#define ofile files[file_count - 1] +static size_t file_count = 0; +static size_t input_count = 0; +static size_t output_count = 0; + +/* Effects */ + +/* We parse effects into a temporary effects table and then place into + * the real effects chain. This allows scanning all effects to give + * hints to what input effect options should be as well as determining + * when mixer or resample effects need to be auto-inserted as well. + */ +static sox_effect_t **user_efftab = NULL; +static size_t user_efftab_size = 0; +static sox_effects_chain_t *effects_chain = NULL; +static sox_effect_t *save_output_eff = NULL; + +static struct { char *name; int argc; char **argv; size_t argv_size; } **user_effargs = NULL; +static size_t *user_effargs_size = NULL; /* array: size of user_effargs for each chain */ +/* Size of memory structures related to effects arguments (user_effargs[i], + * user_effargs[i][j].argv) to be extended in steps of EFFARGS_STEP */ +#define EFFARGS_STEP 8 +static size_t *nuser_effects = NULL; /* array: number of effects in each chain */ +static size_t current_eff_chain = 0; +static size_t eff_chain_count = 0; +static sox_bool very_first_effchain = sox_true; + /* Indicates that not only the first effects chain is in effect (hrm), but + also that it has never been restarted. Only then we may use the + optimize_trim() hack. */ +static char *effects_filename = NULL; +static char * play_rate_arg = NULL; +static char *norm_level = NULL; + +/* Flowing */ + +static sox_signalinfo_t combiner_signal, ofile_signal_options; +static sox_encodinginfo_t combiner_encoding, ofile_encoding_options; +static uint64_t mixing_clips = 0; +static size_t current_input = 0; +static uint64_t input_wide_samples = 0; +static uint64_t read_wide_samples = 0; +static uint64_t output_samples = 0; +static sox_bool input_eof = sox_false; +static sox_bool output_eof = sox_false; +static sox_bool user_abort = sox_false; +static sox_bool user_skip = sox_false; +static sox_bool user_restart_eff = sox_false; +static int success = 0; +static int cleanup_called = 0; +static sox_sample_t omax[2], omin[2]; + +#ifdef HAVE_TERMIOS_H +#include +static struct termios original_termios; +static sox_bool original_termios_saved = sox_false; +#endif + +static sox_bool stdin_is_a_tty, is_player, is_guarded, do_guarded_norm, no_dither, reported_sox_opts; + +struct timeval load_timeofday; + +static void cleanup(void) +{ + size_t i; + + if (!success && !reported_sox_opts) { + char const * env_opts = getenv(SOX_OPTS); + if (env_opts && *env_opts) + lsx_report("used "SOX_OPTS"=%s", env_opts); + } + /* Close the input and output files before exiting. */ + for (i = 0; i < input_count; i++) { + if (files[i]->ft) { + sox_close(files[i]->ft); + } + free(files[i]->filename); + free(files[i]); + } + + if (file_count) { + if (ofile->ft) { + if (!success && ofile->ft->io_type == lsx_io_file) { /* If we failed part way through */ + struct stat st; /* writing a normal file, remove it. */ + if (!stat(ofile->ft->filename, &st) && + (st.st_mode & S_IFMT) == S_IFREG) + unlink(ofile->ft->filename); + } + sox_close(ofile->ft); /* Assume we can unlink a file before closing it. */ + } + free(ofile->filename); + free(ofile); + } + + free(files); + +#ifdef HAVE_TERMIOS_H + if (original_termios_saved) + tcsetattr(fileno(stdin), TCSANOW, &original_termios); +#endif + + free(user_efftab); + + free(sox_globals.tmp_path); + sox_globals.tmp_path = NULL; + + free(play_rate_arg); + free(effects_filename); + free(norm_level); + + sox_quit(); + + cleanup_called = 1; +} + +/* Cleanup atexit() function, hence always called. */ +static void atexit_cleanup(void) +{ + /* Do not call cleanup using atexit() if possible. pthread's can + * act unpredictable if called outside of main(). + */ + if (!cleanup_called) + cleanup(); +} + +static char const * str_time(double seconds) +{ + static char string[16][50]; + static int i; + int hours, mins = seconds / 60; + seconds -= mins * 60; + hours = mins / 60; + mins -= hours * 60; + i = (i+1) & 15; + sprintf(string[i], "%02i:%02i:%05.2f", hours, mins, seconds); + return string[i]; +} + +static char const * size_and_bitrate(sox_format_t * ft, char const * * text) +{ + off_t size = lsx_filelength(ft); + if (ft->signal.length && ft->signal.channels && ft->signal.rate && text) { + double secs = ft->signal.length / ft->signal.channels / ft->signal.rate; + *text = lsx_sigfigs3(8. * size / secs); + } + return lsx_sigfigs3((double)size); +} + +static void play_file_info(sox_format_t * ft, file_t * f, sox_bool full) +{ + FILE * const output = sox_mode == sox_soxi? stdout : stderr; + char const * text, * text2 = NULL; + char buffer[30]; + uint64_t ws = ft->signal.length / ft->signal.channels; + (void)full; + + fprintf(output, "\n"); + if (ft->filename[0]) { + fprintf(output, "%s:", ft->filename); + if (strcmp(ft->filename, "-") == 0 || (ft->handler.flags & SOX_FILE_DEVICE)) + fprintf(output, " (%s)", ft->handler.names[0]); + fprintf(output, "\n\n"); + } + + if ((text = size_and_bitrate(ft, &text2))) { + fprintf(output, " File Size: %-10s", text); + if (text2) + fprintf(output, "Bit Rate: %s", text2); + fprintf(output, "\n"); + } + + fprintf(output, " Encoding: %-14s", sox_encodings_info[ft->encoding.encoding].name); + text = sox_find_comment(f->ft->oob.comments, "Comment"); + if (!text) + text = sox_find_comment(f->ft->oob.comments, "Description"); + if (!text) + text = sox_find_comment(f->ft->oob.comments, "Year"); + if (text) + fprintf(output, "Info: %s", text); + fprintf(output, "\n"); + + sprintf(buffer, " Channels: %u @ %u-bit", ft->signal.channels, ft->signal.precision); + fprintf(output, "%-25s", buffer); + text = sox_find_comment(f->ft->oob.comments, "Tracknumber"); + if (text) { + fprintf(output, "Track: %s", text); + text = sox_find_comment(f->ft->oob.comments, "Tracktotal"); + if (text) + fprintf(output, " of %s", text); + } + fprintf(output, "\n"); + + sprintf(buffer, "Samplerate: %gHz", ft->signal.rate); + fprintf(output, "%-25s", buffer); + text = sox_find_comment(f->ft->oob.comments, "Album"); + if (text) + fprintf(output, "Album: %s", text); + fprintf(output, "\n"); + + if (f && f->replay_gain != HUGE_VAL){ + sprintf(buffer, "%s gain: %+.1fdB", lsx_find_enum_value(f->replay_gain_mode, rg_modes)->text, f->replay_gain); + buffer[0] += 'A' - 'a'; + fprintf(output, "%-24s", buffer); + } else + fprintf(output, "%-24s", "Replaygain: off"); + text = sox_find_comment(f->ft->oob.comments, "Artist"); + if (text) + fprintf(output, "Artist: %s", text); + fprintf(output, "\n"); + + fprintf(output, " Duration: %-13s", ft->signal.length? str_time((double)ws / ft->signal.rate) : "unknown"); + text = sox_find_comment(f->ft->oob.comments, "Title"); + if (text) + fprintf(output, "Title: %s", text); + fprintf(output, "\n\n"); +} + +static void display_file_info(sox_format_t * ft, file_t * f, sox_bool full) +{ + static char const * const no_yes[] = {"no", "yes"}; + FILE * const output = sox_mode == sox_soxi? stdout : stderr; + char const * filetype = lsx_find_file_extension(ft->filename); + sox_bool show_type = sox_true; + size_t i; + + if (is_player && sox_globals.verbosity < 3) { + play_file_info(ft, f, full); + return; + } + + fprintf(output, "\n%s: '%s'", + ft->mode == 'r'? "Input File " : "Output File ", ft->filename); + if (filetype) for (i = 0; ft->handler.names[i] && show_type; ++i) + if (!strcasecmp(filetype, ft->handler.names[i])) + show_type = sox_false; + if (show_type) + fprintf(output, " (%s)", ft->handler.names[0]); + fprintf(output, "\n"); + + fprintf(output, + "Channels : %u\n" + "Sample Rate : %g\n" + "Precision : %u-bit\n", + ft->signal.channels, + ft->signal.rate, + ft->signal.precision); + + if (ft->signal.length && ft->signal.channels && ft->signal.rate) { + uint64_t ws = ft->signal.length / ft->signal.channels; + char const * text, * text2 = NULL; + fprintf(output, + "Duration : %s = %" PRIu64 " samples %c %g CDDA sectors\n", + str_time((double)ws / ft->signal.rate), + ws, "~="[ft->signal.rate == 44100], + (double)ws / ft->signal.rate * 44100 / 588); + if (ft->mode == 'r' && (text = size_and_bitrate(ft, &text2))) { + fprintf(output, "File Size : %s\n", text); + if (text2) + fprintf(output, "Bit Rate : %s\n", text2); + } + } + + if (ft->encoding.encoding) { + char buffer[20] = {'\0'}; + if (ft->encoding.bits_per_sample) + sprintf(buffer, "%u-bit ", ft->encoding.bits_per_sample); + + fprintf(output, "Sample Encoding: %s%s\n", buffer, + sox_encodings_info[ft->encoding.encoding].desc); + } + + if (full) { + if (ft->encoding.bits_per_sample > 8 || (ft->handler.flags & SOX_FILE_ENDIAN)) + fprintf(output, "Endian Type : %s\n", + ft->encoding.reverse_bytes != MACHINE_IS_BIGENDIAN ? "big" : "little"); + if (ft->encoding.bits_per_sample) + fprintf(output, + "Reverse Nibbles: %s\n" + "Reverse Bits : %s\n", + no_yes[ft->encoding.reverse_nibbles], + no_yes[ft->encoding.reverse_bits]); + } + + if (f && f->replay_gain != HUGE_VAL) + fprintf(output, "Replay gain : %+g dB (%s)\n" , f->replay_gain, + lsx_find_enum_value(f->replay_gain_mode, rg_modes)->text); + if (f && f->volume != HUGE_VAL) + fprintf(output, "Level adjust : %g (linear gain)\n" , f->volume); + + if (!(ft->handler.flags & SOX_FILE_DEVICE) && ft->oob.comments) { + if (sox_num_comments(ft->oob.comments) > 1) { + sox_comments_t p = ft->oob.comments; + fprintf(output, "Comments : \n"); + do fprintf(output, "%s\n", *p); + while (*++p); + } + else fprintf(output, "Comment : '%s'\n", ft->oob.comments[0]); + } + fprintf(output, "\n"); +} + +static void report_file_info(file_t * f) +{ + if (sox_globals.verbosity > 2) + display_file_info(f->ft, f, sox_true); +} + +static void progress_to_next_input_file(file_t * f, sox_effect_t * effp) +{ + if (user_skip) { + user_skip = sox_false; + fprintf(stderr, "\nSkipped (Ctrl-C twice to quit).\n"); + } + read_wide_samples = 0; + input_wide_samples = f->ft->signal.length / f->ft->signal.channels; + if (show_progress && (sox_globals.verbosity < 3 || + (is_serial(combine_method) && input_count > 1))) + display_file_info(f->ft, f, sox_false); + if (f->volume == HUGE_VAL) + f->volume = 1; + if (f->replay_gain != HUGE_VAL) + f->volume *= pow(10.0, f->replay_gain / 20); + if (effp && f->volume != floor(f->volume)) + effp->out_signal.precision = SOX_SAMPLE_PRECISION; + f->ft->sox_errno = errno = 0; +} + +/* Read up to max `wide' samples. A wide sample contains one sample per channel + * from the input audio. */ +static size_t sox_read_wide(sox_format_t * ft, sox_sample_t * buf, size_t max) +{ + size_t len = max / combiner_signal.channels; + len = sox_read(ft, buf, len * ft->signal.channels) / ft->signal.channels; + if (!len && ft->sox_errno) + lsx_fail("`%s' %s: %s", + ft->filename, ft->sox_errstr, sox_strerror(ft->sox_errno)); + return len; +} + +static void balance_input(sox_sample_t * buf, size_t ws, file_t * f) +{ + size_t s = ws * f->ft->signal.channels; + + if (f->volume != 1) while (s--) { + double d = f->volume * *buf; + *buf++ = SOX_ROUND_CLIP_COUNT(d, f->volume_clips); + } +} + +/* The input combiner: contains one sample buffer per input file, but only + * needed if is_parallel(combine_method) */ +typedef struct { + sox_sample_t * * ibuf; + size_t * ilen; +} input_combiner_t; + +static int combiner_start(sox_effect_t *effp) +{ + input_combiner_t * z = (input_combiner_t *) effp->priv; + uint64_t ws; + size_t i; + + if (is_serial(combine_method)) + progress_to_next_input_file(files[current_input], effp); + else { + ws = 0; + z->ibuf = lsx_malloc(input_count * sizeof(*z->ibuf)); + for (i = 0; i < input_count; i++) { + z->ibuf[i] = lsx_malloc(sox_globals.bufsiz * sizeof(sox_sample_t)); + progress_to_next_input_file(files[i], effp); + ws = max(ws, input_wide_samples); + } + input_wide_samples = ws; /* Output length is that of longest input file. */ + } + z->ilen = lsx_malloc(input_count * sizeof(*z->ilen)); + return SOX_SUCCESS; +} + +static sox_bool can_segue(size_t i) +{ + return + files[i]->ft->signal.channels == files[i - 1]->ft->signal.channels && + files[i]->ft->signal.rate == files[i - 1]->ft->signal.rate; +} + +static int combiner_drain(sox_effect_t *effp, sox_sample_t * obuf, size_t * osamp) +{ + input_combiner_t * z = (input_combiner_t *) effp->priv; + size_t ws, s, i; + size_t olen = 0; + + if (is_serial(combine_method)) { + while (sox_true) { + if (!user_skip) + olen = sox_read_wide(files[current_input]->ft, obuf, *osamp); + if (olen == 0) { /* If EOF, go to the next input file. */ + if (++current_input < input_count) { + if (combine_method == sox_sequence && !can_segue(current_input)) + break; + progress_to_next_input_file(files[current_input], NULL); + continue; + } + } + balance_input(obuf, olen, files[current_input]); + break; + } /* while */ + } /* is_serial */ else { /* else is_parallel() */ + sox_sample_t * p = obuf; + for (i = 0; i < input_count; ++i) { + z->ilen[i] = sox_read_wide(files[i]->ft, z->ibuf[i], *osamp); + balance_input(z->ibuf[i], z->ilen[i], files[i]); + olen = max(olen, z->ilen[i]); + } + for (ws = 0; ws < olen; ++ws) { /* wide samples */ + if (combine_method == sox_mix || combine_method == sox_mix_power) { + for (s = 0; s < effp->in_signal.channels; ++s, ++p) { /* sum samples */ + *p = 0; + for (i = 0; i < input_count; ++i) + if (ws < z->ilen[i] && s < files[i]->ft->signal.channels) { + /* Cast to double prevents integer overflow */ + double sample = *p + (double)z->ibuf[i][ws * files[i]->ft->signal.channels + s]; + *p = SOX_ROUND_CLIP_COUNT(sample, mixing_clips); + } + } + } /* sox_mix */ else if (combine_method == sox_multiply) { + for (s = 0; s < effp->in_signal.channels; ++s, ++p) { /* multiply samples */ + i = 0; + *p = ws < z->ilen[i] && s < files[i]->ft->signal.channels? + z->ibuf[i][ws * files[i]->ft->signal.channels + s] : 0; + for (++i; i < input_count; ++i) { + double sample = *p * (-1. / SOX_SAMPLE_MIN) * (ws < z->ilen[i] && s < files[i]->ft->signal.channels? z->ibuf[i][ws * files[i]->ft->signal.channels + s] : 0); + *p = SOX_ROUND_CLIP_COUNT(sample, mixing_clips); + } + } + } /* sox_multiply */ else { /* sox_merge: like a multi-track recorder */ + for (i = 0; i < input_count; ++i) + for (s = 0; s < files[i]->ft->signal.channels; ++s) + *p++ = (ws < z->ilen[i]) * z->ibuf[i][ws * files[i]->ft->signal.channels + s]; + } /* sox_merge */ + } /* wide samples */ + } /* is_parallel */ + read_wide_samples += olen; + olen *= effp->in_signal.channels; + *osamp = olen; + + input_eof = olen ? sox_false : sox_true; + + if (input_eof && is_parallel(combine_method)) + current_input += input_count; + + return olen? SOX_SUCCESS : SOX_EOF; +} + +static int combiner_stop(sox_effect_t *effp) +{ + input_combiner_t * z = (input_combiner_t *) effp->priv; + size_t i; + + if (is_parallel(combine_method)) { + /* Free input buffers now that they are not used */ + for (i = 0; i < input_count; i++) + free(z->ibuf[i]); + free(z->ibuf); + } + free(z->ilen); + + return SOX_SUCCESS; +} + +static sox_effect_handler_t const * input_combiner_effect_fn(void) +{ + static sox_effect_handler_t handler = { "input", 0, SOX_EFF_MCHAN | + SOX_EFF_MODIFY, 0, combiner_start, 0, combiner_drain, + combiner_stop, 0, sizeof(input_combiner_t) + }; + return &handler; +} + +static int ostart(sox_effect_t *effp) +{ + unsigned prec = effp->out_signal.precision; + if (effp->in_signal.mult && effp->in_signal.precision > prec) + *effp->in_signal.mult *= 1 - (1 << (31 - prec)) * (1. / SOX_SAMPLE_MAX); + return SOX_SUCCESS; +} + +static int output_flow(sox_effect_t *effp, sox_sample_t const * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + size_t len; + + (void)effp, (void)obuf; + if (show_progress) for (len = 0; len < *isamp; len += effp->in_signal.channels) { + omax[0] = max(omax[0], ibuf[len]); + omin[0] = min(omin[0], ibuf[len]); + if (effp->in_signal.channels > 1) { + omax[1] = max(omax[1], ibuf[len + 1]); + omin[1] = min(omin[1], ibuf[len + 1]); + } + else { + omax[1] = omax[0]; + omin[1] = omin[0]; + } + } + *osamp = 0; + len = *isamp? sox_write(ofile->ft, ibuf, *isamp) : 0; + output_samples += len / ofile->ft->signal.channels; + output_eof = (len != *isamp) ? sox_true: sox_false; + if (len != *isamp) { + if (ofile->ft->sox_errno) + lsx_fail("`%s' %s: %s", ofile->ft->filename, + ofile->ft->sox_errstr, sox_strerror(ofile->ft->sox_errno)); + return SOX_EOF; + } + return SOX_SUCCESS; +} + +static sox_effect_handler_t const * output_effect_fn(void) +{ + static sox_effect_handler_t handler = {"output", 0, SOX_EFF_MCHAN | + SOX_EFF_MODIFY | SOX_EFF_PREC, NULL, ostart, output_flow, NULL, NULL, NULL, 0 + }; + return &handler; +} + +static void auto_effect(sox_effects_chain_t *, char const *, int, char **, + sox_signalinfo_t *, int *); + +static int add_effect(sox_effects_chain_t * chain, sox_effect_t * effp, + sox_signalinfo_t * in, sox_signalinfo_t const * out, int * guard) { + int no_guard = -1; + switch (*guard) { + case 0: if (!(effp->handler.flags & SOX_EFF_GAIN)) { + char * arg = "-h"; + auto_effect(chain, "gain", 1, &arg, in, &no_guard); + ++*guard; + } + break; + case 1: if (effp->handler.flags & SOX_EFF_GAIN) { + char * arg = "-r"; + auto_effect(chain, "gain", 1, &arg, in, &no_guard); + --*guard; + } + break; + case 2: if (!(effp->handler.flags & SOX_EFF_MODIFY)) { + lsx_warn("%s: effects that modify audio should not follow dither", + effp->handler.name); + } + break; + } + return sox_add_effect(chain, effp, in, out); +} + +static void auto_effect(sox_effects_chain_t *chain, char const *name, int argc, + char *argv[], sox_signalinfo_t *signal, int * guard) +{ + sox_effect_t * effp; + + effp = sox_create_effect(sox_find_effect(name)); /* Should always succeed. */ + + if (sox_effect_options(effp, argc, argv) == SOX_EOF) + exit(1); /* The failing effect should have displayed an error message */ + + if (add_effect(chain, effp, signal, &ofile->ft->signal, guard) != SOX_SUCCESS) + exit(2); /* The effects chain should have displayed an error message */ + free(effp); +} + +/* add_eff_chain() - NOTE: this only adds memory for one + * additional effects chain beyond value of eff_chain_count. It + * does not unconditionally increase size of effects chain. + */ +static void add_eff_chain(void) +{ + lsx_revalloc(user_effargs, eff_chain_count+1); + user_effargs[eff_chain_count] = lsx_malloc(sizeof(**user_effargs)); + + lsx_revalloc(user_effargs_size, eff_chain_count+1); + user_effargs_size[eff_chain_count] = 0; + lsx_revalloc(nuser_effects, eff_chain_count+1); + nuser_effects[eff_chain_count] = 0; +} /* add_eff_chain */ + +/* free_eff_chain() - the inverse of add_eff_chain(). Frees + * one effects chain (with index eff_chain_count) such that + * there are eff_chain_count left, the last having index + * eff_chain_count-1. + */ +static void free_eff_chain(void) +{ + size_t j; + int k; + for (j = 0; j < nuser_effects[eff_chain_count]; j++) + { + free(user_effargs[eff_chain_count][j].name); + user_effargs[eff_chain_count][j].name = NULL; + for (k = 0; k < user_effargs[eff_chain_count][j].argc; k++) + { + free(user_effargs[eff_chain_count][j].argv[k]); + user_effargs[eff_chain_count][j].argv[k] = NULL; + } + user_effargs[eff_chain_count][j].argc = 0; + free(user_effargs[eff_chain_count][j].argv); + user_effargs[eff_chain_count][j].argv = NULL; + user_effargs[eff_chain_count][j].argv_size = 0; + } + nuser_effects[eff_chain_count] = 0; + free(user_effargs[eff_chain_count]); +} /* free_eff_chain */ + +static void delete_eff_chains(void) +{ + while (eff_chain_count > 0) { + eff_chain_count--; + free_eff_chain(); + } + free(user_effargs); + free(user_effargs_size); + free(nuser_effects); + user_effargs = NULL; + user_effargs_size = NULL; + nuser_effects = NULL; +} /* delete_eff_chains */ + +static sox_bool is_pseudo_effect(const char *s) +{ + if (s) + if (strcmp("newfile", s) == 0 || + strcmp("restart", s) == 0 || + strcmp(":", s) == 0) + return sox_true; + return sox_false; +} /* is_pseudo_effect */ + +static void parse_effects(int argc, char ** argv) +{ + while (optstate.ind < argc) { + size_t eff_offset, j; + int newline_mode = 0; + + eff_offset = nuser_effects[eff_chain_count]; + if (eff_offset == user_effargs_size[eff_chain_count]) { + size_t i = user_effargs_size[eff_chain_count]; + user_effargs_size[eff_chain_count] += EFFARGS_STEP; + lsx_revalloc(user_effargs[eff_chain_count], user_effargs_size[eff_chain_count]); + for (; i < user_effargs_size[eff_chain_count]; i++) { + user_effargs[eff_chain_count][i].argv = NULL; + user_effargs[eff_chain_count][i].argv_size = 0; + } + } + + /* pseudo-effect ":" is used to create a new effects chain */ + if (strcmp(argv[optstate.ind], ":") == 0) + { + /* Only create a new chain if current one has effects. + * Error checking will be done when loop is restarted. + */ + if (nuser_effects[eff_chain_count] != 0) + { + eff_chain_count++; + add_eff_chain(); + } + optstate.ind++; + continue; + } + + if (strcmp(argv[optstate.ind], "newfile") == 0) + { + /* Start a new effect chain for newfile if user doesn't + * manually do it. Restart loop without advancing + * optstate.ind to do error checking. + */ + if (nuser_effects[eff_chain_count] != 0) + { + eff_chain_count++; + add_eff_chain(); + continue; + } + newline_mode = 1; + output_method = sox_multiple; + } + else if (strcmp(argv[optstate.ind], "restart") == 0) + { + /* Start a new effect chain for restart if user doesn't + * manually do it. Restart loop without advancing + * optstate.ind to do error checking. + */ + if (nuser_effects[eff_chain_count] != 0) + { + eff_chain_count++; + add_eff_chain(); + continue; + } + newline_mode = 1; + } + + /* Name should always be correct! */ + user_effargs[eff_chain_count][eff_offset].name = lsx_strdup(argv[optstate.ind]); + optstate.ind++; + for (j = 0; j < (size_t)(argc - optstate.ind) && !sox_find_effect(argv[optstate.ind + j]) && + !is_pseudo_effect(argv[optstate.ind + j]); ++j) { + if (j >= user_effargs[eff_chain_count][eff_offset].argv_size) { + user_effargs[eff_chain_count][eff_offset].argv_size += EFFARGS_STEP; + lsx_revalloc(user_effargs[eff_chain_count][eff_offset].argv, + user_effargs[eff_chain_count][eff_offset].argv_size); + } + user_effargs[eff_chain_count][eff_offset].argv[j] = lsx_strdup(argv[optstate.ind + j]); + } + user_effargs[eff_chain_count][eff_offset].argc = j; + + optstate.ind += j; /* Skip past the effect arguments */ + nuser_effects[eff_chain_count]++; + if (newline_mode) + { + eff_chain_count++; + add_eff_chain(); + } + } +} /* parse_effects */ + +static char * * strtoargv(char * s, int * argc) +{ + sox_bool squote = sox_false; /* Single quote mode (') is in effect. */ + sox_bool dquote = sox_false; /* Double quote mode (") is in effect. */ + sox_bool esc = sox_false; /* Escape mode (\) is in effect. */ + char * t, * * argv = NULL; + + for (*argc = 0; *s;) { + for (; isspace(*s); ++s); /* Skip past any (more) white space. */ + if (*s) { /* Found an arg. */ + lsx_revalloc(argv, *argc + 1); + argv[(*argc)++] = s; /* Store pointer to start of arg. */ + /* Find the end of the arg: */ + for (t = s; *s && (esc || squote || dquote || !isspace(*s)); ++s) + if (!esc && !squote && *s == '"') + dquote = !dquote; /* Toggle double quote mode. */ + else if (!esc && !dquote && *s == '\'') + squote = !squote; /* Toggle single quote mode. */ + else if (!(esc = !esc && *s == '\\' && s[1] && + (!squote && (s[1] == '"' || !dquote)))) + *t++ = *s; /* Only copy if not an active ', ", or \ */ + s = *s ? s + 1 : s; /* Skip the 1st white space char. */ + *t = '\0'; /* Terminate the arg. */ + } + } + return argv; +} /* strtoargv */ + +static void read_user_effects(char const *filename) +{ + FILE *file = fopen(filename, "r"); + const size_t buffer_size_step = 1024; + size_t buffer_size = buffer_size_step; + char *s = lsx_malloc(buffer_size); /* buffer for one input line */ + int pos = 0; + int argc; + char * * argv; + sox_bool last_was_colon = sox_false; /* last line read consisted of ":" only */ + + /* Free any command line options and then re-initialize to + * starter user_effargs. + */ + delete_eff_chains(); + current_eff_chain = 0; + add_eff_chain(); + + if (!file) { + lsx_fail("Cannot open effects file `%s': %s", filename, strerror(errno)); + exit(1); + } + + lsx_report("Reading effects from file `%s'", filename); + + while(fgets(s + pos, (int) (buffer_size - pos), file)) { + int len = strlen(s + pos); + if (len && s[pos+len-1] == '\n') + s[pos+len-1] = '\0', pos = 0; /* we've read a complete line */ + else if (len == (int)(buffer_size - pos - 1)) { + /* line was longer than buffer size */ + buffer_size += buffer_size_step; + s = lsx_realloc(s, buffer_size); + pos += len; + continue; /* read next part */ + } else { + /* something strange happened; the file might have ended + without a '\n', might contain '\0', or a read error + occurred */ + if (ferror(file)) + break; /* use error reporting after loop */ + lsx_fail("Error reading effects file `%s' (not a text file?)", filename); + exit(1); + } + + last_was_colon = sox_false; + + argv = strtoargv(s, &argc); + + if (argv && argc == 1 && strcmp(argv[0], ":") == 0) + last_was_colon = sox_true; + + if (argv) { + /* Make sure first option is an effect name. */ + if (!sox_find_effect(argv[0]) && !is_pseudo_effect(argv[0])) + { + lsx_fail("Cannot find an effect called `%s'.", argv[0]); + exit(1); + } + + /* parse_effects normally parses options from command line. + * Reset opt index so it thinks its back at beginning of + * main()'s argv[]. + */ + optstate.ind = 0; + parse_effects(argc, argv); + + /* Advance to next effect but only if current chain has been + * filled in. This recovers from side affects of pseudo-effects. + */ + if (nuser_effects[eff_chain_count] > 0) { + eff_chain_count++; + add_eff_chain(); + } + + free(argv); + } + } + if (ferror(file)) { + lsx_fail("Error reading effects file `%s': %s", filename, strerror(errno)); + exit(1); + } + fclose(file); + free(s); + + if (last_was_colon || eff_chain_count == 0) { + /* user explicitly wanted an empty last effects chain, + or didn't specify any chains at all */ + eff_chain_count++; + } else { + /* there's one unneeded effects chain */ + free_eff_chain(); + } +} /* read_user_effects */ + +/* Creates users effects and passes in user specified options. + * This is done without putting anything into the effects chain + * because an effect may set the effp->in_format and we may want + * to copy that back into the input/combiner before opening and + * inserting it. + * Similarly, we may want to use effp->out_format to override the + * default values of output file before we open it. + * To keep things simple, we create all user effects. Later, when + * we add them, some may already be in the chain and we will need to free + * them. + */ +static void create_user_effects(void) +{ + size_t i; + sox_effect_t *effp; + size_t num_effects = nuser_effects[current_eff_chain]; + + /* extend user_efftab, if needed */ + if (user_efftab_size < num_effects) { + user_efftab_size = num_effects; + lsx_revalloc(user_efftab, num_effects); + } + + for (i = 0; i < num_effects; i++) { + effp = sox_create_effect(sox_find_effect(user_effargs[current_eff_chain][i].name)); + + if (effp->handler.flags & SOX_EFF_DEPRECATED) + lsx_warn("effect `%s' is deprecated; see sox(1) for an alternative", + effp->handler.name); + else if (effp->handler.flags & SOX_EFF_ALPHA) + lsx_warn("effect `%s' is experimental/incomplete", effp->handler.name); + else if (effp->handler.flags & SOX_EFF_INTERNAL) { + lsx_fail("`%s' is a libSoX-only effect", effp->handler.name); + exit(1); + } + + /* The failing effect should have displayed an error message */ + if (sox_effect_options(effp, user_effargs[current_eff_chain][i].argc, + user_effargs[current_eff_chain][i].argv) == SOX_EOF) + exit(1); + + user_efftab[i] = effp; + } +} + +/* Add all user effects to the chain. If the output effect's rate or + * channel count do not match the end of the effects chain then + * insert effects to correct this. + * + * This can be called with the input effect already in the effects + * chain from a previous run. Also, it use a pre-existing + * output effect if its been saved into save_output_eff. + */ +static void add_effects(sox_effects_chain_t *chain) +{ + sox_signalinfo_t signal = combiner_signal; + int guard = is_guarded - 1; + size_t i; + sox_effect_t * effp; + char * rate_arg = is_player ? (play_rate_arg ? play_rate_arg : "-l") : NULL; + + /* 1st `effect' in the chain is the input combiner_signal. + * add it only if its not there from a previous run. */ + if (chain->length == 0) { + effp = sox_create_effect(input_combiner_effect_fn()); + sox_add_effect(chain, effp, &signal, &ofile->ft->signal); + free(effp); + } + + /* Add user specified effects; stop before `dither' */ + for (i = 0; i < nuser_effects[current_eff_chain] && + strcmp(user_efftab[i]->handler.name, "dither"); i++) { + if (add_effect(chain, user_efftab[i], &signal, &ofile->ft->signal, + &guard) != SOX_SUCCESS) + exit(2); /* Effects chain should have displayed an error message */ + free(user_efftab[i]); + } + + /* Add auto effects if still needed at this point */ + if (signal.channels < ofile->ft->signal.channels && + signal.rate != ofile->ft->signal.rate) + auto_effect(chain, "rate", rate_arg != NULL, &rate_arg, &signal, &guard); + if (signal.channels != ofile->ft->signal.channels) + auto_effect(chain, "channels", 0, NULL, &signal, &guard); + if (signal.rate != ofile->ft->signal.rate) + auto_effect(chain, "rate", rate_arg != NULL, &rate_arg, &signal, &guard); + + if (is_guarded && (do_guarded_norm || !(signal.mult && *signal.mult == 1))) { + char *args[2]; + int no_guard = -1; + args[0] = do_guarded_norm? "-nh" : guard? "-rh" : "-h"; + args[1] = norm_level; + auto_effect(chain, "gain", norm_level ? 2 : 1, args, &signal, &no_guard); + guard = 1; + } + + if (i == nuser_effects[current_eff_chain] && !no_dither && signal.precision > + ofile->ft->signal.precision && ofile->ft->signal.precision < 24) + auto_effect(chain, "dither", 0, NULL, &signal, &guard); + + /* Add user specified effects from `dither' onwards */ + for (; i < nuser_effects[current_eff_chain]; i++, guard = 2) { + if (add_effect(chain, user_efftab[i], &signal, &ofile->ft->signal, + &guard) != SOX_SUCCESS) + exit(2); /* Effects chain should have displayed an error message */ + free(user_efftab[i]); + } + + if (!save_output_eff) + { + /* Last `effect' in the chain is the output file */ + effp = sox_create_effect(output_effect_fn()); + if (sox_add_effect(chain, effp, &signal, &ofile->ft->signal) != SOX_SUCCESS) + exit(2); + free(effp); + } + else + { + sox_push_effect_last(chain, save_output_eff); + save_output_eff = NULL; + } + + for (i = 0; i < chain->length; ++i) { + char const * format = sox_globals.verbosity > 3? + "effects chain: %-10s %7gHz %2u channels %7s %2u bits %s" : + "effects chain: %-10s %7gHz %2u channels"; + sox_effect_t const * effp = &chain->effects[i][0]; + lsx_report(format, effp->handler.name, effp->out_signal.rate, + effp->out_signal.channels, + (effp->handler.flags & SOX_EFF_MCHAN)? "(multi)" : "", + effp->out_signal.precision, + effp->out_signal.length != SOX_UNKNOWN_LEN ? + str_time(effp->out_signal.length/effp->out_signal.channels/effp->out_signal.rate) : + "unknown length" + ); + } +} + +static int advance_eff_chain(void) +{ + sox_bool reuse_output = sox_true; + + very_first_effchain = sox_false; + + /* If input file reached EOF then delete all effects in current + * chain and restart the current chain. + * + * This is only used with sox_sequence combine mode even though + * we do not specifically check for that method. + */ + if (input_eof) + sox_delete_effects(effects_chain); + else + { + /* If user requested to restart this effect chain then + * do not advance to next. Usually, this is because + * an option to current effect was changed. + */ + if (user_restart_eff) + user_restart_eff = sox_false; + /* Effect chain stopped so advance to next effect chain but + * quite if no more chains exist. + */ + else if (++current_eff_chain >= eff_chain_count) + return SOX_EOF; + + while (nuser_effects[current_eff_chain] == 1 && + is_pseudo_effect(user_effargs[current_eff_chain][0].name)) + { + if (strcmp("newfile", user_effargs[current_eff_chain][0].name) == 0) + { + if (++current_eff_chain >= eff_chain_count) + return SOX_EOF; + reuse_output = sox_false; + } + else if (strcmp("restart", user_effargs[current_eff_chain][0].name) == 0) + current_eff_chain = 0; + } + + if (reuse_output) + save_output_eff = sox_pop_effect_last(effects_chain); + + while (effects_chain->length > 1) + sox_delete_effect_last(effects_chain); + } + return SOX_SUCCESS; +} /* advance_eff_chain */ + +static uint64_t total_clips(void) +{ + size_t i; + uint64_t clips = 0; + for (i = 0; i < file_count; ++i) + clips += files[i]->ft->clips + files[i]->volume_clips; + return clips + mixing_clips + sox_effects_clips(effects_chain); +} + +static sox_bool since(struct timeval * then, double secs, sox_bool always_reset) +{ + sox_bool ret; + struct timeval now; + time_t d; + gettimeofday(&now, NULL); + d = now.tv_sec - then->tv_sec; + ret = d > ceil(secs) || now.tv_usec - then->tv_usec + d * TIME_FRAC >= secs * TIME_FRAC; + if (ret || always_reset) + *then = now; + return ret; +} + +static int termwidth = 80; + +#ifdef TIOCGWINSZ +static void get_termwidth(int s) +{ + struct winsize w; + + if (!ioctl(2, TIOCGWINSZ, &w)) + termwidth = w.ws_col; +} +#endif + +#define MIN_HEADROOM 6. +static double min_headroom = MIN_HEADROOM; + +static char const * vu(unsigned channel) +{ + static struct timeval then; + static char const * const text[][2] = { + /* White: 2dB steps */ + {"", ""}, {"-", "-"}, {"=", "="}, {"-=", "=-"}, + {"==", "=="}, {"-==", "==-"}, {"===", "==="}, {"-===", "===-"}, + {"====", "===="}, {"-====", "====-"}, {"=====", "====="}, + {"-=====", "=====-"}, {"======", "======"}, + /* Red: 1dB steps */ + {"!=====", "=====!"}, + }; + int const red = 1, white = array_length(text) - red; + double const MAX = SOX_SAMPLE_MAX, MIN = SOX_SAMPLE_MIN; + double linear = max(omax[channel] / MAX, omin[channel] / MIN); + double dB = linear_to_dB(linear); + int vu_dB = linear? floor(2 * white + red + dB) : 0; + int index = vu_dB < 2 * white? max(vu_dB / 2, 0) : min(vu_dB - white, red + white - 1); + omax[channel] = omin[channel] = 0; + if (-dB < min_headroom) { + gettimeofday(&then, NULL); + min_headroom = -dB; + } + else if (since(&then, 3., sox_false)) + min_headroom = -dB; + + return text[index][channel]; +} + +static char * headroom(void) +{ + if (min_headroom < MIN_HEADROOM) { + static char buff[16]; + unsigned h = (unsigned)(min_headroom * 10); + snprintf(buff, sizeof(buff), "Hd:%u.%u", h /10, h % 10); + return buff; + } + return " "; +} + +static void display_status(sox_bool all_done) +{ + static struct timeval then; + if (!show_progress) + return; + if (all_done || since(&then, .1, sox_false)) { + double read_time = (double)read_wide_samples / combiner_signal.rate; + double left_time = 0, in_time = 0, percentage = 0; + char buf[128]; + + if (input_wide_samples) { + in_time = (double)input_wide_samples / combiner_signal.rate; + left_time = max(in_time - read_time, 0); + percentage = max(100. * read_wide_samples / input_wide_samples, 0); + } + snprintf(buf, min(termwidth + 2, sizeof(buf)), + "\rIn:%-5s %s [%s] Out:%-5s [%6s|%-6s] %s Clip:%-5s", + lsx_sigfigs3p(percentage), str_time(read_time), str_time(left_time), + lsx_sigfigs3((double)output_samples), + vu(0), vu(1), headroom(), lsx_sigfigs3((double)total_clips())); + fputs(buf, stderr); + } + if (all_done) + fputc('\n', stderr); +} + +#ifdef HAVE_TERMIOS_H +static int kbhit(void) +{ + struct timeval time_val = {0, 0}; + fd_set fdset; + + FD_ZERO(&fdset); + FD_SET(fileno(stdin), &fdset); + select(fileno(stdin) + 1, &fdset, NULL, NULL, &time_val); + return FD_ISSET(fileno(stdin), &fdset); +} +#elif !defined(HAVE_CONIO_H) +#define kbhit() 0 +#endif + +static int update_status(sox_bool all_done, void * client_data) +{ + (void)client_data; + if (interactive) while (kbhit()) { + int LSX_UNUSED ch; +#ifdef HAVE_CONIO_H + ch = _getch(); +#else + ch = getchar(); +#endif + +#ifdef MORE_INTERACTIVE + if (files[current_input]->ft->handler.seek && + files[current_input]->ft->seekable) + { + if (ch == '>') + { + uint64_t jump = files[current_input]->ft->signal.rate*30; /* 30 sec. */ + if (input_wide_samples == 0 || + read_wide_samples+jump < input_wide_samples) { + read_wide_samples += jump; + sox_seek(files[current_input]->ft, read_wide_samples, + SOX_SEEK_SET); + /* FIXME: Do something if seek fails. */ + } + } + if (ch == '<') + { + uint64_t jump = files[current_input]->ft->signal.rate*30; /* 30 sec. */ + read_wide_samples = jump < read_wide_samples ? + read_wide_samples-jump : 0; + sox_seek(files[current_input]->ft, read_wide_samples, + SOX_SEEK_SET); + /* FIXME: Do something if seek fails. */ + } + } + if (ch == 'R') + { + /* Not very useful, eh! Sample though of the place you + * could change the value to effects options + * like vol or speed or remix. + * Modify values in user_effargs[current_eff_chain][xxx] + * and then chain will be drain()ed and restarted whence + * this function is existed. + */ + user_restart_eff = sox_true; + } +#endif + } + + display_status(all_done || user_abort); + return (user_abort || user_restart_eff) ? SOX_EOF : SOX_SUCCESS; +} + +static void optimize_trim(void) +{ + /* Speed hack. If the "trim" effect is the first effect then peek inside its + * "effect descriptor" and see what the start location is. This has to be + * done after its start() is called to have the correct location. Also, only + * do this when only working with one input file. This is because the logic + * to do it for multiple files is complex and probably never used. The same + * is true for a restarted or additional effects chain (relative positioning + * within the file and possible samples still buffered in the input effect + * would have to be taken into account). This hack is a huge time savings + * when trimming gigs of audio data into managable chunks. */ + if (input_count == 1 && very_first_effchain && effects_chain->length > 1 && + strcmp(effects_chain->effects[1][0].handler.name, "trim") == 0) { + if (files[0]->ft->handler.seek && files[0]->ft->seekable){ + uint64_t offset = sox_trim_get_start(&effects_chain->effects[1][0]); + if (offset && sox_seek(files[0]->ft, offset, SOX_SEEK_SET) == SOX_SUCCESS) { + read_wide_samples = offset / files[0]->ft->signal.channels; + /* Assuming a failed seek stayed where it was. If the seek worked then + * reset the start location of trim so that it thinks user didn't + * request a skip. */ + sox_trim_clear_start(&effects_chain->effects[1][0]); + lsx_debug("optimize_trim successful"); + } + } + } +} + +static sox_bool overwrite_permitted(char const * filename) +{ + char c; + + if (!no_clobber) { + lsx_report("Overwriting `%s'", filename); + return sox_true; + } + lsx_warn("Output file `%s' already exists", filename); + if (!stdin_is_a_tty) + return sox_false; + do fprintf(stderr, "%s sox: overwrite `%s' (y/n)? ", myname, filename); + while (scanf(" %c%*[^\n]", &c) != 1 || !strchr("yYnN", c)); + return c == 'y' || c == 'Y'; +} + +static char *fndup_with_count(const char *filename, size_t count) +{ + char *expand_fn, *efn; + const char *fn, *ext, *end; + sox_bool found_marker = sox_false; + + fn = filename; + + efn = expand_fn = lsx_malloc((size_t)FILENAME_MAX); + + /* Find extension in case user didn't specify a substitution + * marker. + */ + end = ext = filename + strlen(filename); + while (ext > filename && *ext != '.') + ext--; + + /* In case extension not found, point back to end of string to do less + * copying later. + */ + if (*ext != '.') + ext = end; + + while (fn < end) + { + /* Look for %n. If found, replace with count. Can specify an + * option width of 1-9. + */ + if (*fn == '%') + { + char width = 0; + fn++; + if (*fn >= '1' && *fn <= '9') + { + width = *fn++; + } + if (*fn == 'n') + { + char format[5]; + + found_marker = sox_true; + + if (width) + { + sprintf(format, "%%0%cd", width); + } + else + { + strcpy(format, "%02d"); + } + + efn += sprintf(efn, format, count); + fn++; + } + else + *efn++ = *fn++; + } + else + *efn++ = *fn++; + } + + *efn = 0; + + /* If user didn't tell us what to do then default to putting + * the count right before file extension. + */ + if (!found_marker) + { + efn -= strlen (ext); + + sprintf(efn, "%03lu", (unsigned long)count); + efn = efn + 3; + strcat(efn, ext); + } + + return expand_fn; +} + +static void open_output_file(void) +{ + double factor; + int i; + sox_comments_t p = ofile->oob.comments; + sox_oob_t oob = files[0]->ft->oob; + char *expand_fn; + + /* Skip opening file if we are not recreating output effect */ + if (save_output_eff) + return; + + oob.comments = sox_copy_comments(files[0]->ft->oob.comments); + + if (!oob.comments && !p) + sox_append_comment(&oob.comments, "Processed by SoX"); + else if (p) { + if (!(*p)[0]) { + sox_delete_comments(&oob.comments); + ++p; + } + while (*p) + sox_append_comment(&oob.comments, *p++); + } + + /* Copy loop info, resizing appropriately it's in samples, so # channels + * don't matter FIXME: This doesn't work for multi-file processing or effects + * that change file length. */ + factor = (double) ofile->signal.rate / combiner_signal.rate; + for (i = 0; i < SOX_MAX_NLOOPS; i++) { + oob.loops[i].start = oob.loops[i].start * factor; + oob.loops[i].length = oob.loops[i].length * factor; + } + + if (output_method == sox_multiple) + expand_fn = fndup_with_count(ofile->filename, ++output_count); + else + expand_fn = lsx_strdup(ofile->filename); + ofile->ft = sox_open_write(expand_fn, &ofile->signal, &ofile->encoding, + ofile->filetype, &oob, overwrite_permitted); + sox_delete_comments(&oob.comments); + free(expand_fn); + + if (!ofile->ft) + /* sox_open_write() will call lsx_warn for most errors. + * Rely on that printing something. */ + exit(2); + + /* If whether to enable the progress display (similar to that of ogg123) has + * not been specified by the user, auto turn on when outputting to an audio + * device: */ + if (show_progress == sox_option_default) + show_progress = (ofile->ft->handler.flags & SOX_FILE_DEVICE) != 0 && + (ofile->ft->handler.flags & SOX_FILE_PHONY) == 0; + + report_file_info(ofile); +} + +static void setsig(int sig, void (*handler)(int)) +{ +#ifdef HAVE_SIGACTION + struct sigaction sa; + + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + sigaction(sig, &sa, NULL); +#else + signal(sig, handler); +#endif +} + +static void sigint(int s) +{ + static struct timeval then; + if (input_count > 1 && show_progress && s == SIGINT && + is_serial(combine_method) && since(&then, 1.0, sox_true)) + { + setsig(SIGINT, sigint); + user_skip = sox_true; + } + else user_abort = sox_true; +} + +static void calculate_combiner_signal_parameters(void) +{ + size_t i; + + /* If user didn't specify # of channels then see if an effect + * is specifying them. This is of most use currently with the + * synth effect were user can use null input handler and specify + * channel counts directly in effect. Forcing to use -c with + * -n isn't as convenient. + */ + for (i = 0; i < input_count; i++) { + size_t j; + for (j =0; j < nuser_effects[current_eff_chain] && + !files[i]->ft->signal.channels; ++j) + files[i]->ft->signal.channels = user_efftab[j]->in_signal.channels; + /* For historical reasons, default to one channel if not specified. */ + if (!files[i]->ft->signal.channels) + files[i]->ft->signal.channels = 1; + } + + /* Set the combiner output signal attributes to those of the 1st/next input + * file. If we are in sox_sequence mode then we don't need to check the + * attributes of the other inputs, otherwise, it is mandatory that all input + * files have the same sample rate, and for sox_concatenate, it is mandatory + * that they have the same number of channels, otherwise, the number of + * channels at the output of the combiner is calculated according to the + * combiner mode. */ + combiner_signal = files[current_input]->ft->signal; + if (combine_method == sox_sequence) { + /* Report all input files; do this only the 1st time process() is called: */ + if (!current_input) for (i = 0; i < input_count; i++) + report_file_info(files[i]); + combiner_signal.length = SOX_UNKNOWN_LEN; + } else { + size_t total_channels = 0; + size_t min_channels = SOX_SIZE_MAX; + size_t max_channels = 0; + size_t min_rate = SOX_SIZE_MAX; + size_t max_rate = 0; + uint64_t total_length = 0, max_length_ws = 0; + + /* Report all input files and gather info on differing rates & numbers of + * channels, and on the resulting output audio length: */ + for (i = 0; i < input_count; i++) { + report_file_info(files[i]); + total_channels += files[i]->ft->signal.channels; + min_channels = min(min_channels, files[i]->ft->signal.channels); + max_channels = max(max_channels, files[i]->ft->signal.channels); + min_rate = min(min_rate , files[i]->ft->signal.rate); + max_rate = max(max_rate , files[i]->ft->signal.rate); + max_length_ws = files[i]->ft->signal.length ? + max(max_length_ws, files[i]->ft->signal.length / files[i]->ft->signal.channels) : + SOX_UNKNOWN_LEN; + if (total_length != SOX_UNKNOWN_LEN && files[i]->ft->signal.length) + total_length += files[i]->ft->signal.length; + else + total_length = SOX_UNKNOWN_LEN; + } + + /* Check for invalid/unusual rate or channel combinations: */ + if (min_rate != max_rate) + lsx_fail("Input files must have the same sample-rate"); + /* Don't exit quite yet; give the user any other message 1st */ + if (min_channels != max_channels) { + if (combine_method == sox_concatenate) { + lsx_fail("Input files must have the same # channels"); + exit(1); + } else if (combine_method != sox_merge) + lsx_warn("Input files don't have the same # channels"); + } + if (min_rate != max_rate) + exit(1); + + /* Store the calculated # of combined channels: */ + combiner_signal.channels = + combine_method == sox_merge? total_channels : max_channels; + + if (combine_method == sox_concatenate) + combiner_signal.length = total_length; + else if (is_parallel(combine_method)) + combiner_signal.length = max_length_ws != SOX_UNKNOWN_LEN ? + max_length_ws * combiner_signal.channels : SOX_UNKNOWN_LEN; + } +} /* calculate_combiner_signal_parameters */ + +static void calculate_output_signal_parameters(void) +{ + sox_bool known_length = combine_method != sox_sequence; + size_t i; + uint64_t olen = 0; + + /* Report all input files and gather info on differing rates & numbers of + * channels, and on the resulting output audio length: */ + for (i = 0; i < input_count; i++) { + known_length = known_length && files[i]->ft->signal.length != SOX_UNSPEC; + if (combine_method == sox_concatenate) + olen += files[i]->ft->signal.length / files[i]->ft->signal.channels; + else + olen = max(olen, files[i]->ft->signal.length / files[i]->ft->signal.channels); + } + + /* Determine the output file signal attributes; set from user options + * if given: */ + ofile->signal = ofile_signal_options; + + /* If no user option for output rate or # of channels, set from the last + * effect that sets these, or from the input combiner if there is none such */ + for (i = 0; i < nuser_effects[current_eff_chain] && !ofile->signal.rate; ++i) + ofile->signal.rate = user_efftab[nuser_effects[current_eff_chain] - 1 - i]->out_signal.rate; + for (i = 0; i < nuser_effects[current_eff_chain] && !ofile->signal.channels; ++i) + ofile->signal.channels = user_efftab[nuser_effects[current_eff_chain] - 1 - i]->out_signal.channels; + if (!ofile->signal.rate) + ofile->signal.rate = combiner_signal.rate; + if (!ofile->signal.channels) + ofile->signal.channels = combiner_signal.channels; + + /* FIXME: comment this: */ + ofile->signal.precision = combiner_signal.precision; + + /* If any given user effect modifies the audio length, then we assume that + * we don't know what the output length will be. FIXME: in most cases, + * an effect that modifies length will be able to determine by how much from + * its getopts parameters, so olen should be calculable. */ + for (i = 0; i < nuser_effects[current_eff_chain]; i++) + known_length = known_length && !(user_efftab[i]->handler.flags & SOX_EFF_LENGTH); + + if (!known_length) + olen = 0; + ofile->signal.length = (uint64_t)(olen * ofile->signal.channels * ofile->signal.rate / combiner_signal.rate + .5); +} + +static void set_combiner_and_output_encoding_parameters(void) +{ + /* The input encoding parameters passed to the effects chain are those of + * the first input file (for each segued block if sox_sequence):*/ + combiner_encoding = files[current_input]->ft->encoding; + + /* Determine the output file encoding attributes; set from user options + * if given: */ + ofile->encoding = ofile_encoding_options; + + /* Get unspecified output file encoding attributes from the input file and + * set the output file to the resultant encoding if this is supported by the + * output file type; if not, the output file handler should select an + * encoding suitable for the output signal and its precision. */ + { + sox_encodinginfo_t t = ofile->encoding; + if (!t.encoding) + t.encoding = combiner_encoding.encoding; + if (!t.bits_per_sample) + t.bits_per_sample = combiner_encoding.bits_per_sample; + if (sox_format_supports_encoding(ofile->filename, ofile->filetype, &t)) + ofile->encoding = t; + } +} + +static int process(void) +{ /* Input(s) -> Balancing -> Combiner -> Effects -> Output */ + int flow_status; + + create_user_effects(); + + calculate_combiner_signal_parameters(); + set_combiner_and_output_encoding_parameters(); + calculate_output_signal_parameters(); + open_output_file(); + + if (!effects_chain) + effects_chain = sox_create_effects_chain(&combiner_encoding, + &ofile->ft->encoding); + add_effects(effects_chain); + + if (very_first_effchain) + optimize_trim(); + +#if defined(HAVE_TERMIOS_H) || defined(HAVE_CONIO_H) + if (stdin_is_a_tty) { + if (show_progress && is_player && !interactive) { + lsx_debug("automatically entering interactive mode"); + interactive = sox_true; + } + } else if (interactive) { + /* User called for interactive mode, but ... */ + lsx_warn("Standard input has to be a terminal for interactive mode"); + interactive = sox_false; + } +#endif +#ifdef HAVE_TERMIOS_H + /* Prepare terminal for interactive mode and save the original termios + settings. Do this only once, otherwise the "original" settings won't + be original anymore after a second call to process() (next/restarted + effects chain). */ + if (interactive && !original_termios_saved) { + struct termios modified_termios; + + original_termios_saved = sox_true; + tcgetattr(fileno(stdin), &original_termios); + modified_termios = original_termios; + modified_termios.c_lflag &= ~(ICANON | ECHO); + modified_termios.c_cc[VMIN] = modified_termios.c_cc[VTIME] = 0; + tcsetattr(fileno(stdin), TCSANOW, &modified_termios); + } +#endif +#if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) + if (interactive) { + int fd = fileno(stdin); + int flags = fcntl(fd, F_GETFL); + if (flags == -1) { + lsx_warn("error getting flags on stdin descriptor: %s", strerror(errno)); + } else if (!(flags & O_NONBLOCK)) { + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) + lsx_warn("error setting non-blocking on stdin: %s", strerror(errno)); + } + } +#endif + +#ifdef TIOCGWINSZ + get_termwidth(0); +#ifdef SIGWINCH + setsig(SIGWINCH, get_termwidth); +#endif +#endif + + setsig(SIGTERM, sigint); /* Stop gracefully, as soon as we possibly can. */ + setsig(SIGINT , sigint); /* Either skip current input or behave as SIGTERM. */ + if (very_first_effchain) { + struct timeval now; + double d; + gettimeofday(&now, NULL); + d = now.tv_sec - load_timeofday.tv_sec + (now.tv_usec - load_timeofday.tv_usec) / TIME_FRAC; + lsx_debug("start-up time = %g", d); + } + flow_status = sox_flow_effects(effects_chain, update_status, NULL); + + /* Don't return SOX_EOF if + * 1) input reach EOF and there are more input files to process or + * 2) output didn't return EOF (disk full?) there are more + * effect chains. + * For case #2, something else must decide when to stop processing. + */ + if ((input_eof && current_input < input_count) || + (!output_eof && current_eff_chain < eff_chain_count)) + flow_status = SOX_SUCCESS; + + return flow_status; +} + +static void display_SoX_version(FILE * file) +{ +#if HAVE_SYS_UTSNAME_H + struct utsname uts; +#endif + const sox_version_info_t* info = sox_version_info(); + + fprintf(file, "%s: SoX v%s%s%s\n", + myname, + info->version, + info->version_extra ? "-" : "", + info->version_extra ? info->version_extra : ""); + + if (sox_globals.verbosity > 3) { + if (info->time) + fprintf(file, "time: %s\n", info->time); + if (info->distro) + fprintf(file, "issue: %s\n", info->distro); +#if HAVE_SYS_UTSNAME_H + if (!uname(&uts)) + fprintf(file, "uname: %s %s %s %s %s\n", uts.sysname, uts.nodename, + uts.release, uts.version, uts.machine); +#endif + if (info->compiler) + fprintf(file, "compiler: %s\n", info->compiler); + if (info->arch) + fprintf(file, "arch: %s\n", info->arch); + } +} + +static int strcmp_p(const void *p1, const void *p2) +{ + return strcmp(*(const char **)p1, *(const char **)p2); +} + +static void display_supported_formats(void) +{ + size_t i, formats; + char const * * format_list; + char const * const * names; + + sox_format_init(); + for (i = formats = 0; sox_format_fns[i].fn; ++i) { + char const * const *names = sox_format_fns[i].fn()->names; + while (*names++) + formats++; + } + format_list = lsx_malloc(formats * sizeof(*format_list)); + + printf("AUDIO FILE FORMATS:"); + for (i = formats = 0; sox_format_fns[i].fn; ++i) { + sox_format_handler_t const * handler = sox_format_fns[i].fn(); + if (!(handler->flags & SOX_FILE_DEVICE)) + for (names = handler->names; *names; ++names) + if (!strchr(*names, '/')) + format_list[formats++] = *names; + } + qsort((void*)format_list, formats, sizeof(*format_list), strcmp_p); + for (i = 0; i < formats; i++) + printf(" %s", format_list[i]); + putchar('\n'); + + printf("PLAYLIST FORMATS: m3u pls\nAUDIO DEVICE DRIVERS:"); + for (i = formats = 0; sox_format_fns[i].fn; ++i) { + sox_format_handler_t const * handler = sox_format_fns[i].fn(); + if ((handler->flags & SOX_FILE_DEVICE) && !(handler->flags & SOX_FILE_PHONY)) + for (names = handler->names; *names; ++names) + format_list[formats++] = *names; + } + qsort((void*)format_list, formats, sizeof(*format_list), strcmp_p); + for (i = 0; i < formats; i++) + printf(" %s", format_list[i]); + puts("\n"); + + free((void*)format_list); +} + +static void display_supported_effects(void) +{ + size_t i; + const sox_effect_handler_t *e; + + printf("EFFECTS:"); + for (i = 0; sox_effect_fns[i]; i++) { + e = sox_effect_fns[i](); + if (e && e->name) + printf(" %s%s", e->name, (e->flags & SOX_EFF_DEPRECATED)? "*" : (e->flags & SOX_EFF_ALPHA)? "+" : (e->flags & SOX_EFF_INTERNAL)? "#" : ""); + } + puts("\n * Deprecated effect + Experimental effect # LibSoX-only effect"); +} + +static void usage(char const * message) +{ + const sox_version_info_t * info = sox_version_info(); + size_t i; + static char const * const lines1[] = { +"SPECIAL FILENAMES (infile, outfile):", +"- Pipe/redirect input/output (stdin/stdout); may need -t", +"-d, --default-device Use the default audio device (where available)", +"-n, --null Use the `null' file handler; e.g. with synth effect", +"-p, --sox-pipe Alias for `-t sox -'" + }; + static char const * const linesPopen[] = { +"\nSPECIAL FILENAMES (infile only):", +"\"|program [options] ...\" Pipe input from external program (where supported)", +"http://server/file Use the given URL as input file (where supported)" + }; + static char const * const lines2[] = { +"", +"GLOBAL OPTIONS (gopts) (can be specified at any point before the first effect):", +"--buffer BYTES Set the size of all processing buffers (default 8192)", +"--clobber Don't prompt to overwrite output file (default)", +"--combine concatenate Concatenate all input files (default for sox, rec)", +"--combine sequence Sequence all input files (default for play)", +"-D, --no-dither Don't dither automatically", +"--dft-min NUM Minimum size (log2) for DFT processing (default 10)", +"--effects-file FILENAME File containing effects and options", +"-G, --guard Use temporary files to guard against clipping", +"-h, --help Display version number and usage information", +"--help-effect NAME Show usage of effect NAME, or NAME=all for all", +"--help-format NAME Show info on format NAME, or NAME=all for all", +"--i, --info Behave as soxi(1)", +"--input-buffer BYTES Override the input buffer size (default: as --buffer)", +"--no-clobber Prompt to overwrite output file", +"-m, --combine mix Mix multiple input files (instead of concatenating)", +"--combine mix-power Mix to equal power (instead of concatenating)", +"-M, --combine merge Merge multiple input files (instead of concatenating)" + }; + static char const * const linesMagic[] = { +"--magic Use `magic' file-type detection" + }; + static char const * const linesThreads[] = { +"--multi-threaded Enable parallel effects channels processing" + }; + static char const * const lines3[] = { +"--norm Guard (see --guard) & normalise", +"--play-rate-arg ARG Default `rate' argument for auto-resample with `play'", +"--plot gnuplot|octave Generate script to plot response of filter effect", +"-q, --no-show-progress Run in quiet mode; opposite of -S", +"--replay-gain track|album|off Default: off (sox, rec), track (play)", +"-R Use default random numbers (same on each run of SoX)", +"-S, --show-progress Display progress while processing audio data", +"--single-threaded Disable parallel effects channels processing", +"--temp DIRECTORY Specify the directory to use for temporary files", +"-T, --combine multiply Multiply samples of corresponding channels from all", +" input files (instead of concatenating)", +"--version Display version number of SoX and exit", +"-V[LEVEL] Increment or set verbosity level (default 2); levels:", +" 1: failure messages", +" 2: warnings", +" 3: details of processing", +" 4-6: increasing levels of debug messages", +"FORMAT OPTIONS (fopts):", +"Input file format options need only be supplied for files that are headerless.", +"Output files will have the same format as the input file where possible and not", +"overridden by any of various means including providing output format options.", +"", +"-v|--volume FACTOR Input file volume adjustment factor (real number)", +"--ignore-length Ignore input file length given in header; read to EOF", +"-t|--type FILETYPE File type of audio", +"-e|--encoding ENCODING Set encoding (ENCODING may be one of signed-integer,", +" unsigned-integer, floating-point, mu-law, a-law,", +" ima-adpcm, ms-adpcm, gsm-full-rate)", +"-b|--bits BITS Encoded sample size in bits", +"-N|--reverse-nibbles Encoded nibble-order", +"-X|--reverse-bits Encoded bit-order", +"--endian little|big|swap Encoded byte-order; swap means opposite to default", +"-L/-B/-x Short options for the above", +"-c|--channels CHANNELS Number of channels of audio data; e.g. 2 = stereo", +"-r|--rate RATE Sample rate of audio", +"-C|--compression FACTOR Compression factor for output format", +"--add-comment TEXT Append output file comment", +"--comment TEXT Specify comment text for the output file", +"--comment-file FILENAME File containing comment text for the output file", +#if HAVE_GLOB_H +"--no-glob Don't `glob' wildcard match the following filename", +#endif +""}; + + if (!(sox_globals.verbosity > 2)) { + display_SoX_version(stdout); + putchar('\n'); + } + + if (message) + lsx_fail("%s\n", message); /* N.B. stderr */ + + printf("Usage summary: [gopts] [[fopts] infile]... [fopts]%s [effect [effopt]]...\n\n", + sox_mode == sox_play? "" : " outfile"); + for (i = 0; i < array_length(lines1); ++i) + puts(lines1[i]); + if (info->flags & sox_version_have_popen) + for (i = 0; i < array_length(linesPopen); ++i) + puts(linesPopen[i]); + for (i = 0; i < array_length(lines2); ++i) + puts(lines2[i]); + if (info->flags & sox_version_have_magic) + for (i = 0; i < array_length(linesMagic); ++i) + puts(linesMagic[i]); + if (info->flags & sox_version_have_threads) + for (i = 0; i < array_length(linesThreads); ++i) + puts(linesThreads[i]); + for (i = 0; i < array_length(lines3); ++i) + puts(lines3[i]); + display_supported_formats(); + display_supported_effects(); + printf("EFFECT OPTIONS (effopts): effect dependent; see --help-effect\n"); + exit(message != NULL); +} + +static void usage_effect(char const * name) +{ + size_t i; + + display_SoX_version(stdout); + putchar('\n'); + + if (strcmp("all", name) && !sox_find_effect(name)) { + printf("Cannot find an effect called `%s'.\n", name); + display_supported_effects(); + } + else { + printf("Effect usage:\n\n"); + + for (i = 0; sox_effect_fns[i]; i++) { + const sox_effect_handler_t *e = sox_effect_fns[i](); + if (e && e->name && (!strcmp("all", name) || !strcmp(e->name, name))) { + printf("%s %s\n", e->name, e->usage? e->usage : ""); + if (e->flags & (SOX_EFF_DEPRECATED | SOX_EFF_ALPHA | SOX_EFF_INTERNAL)) + putchar('\n'); + if (e->flags & SOX_EFF_DEPRECATED) + printf("`%s' is deprecated\n", e->name); + if (e->flags & SOX_EFF_ALPHA) + printf("`%s' is experimental/incomplete\n", e->name); + if (e->flags & SOX_EFF_INTERNAL) + printf("`%s' is libSoX-only\n", e->name); + printf("\n\n"); + } + } + } + exit(1); +} + +static void usage_format1(sox_format_handler_t const * f) +{ + char const * const * names; + + printf("\nFormat: %s\n", f->names[0]); + printf("Description: %s\n", f->description); + if (f->names[1]) { + printf("Also handles:"); + for (names = f->names + 1; *names; ++names) + printf(" %s", *names); + putchar('\n'); + } + if (f->flags & SOX_FILE_CHANS) { + printf("Channels restricted to:"); + if (f->flags & SOX_FILE_MONO) printf(" mono"); + if (f->flags & SOX_FILE_STEREO) printf(" stereo"); + if (f->flags & SOX_FILE_QUAD) printf(" quad"); + putchar('\n'); + } + if (f->write_rates) { + sox_rate_t const * p = f->write_rates; + printf("Sample-rate restricted to:"); + while (*p) + printf(" %g", *p++); + putchar('\n'); + } + printf("Reads: %s\n", f->startread || f->read? "yes" : "no"); + if (f->startwrite || f->write) { + if (f->write_formats) { + sox_encoding_t e; + unsigned i, s; +#define enc_arg(T) (T)f->write_formats[i++] + i = 0; + puts("Writes:"); + while ((e = enc_arg(sox_encoding_t))) + do { + s = enc_arg(unsigned); + if (sox_precision(e, s)) { + printf(" "); + if (s) + printf("%2u-bit ", s); + printf("%s (%u-bit precision)\n", sox_encodings_info[e].desc, sox_precision(e, s)); + } + } while (s); + } + else puts("Writes: yes"); + } + else puts("Writes: no"); +} + +static void usage_format(char const * name) +{ + sox_format_handler_t const * f; + unsigned i; + + display_SoX_version(stdout); + + if (strcmp("all", name)) { + if (!(f = sox_find_format(name, sox_false))) { + printf("Cannot find a format called `%s'.\n", name); + display_supported_formats(); + } + else usage_format1(f); + } + else { + for (i = 0; sox_format_fns[i].fn; ++i) { + sox_format_handler_t const * f = sox_format_fns[i].fn(); + if (!(f->flags & SOX_FILE_PHONY)) + usage_format1(f); + } + } + exit(1); +} + +static void read_comment_file(sox_comments_t * comments, char const * const filename) +{ + int c; + size_t text_length = 100; + char * text = lsx_malloc(text_length + 1); + FILE * file = fopen(filename, "r"); + + if (file == NULL) { + lsx_fail("Cannot open comment file `%s'", filename); + exit(1); + } + do { + size_t i = 0; + + while ((c = getc(file)) != EOF && !strchr("\r\n", c)) { + if (i == text_length) + text = lsx_realloc(text, (text_length <<= 1) + 1); + text[i++] = c; + } + if (ferror(file)) { + lsx_fail("Error reading comment file `%s'", filename); + exit(1); + } + if (i) { + text[i] = '\0'; + sox_append_comment(comments, text); + } + } while (c != EOF); + + fclose(file); + free(text); +} + +static char const * const getoptstr = + "+b:c:de:hmnpqr:t:v:xBC:DGLMNRSTV::X"; + +static struct lsx_option_t const long_options[] = { + {"add-comment" , lsx_option_arg_required, NULL, 0}, + {"buffer" , lsx_option_arg_required, NULL, 0}, + {"combine" , lsx_option_arg_required, NULL, 0}, + {"comment-file" , lsx_option_arg_required, NULL, 0}, + {"comment" , lsx_option_arg_required, NULL, 0}, + {"endian" , lsx_option_arg_required, NULL, 0}, + {"input-buffer" , lsx_option_arg_required, NULL, 0}, + {"interactive" , lsx_option_arg_none , NULL, 0}, + {"help-effect" , lsx_option_arg_required, NULL, 0}, + {"help-format" , lsx_option_arg_required, NULL, 0}, + {"no-glob" , lsx_option_arg_none , NULL, 0}, + {"plot" , lsx_option_arg_required, NULL, 0}, + {"replay-gain" , lsx_option_arg_required, NULL, 0}, + {"version" , lsx_option_arg_none , NULL, 0}, + {"output" , lsx_option_arg_required, NULL, 0}, + {"effects-file" , lsx_option_arg_required, NULL, 0}, + {"temp" , lsx_option_arg_required, NULL, 0}, + {"single-threaded" , lsx_option_arg_none , NULL, 0}, + {"ignore-length" , lsx_option_arg_none , NULL, 0}, + {"norm" , lsx_option_arg_optional, NULL, 0}, + {"magic" , lsx_option_arg_none , NULL, 0}, + {"play-rate-arg" , lsx_option_arg_required, NULL, 0}, + {"clobber" , lsx_option_arg_none , NULL, 0}, + {"no-clobber" , lsx_option_arg_none , NULL, 0}, + {"multi-threaded" , lsx_option_arg_none , NULL, 0}, + {"dft-min" , lsx_option_arg_required, NULL, 0}, + + {"bits" , lsx_option_arg_required, NULL, 'b'}, + {"channels" , lsx_option_arg_required, NULL, 'c'}, + {"compression" , lsx_option_arg_required, NULL, 'C'}, + {"default-device" , lsx_option_arg_none , NULL, 'd'}, + {"no-dither" , lsx_option_arg_none , NULL, 'D'}, + {"encoding" , lsx_option_arg_required, NULL, 'e'}, + {"help" , lsx_option_arg_none , NULL, 'h'}, + {"null" , lsx_option_arg_none , NULL, 'n'}, + {"no-show-progress", lsx_option_arg_none , NULL, 'q'}, + {"pipe" , lsx_option_arg_none , NULL, 'p'}, + {"rate" , lsx_option_arg_required, NULL, 'r'}, + {"reverse-bits" , lsx_option_arg_none , NULL, 'X'}, + {"reverse-nibbles" , lsx_option_arg_none , NULL, 'N'}, + {"show-progress" , lsx_option_arg_none , NULL, 'S'}, + {"type" , lsx_option_arg_required, NULL, 't'}, + {"volume" , lsx_option_arg_required, NULL, 'v'}, + {"guard" , lsx_option_arg_none , NULL, 'G'}, + + {NULL, 0, NULL, 0} +}; + +static int opt_index(int val) +{ + int i; + for (i = 0; long_options[i].name; ++i) + if (long_options[i].val == val) + return i; + return -1; +} + +static lsx_enum_item const combine_methods[] = { + LSX_ENUM_ITEM(sox_,sequence) + LSX_ENUM_ITEM(sox_,concatenate) + LSX_ENUM_ITEM(sox_,mix) + {"mix-power", sox_mix_power}, + LSX_ENUM_ITEM(sox_,merge) + LSX_ENUM_ITEM(sox_,multiply) + {0, 0}}; + +enum {ENDIAN_little, ENDIAN_big, ENDIAN_swap}; +static lsx_enum_item const endian_options[] = { + LSX_ENUM_ITEM(ENDIAN_,little) + LSX_ENUM_ITEM(ENDIAN_,big) + LSX_ENUM_ITEM(ENDIAN_,swap) + {0, 0}}; + +static lsx_enum_item const plot_methods[] = { + LSX_ENUM_ITEM(sox_plot_,off) + LSX_ENUM_ITEM(sox_plot_,octave) + LSX_ENUM_ITEM(sox_plot_,gnuplot) + LSX_ENUM_ITEM(sox_plot_,data) + {0, 0}}; + +enum { + encoding_signed_integer, encoding_unsigned_integer, encoding_floating_point, + encoding_ms_adpcm, encoding_ima_adpcm, encoding_oki_adpcm, + encoding_gsm_full_rate, encoding_u_law, encoding_a_law}; + +static lsx_enum_item const encodings[] = { + {"signed-integer", encoding_signed_integer}, + {"unsigned-integer", encoding_unsigned_integer}, + {"floating-point", encoding_floating_point}, + {"ms-adpcm", encoding_ms_adpcm}, + {"ima-adpcm", encoding_ima_adpcm}, + {"oki-adpcm", encoding_oki_adpcm}, + {"gsm-full-rate", encoding_gsm_full_rate}, + {"u-law", encoding_u_law}, + {"mu-law", encoding_u_law}, + {"a-law", encoding_a_law}, + {0, 0}}; + +static int enum_option(char const * arg, int option_index, lsx_enum_item const * items) +{ + lsx_enum_item const * p = lsx_find_enum_text(arg, items, 0); + if (p == NULL) { + size_t len = 1; + char * set = lsx_malloc(len); + *set = 0; + for (p = items; p->text; ++p) { + set = lsx_realloc(set, len += 2 + strlen(p->text)); + strcat(set, ", "); strcat(set, p->text); + } + lsx_fail("--%s: `%s' is not one of: %s.", + long_options[option_index].name, arg, set + 2); + free(set); + exit(1); + } + return p->value; +} + +static char parse_gopts_and_fopts(file_t * f) +{ + const sox_version_info_t* info = sox_version_info(); + while (sox_true) { + int c; + int i; /* sscanf silently accepts negative numbers for %u :( */ + char dummy; /* To check for extraneous chars in optarg. */ + + switch (c=lsx_getopt(&optstate)) { + case -1: /* @ one of: file-name, effect name, end of arg-list. */ + return '\0'; /* i.e. not device. */ + + case 0: /* Long options with no short equivalent. */ + switch (optstate.lngind) { + case 0: + if (optstate.arg) + sox_append_comment(&f->oob.comments, optstate.arg); + break; + + case 1: +#define SOX_BUFMIN 16 + if (sscanf(optstate.arg, "%i %c", &i, &dummy) != 1 || i <= SOX_BUFMIN) { + lsx_fail("Buffer size `%s' must be > %d", optstate.arg, SOX_BUFMIN); + exit(1); + } + sox_globals.bufsiz = i; + break; + + case 2: + combine_method = enum_option(optstate.arg, optstate.lngind, combine_methods); + break; + + case 3: + sox_append_comment(&f->oob.comments, ""); + read_comment_file(&f->oob.comments, optstate.arg); + break; + + case 4: + sox_append_comment(&f->oob.comments, ""); + if (*optstate.arg) + sox_append_comment(&f->oob.comments, optstate.arg); + break; + + case 5: + if (f->encoding.reverse_bytes != sox_option_default || f->encoding.opposite_endian) + usage("only one endian option per file is allowed"); + switch (enum_option(optstate.arg, optstate.lngind, endian_options)) { + case ENDIAN_little: f->encoding.reverse_bytes = MACHINE_IS_BIGENDIAN; break; + case ENDIAN_big: f->encoding.reverse_bytes = MACHINE_IS_LITTLEENDIAN; break; + case ENDIAN_swap: f->encoding.opposite_endian = sox_true; break; + } + break; + + case 6: + if (sscanf(optstate.arg, "%i %c", &i, &dummy) != 1 || i <= SOX_BUFMIN) { + lsx_fail("Buffer size `%s' must be > %d", optstate.arg, SOX_BUFMIN); + exit(1); + } + sox_globals.input_bufsiz = i; + break; + + case 7: +#if defined(HAVE_TERMIOS_H) || defined(HAVE_CONIO_H) + interactive = sox_true; break; +#else + lsx_fail("Interactive mode has not been enabled at compile time."); + exit(1); break; +#endif + case 8: usage_effect(optstate.arg); break; + case 9: usage_format(optstate.arg); break; + case 10: f->no_glob = sox_true; break; + case 11: + sox_effects_globals.plot = enum_option(optstate.arg, optstate.lngind, plot_methods); + break; + case 12: replay_gain_mode = enum_option(optstate.arg, optstate.lngind, rg_modes); break; + case 13: display_SoX_version(stdout); exit(0); break; + case 14: break; + case 15: effects_filename = lsx_strdup(optstate.arg); break; + case 16: sox_globals.tmp_path = lsx_strdup(optstate.arg); break; + case 17: sox_globals.use_threads = sox_false; break; + case 18: f->signal.length = SOX_IGNORE_LENGTH; break; + case 19: do_guarded_norm = is_guarded = sox_true; + norm_level = lsx_strdup(optstate.arg); + break; + case 20: + if (info->flags & sox_version_have_magic) + sox_globals.use_magic = sox_true; + else + lsx_warn("this build of SoX does not include `magic'"); + break; + case 21: play_rate_arg = lsx_strdup(optstate.arg); break; + case 22: no_clobber = sox_false; break; + case 23: no_clobber = sox_true; break; + case 24: sox_globals.use_threads = sox_true; break; + case 25: + if (sscanf(optstate.arg, "%i %c", &i, &dummy) != 1 || i < 8 || i > 16) { + lsx_fail("Min DFT size must be in range 8 to 16"); + exit(1); + } + sox_globals.log2_dft_min_size = i; + break; + } + break; + + case 'G': is_guarded = sox_true; break; + case 'm': combine_method = sox_mix; break; + case 'M': combine_method = sox_merge; break; + case 'T': combine_method = sox_multiply; break; + + case 'R': /* Useful for regression testing. */ + sox_globals.repeatable = sox_true; + break; + + case 'd': case 'n': case 'p': + optstate.ind = optstate.ind; + return c; + + case 'h': + usage(NULL); + break; + + case '?': + usage("invalid option"); /* No return */ + break; + + case 't': + f->filetype = optstate.arg; + if (f->filetype[0] == '.') + f->filetype++; + break; + + case 'r': { + char k = 0; + size_t n = sscanf(optstate.arg, "%lf %c %c", &f->signal.rate, &k, &dummy); + if (n < 1 || f->signal.rate <= 0 || (n > 1 && k != 'k') || n > 2) { + lsx_fail("Rate value `%s' is not a positive number", optstate.arg); + exit(1); + } + f->signal.rate *= k == 'k'? 1000. : 1.; + break; + } + + case 'v': + if (sscanf(optstate.arg, "%lf %c", &f->volume, &dummy) != 1) { + lsx_fail("Volume value `%s' is not a number", optstate.arg); + exit(1); + } + uservolume = sox_true; + if (f->volume < 0.0) + lsx_report("Volume adjustment is negative; " + "this will result in a phase change"); + break; + + case 'c': + if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i <= 0) { + lsx_fail("Channels value `%s' is not a positive integer", optstate.arg); + exit(1); + } + f->signal.channels = i; + break; + + case 'C': + if (sscanf(optstate.arg, "%lf %c", &f->encoding.compression, &dummy) != 1) { + lsx_fail("Compression value `%s' is not a number", optstate.arg); + exit(1); + } + break; + + case 'b': + if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i <= 0) { + lsx_fail("Bits value `%s' is not a positive integer", optstate.arg); + exit(1); + } + f->encoding.bits_per_sample = i; + break; + + case 'e': switch (enum_option(optstate.arg, opt_index('e'), encodings)) { + case encoding_signed_integer: f->encoding.encoding = SOX_ENCODING_SIGN2; break; + case encoding_unsigned_integer: f->encoding.encoding = SOX_ENCODING_UNSIGNED; break; + case encoding_floating_point: f->encoding.encoding = SOX_ENCODING_FLOAT; break; + case encoding_ms_adpcm: f->encoding.encoding = SOX_ENCODING_MS_ADPCM; break; + case encoding_ima_adpcm: f->encoding.encoding = SOX_ENCODING_IMA_ADPCM; break; + case encoding_oki_adpcm: f->encoding.encoding = SOX_ENCODING_OKI_ADPCM; break; + case encoding_gsm_full_rate: f->encoding.encoding = SOX_ENCODING_GSM; break; + case encoding_u_law: f->encoding.encoding = SOX_ENCODING_ULAW; + if (f->encoding.bits_per_sample == 0) + f->encoding.bits_per_sample = 8; + break; + case encoding_a_law: f->encoding.encoding = SOX_ENCODING_ALAW; + if (f->encoding.bits_per_sample == 0) + f->encoding.bits_per_sample = 8; + break; + } + break; + + case 'L': case 'B': case 'x': + if (f->encoding.reverse_bytes != sox_option_default || f->encoding.opposite_endian) + usage("only one endian option per file is allowed"); + switch (c) { + case 'L': f->encoding.reverse_bytes = MACHINE_IS_BIGENDIAN; break; + case 'B': f->encoding.reverse_bytes = MACHINE_IS_LITTLEENDIAN; break; + case 'x': f->encoding.opposite_endian = sox_true; break; + } + break; + case 'X': f->encoding.reverse_bits = sox_option_yes; break; + case 'N': f->encoding.reverse_nibbles = sox_option_yes; break; + + case 'S': show_progress = sox_option_yes; break; + case 'q': show_progress = sox_option_no; break; + case 'D': no_dither = sox_true; break; + + case 'V': + if (optstate.arg == NULL) + ++sox_globals.verbosity; + else { + if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i < 0) { + sox_globals.verbosity = 2; + lsx_fail("Verbosity value `%s' is not a non-negative integer", optstate.arg); + exit(1); + } + sox_globals.verbosity = (unsigned)i; + } + break; + } + } +} + +static char const * device_name(char const * const type) +{ + char * name = NULL, * from_env = getenv("AUDIODEV"); + + if (!type) + return NULL; + + if (0 + || !strcmp(type, "sunau") + || !strcmp(type, "oss" ) + || !strcmp(type, "ossdsp") + || !strcmp(type, "alsa") + || !strcmp(type, "ao") + || !strcmp(type, "sndio") + || !strcmp(type, "coreaudio") + || !strcmp(type, "pulseaudio") + || !strcmp(type, "waveaudio") + ) + name = "default"; + + return name? from_env? from_env : name : NULL; +} + +static char const * try_device(char const * name) +{ + sox_format_handler_t const * handler = sox_find_format(name, sox_false); + if (handler) { + sox_format_t format, * ft = &format; + lsx_debug("Looking for a default device: trying format `%s'", name); + memset(ft, 0, sizeof(*ft)); + ft->filename = (char *)device_name(name); + ft->priv = lsx_calloc(1, handler->priv_size); + if (handler->startwrite(ft) == SOX_SUCCESS) { + handler->stopwrite(ft); + free(ft->priv); + return name; + } + free(ft->priv); + } + return NULL; +} + +static char const * set_default_device(file_t * f) +{ + /* Default audio driver type in order of preference: */ + if (!f->filetype) f->filetype = getenv("AUDIODRIVER"); + if (!f->filetype) f->filetype = try_device("coreaudio"); + if (!f->filetype) f->filetype = try_device("pulseaudio"); + if (!f->filetype) f->filetype = try_device("alsa"); + if (!f->filetype) f->filetype = try_device("waveaudio"); + if (!f->filetype) f->filetype = try_device("sndio"); + if (!f->filetype) f->filetype = try_device("oss"); + if (!f->filetype) f->filetype = try_device("sunau"); + if (!f->filetype && file_count) /*!rec*/ + f->filetype = try_device("ao"); + + if (!f->filetype) { + lsx_fail("Sorry, there is no default audio device configured"); + exit(1); + } + return device_name(f->filetype); +} + +static int add_file(file_t const * const opts, char const * const filename) +{ + file_t * f = lsx_malloc(sizeof(*f)); + + *f = *opts; + if (!filename) + usage("missing filename"); /* No return */ + f->filename = lsx_strdup(filename); + files = lsx_realloc(files, (file_count + 1) * sizeof(*files)); + files[file_count++] = f; + return 0; +} + +#if HAVE_GLOB_H +#ifndef GLOB_BRACE +#define GLOB_BRACE 0 +#endif +#ifndef GLOB_TILDE +#define GLOB_TILDE 0 +#endif +static int add_glob_file(file_t const * const opts, char const * const filename) +{ + glob_t globbuf; + size_t i; + + if (opts->no_glob) + return add_file(opts, filename); + + if (glob(filename, GLOB_BRACE | GLOB_TILDE | GLOB_NOCHECK, NULL, &globbuf)) { + lsx_fail("glob: %s", strerror(errno)); + exit(1); + } + for (i = 0; i < globbuf.gl_pathc; ++i) + add_file(opts, globbuf.gl_pathv[i]); + globfree(&globbuf); + return 0; +} +#else + #define add_glob_file add_file +#endif + +static void init_file(file_t * f) +{ + memset(f, 0, sizeof(*f)); + sox_init_encodinginfo(&f->encoding); + f->volume = HUGE_VAL; + f->replay_gain = HUGE_VAL; +} + +static void parse_options_and_filenames(int argc, char **argv) +{ + char const * env_opts = getenv(SOX_OPTS); + file_t opts, opts_none; + init_file(&opts), init_file(&opts_none); + + if (sox_mode == sox_rec) + add_file(&opts, set_default_device(&opts)), init_file(&opts); + + if (env_opts && *env_opts) { + char * * argv2, * str = lsx_malloc(strlen(argv[0]) + strlen(env_opts) + 2); + int argc2; + strcpy(str, argv[0]); + strcat(str, " "); + strcat(str, env_opts); + argv2 = strtoargv(str, &argc2); + lsx_getopt_init(argc2, argv2, getoptstr, long_options, lsx_getopt_flag_opterr, 1, &optstate); + if (parse_gopts_and_fopts(&opts)) { + lsx_fail("invalid option for "SOX_OPTS); + exit(1); + } + free(str); + free(argv2); + } + + lsx_getopt_init(argc, argv, getoptstr, long_options, lsx_getopt_flag_opterr, 1, &optstate); + for (; optstate.ind < argc && !sox_find_effect(argv[optstate.ind]); init_file(&opts)) { + char c = parse_gopts_and_fopts(&opts); + if (c == 'n') { /* is null file? */ + if (opts.filetype != NULL && strcmp(opts.filetype, "null") != 0) + lsx_warn("ignoring `-t %s'.", opts.filetype); + opts.filetype = "null"; + add_file(&opts, ""); + } + else if (c == 'd') /* is default device? */ + add_file(&opts, set_default_device(&opts)); + else if (c == 'p') { /* is sox pipe? */ + if (opts.filetype != NULL && strcmp(opts.filetype, "sox") != 0) + lsx_warn("ignoring `-t %s'.", opts.filetype); + opts.filetype = "sox"; + add_file(&opts, "-"); + } + else if (optstate.ind >= argc || sox_find_effect(argv[optstate.ind])) + break; + else if (!sox_is_playlist(argv[optstate.ind])) + add_glob_file(&opts, argv[optstate.ind++]); + else if (sox_parse_playlist((sox_playlist_callback_t)add_file, &opts, argv[optstate.ind++]) != SOX_SUCCESS) + exit(1); + } + if (env_opts && *env_opts) { + lsx_report("using "SOX_OPTS"=%s", env_opts); + reported_sox_opts = sox_true; + } + if (sox_mode == sox_play) + add_file(&opts, set_default_device(&opts)); + else if (memcmp(&opts, &opts_none, sizeof(opts))) /* fopts but no file */ + add_file(&opts, device_name(opts.filetype)); +} + +static double soxi_total; +static size_t soxi_file_count; + +typedef enum {Full, Type, Rate, Channels, Samples, Duration, Duration_secs, + Bits, Bitrate, Precision, Encoding, Annotation} soxi_t; + +static int soxi1(soxi_t const * type, char const * filename) +{ + sox_format_t * ft = sox_open_read(filename, NULL, NULL, NULL); + double secs; + uint64_t ws; + char const * text = NULL; + + if (!ft) + return 1; + ws = ft->signal.length / max(ft->signal.channels, 1); + secs = (double)ws / max(ft->signal.rate, 1); + ++soxi_file_count; + if (soxi_total >= 0 && !ws) + soxi_total = -2; + if (soxi_total >= 0) soxi_total += *type == Samples? ws : secs; + + switch (*type) { + case Type: printf("%s\n", ft->filetype); break; + case Rate: printf("%g\n", ft->signal.rate); break; + case Channels: printf("%u\n", ft->signal.channels); break; + case Samples: if (soxi_total ==-1) printf("%" PRIu64 "\n", ws); break; + case Duration: if (soxi_total ==-1) printf("%s\n", str_time(secs)); break; + case Duration_secs: if (soxi_total ==-1) printf("%f\n", secs); break; + case Bits: printf("%u\n", ft->encoding.bits_per_sample); break; + case Bitrate: size_and_bitrate(ft, &text); puts(text? text : "0"); break; + case Precision: printf("%u\n", ft->signal.precision); break; + case Encoding: printf("%s\n", sox_encodings_info[ft->encoding.encoding].desc); break; + case Annotation: if (ft->oob.comments) { + sox_comments_t p = ft->oob.comments; + do printf("%s\n", *p); while (*++p); + } + break; + case Full: display_file_info(ft, NULL, sox_false); break; + } + return !!sox_close(ft); +} + +static void soxi_usage(int return_code) +{ + display_SoX_version(stdout); + printf( + "\n" + "Usage: soxi [-V[level]] [-T] [-t|-r|-c|-s|-d|-D|-b|-B|-p|-e|-a] infile1 ...\n" + "\n" + "-V[n]\tIncrement or set verbosity level (default is 2)\n" + "-T\tWith -s, -d or -D, display the total across all given files\n" + "\n" + "-t\tShow detected file-type\n" + "-r\tShow sample-rate\n" + "-c\tShow number of channels\n" + ); printf( + "-s\tShow number of samples (0 if unavailable)\n" + "-d\tShow duration in hours, minutes and seconds (0 if unavailable)\n" + "-D\tShow duration in seconds (0 if unavailable)\n" + "-b\tShow number of bits per sample (0 if not applicable)\n" + "-B\tShow the bitrate averaged over the whole file (0 if unavailable)\n" + "-p\tShow estimated sample precision in bits\n" + "-e\tShow the name of the audio encoding\n" + "-a\tShow file comments (annotations) if available\n" + "\n" + "With no options, as much information as is available is shown for\n" + "each given file.\n" + ); + exit(return_code); +} + +static int soxi(int argc, char * const * argv) +{ + static char const opts[] = "trcsdDbBpea?TV::"; + soxi_t type = Full; + int opt, num_errors = 0; + sox_bool do_total = sox_false; + + if (argc < 2) + soxi_usage(0); + lsx_getopt_init(argc, argv, opts, NULL, lsx_getopt_flag_opterr, 1, &optstate); + while ((opt = lsx_getopt(&optstate)) > 0) /* act only on last option */ + if (opt == 'V') { + int i; /* sscanf silently accepts negative numbers for %u :( */ + char dummy; /* To check for extraneous chars in optstate.arg. */ + if (optstate.arg == NULL) + ++sox_globals.verbosity; + else { + if (sscanf(optstate.arg, "%d %c", &i, &dummy) != 1 || i < 0) { + sox_globals.verbosity = 2; + lsx_fail("Verbosity value `%s' is not a non-negative integer", optstate.arg); + exit(1); + } + sox_globals.verbosity = (unsigned)i; + } + } + else if (opt == 'T') + do_total = sox_true; + else if ((type = 1 + (strchr(opts, opt) - opts)) > Annotation) + soxi_usage(1); + + if (type == Full) + do_total = sox_true; + else if (do_total && (type < Samples || type > Duration_secs)) { + fprintf(stderr, "soxi: ignoring -T; n/a with other given option"); + do_total = sox_false; + } + soxi_total = -!do_total; + for (; optstate.ind < argc; ++optstate.ind) { + if (sox_is_playlist(argv[optstate.ind])) + num_errors += (sox_parse_playlist((sox_playlist_callback_t)soxi1, &type, argv[optstate.ind]) != SOX_SUCCESS); + else num_errors += soxi1(&type, argv[optstate.ind]); + } + if (type == Full) { + if (soxi_file_count > 1 && soxi_total > 0) + printf("Total Duration of %u files: %s\n", (unsigned)soxi_file_count, str_time(soxi_total)); + } + else if (do_total) { + if (soxi_total < 0) + puts("0"); + else if (type == Duration) + printf("%s\n", str_time(soxi_total)); + else printf("%f\n", soxi_total); + } + return num_errors; +} + +static void set_replay_gain(sox_comments_t comments, file_t * f) +{ + rg_mode rg = replay_gain_mode; + int try = 2; /* Will try to find the other GAIN if preferred one not found */ + size_t i, n = sox_num_comments(comments); + + if (rg != RG_off) while (try--) { + char const * target = + rg == RG_track? "REPLAYGAIN_TRACK_GAIN=" : "REPLAYGAIN_ALBUM_GAIN="; + for (i = 0; i < n; ++i) { + if (strncasecmp(comments[i], target, strlen(target)) == 0) { + f->replay_gain = atof(comments[i] + strlen(target)); + f->replay_gain_mode = rg; + return; + } + } + rg ^= RG_track ^ RG_album; + } +} + +static void output_message(unsigned level, const char *filename, const char *fmt, va_list ap) +{ + char const * const str[] = {"FAIL", "WARN", "INFO", "DBUG"}; + if (sox_globals.verbosity >= level) { + char base_name[128]; + sox_basename(base_name, sizeof(base_name), filename); + fprintf(stderr, "%s %s %s: ", myname, str[min(level - 1, 3)], base_name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + } +} + +static sox_bool cmp_comment_text(char const * c1, char const * c2) +{ + return c1 && c2 && !strcasecmp(c1, c2); +} + +int main(int argc, char **argv) +{ + size_t i; + char mybase[6]; + int err; + + gettimeofday(&load_timeofday, NULL); + myname = argv[0]; + sox_globals.output_message_handler = output_message; + + if (0 != sox_basename(mybase, sizeof(mybase), myname)) + { + if (0 == lsx_strcasecmp(mybase, "play")) + sox_mode = sox_play; + else if (0 == lsx_strcasecmp(mybase, "rec")) + sox_mode = sox_rec; + else if (0 == lsx_strcasecmp(mybase, "soxi")) + sox_mode = sox_soxi; + } + + if (!sox_mode && argc > 1 && + (!strcmp(argv[1], "--i") || !strcmp(argv[1], "--info"))) + --argc, ++argv, sox_mode = sox_soxi; + + if (sox_init() != SOX_SUCCESS) + exit(1); + + stdin_is_a_tty = isatty(fileno(stdin)); + errno = 0; /* Both isatty & fileno may set errno. */ + + atexit(atexit_cleanup); + + if (sox_mode == sox_soxi) + exit(soxi(argc, argv)); + + parse_options_and_filenames(argc, argv); + + if (sox_globals.verbosity > 2) + display_SoX_version(stderr); + + input_count = file_count ? file_count - 1 : 0; + + if (file_count) { + sox_format_handler_t const * handler = + sox_write_handler(ofile->filename, ofile->filetype, NULL); + is_player = handler && + (handler->flags & SOX_FILE_DEVICE) && !(handler->flags & SOX_FILE_PHONY); + } + + if (combine_method == sox_default) + combine_method = is_player? sox_sequence : sox_concatenate; + + /* Allow e.g. known length processing in this case */ + if (combine_method == sox_sequence && input_count == 1) + combine_method = sox_concatenate; + + /* Make sure we got at least the required # of input filenames */ + if (input_count < 1) + usage("No input filenames specified"); + + /* Check for misplaced input/output-specific options */ + for (i = 0; i < input_count; ++i) { + if (files[i]->encoding.compression != HUGE_VAL) + usage("A compression factor can be given only for an output file"); + if (files[i]->oob.comments != NULL) + usage("Comments can be given only for an output file"); + } + if (ofile->volume != HUGE_VAL) + usage("-v can be given only for an input file;\n" + "\tuse the `gain' or `vol' effect to set the output file volume"); + if (ofile->signal.length != SOX_UNSPEC) + usage("--ignore-length can be given only for an input file"); + + setsig(SIGINT, SIG_IGN); /* So child pipes aren't killed by track skip */ + for (i = 0; i < input_count; i++) { + size_t j = input_count - 1 - i; /* Open in reverse order 'cos of rec (below) */ + file_t * f = files[j]; + + /* When mixing audio, default to input side volume adjustments that will + * make sure no clipping will occur. Users probably won't be happy with + * this, and will override it, possibly causing clipping to occur. */ + if (combine_method == sox_mix && !uservolume) + f->volume = 1.0 / input_count; + else if (combine_method == sox_mix_power && !uservolume) + f->volume = 1.0 / sqrt((double)input_count); + + if (sox_mode == sox_rec && !j) { /* Set the recording parameters: */ + if (input_count > 1) { /* from the (just openned) next */ + f->signal = files[1]->ft->signal; /* input file, or from the output */ + f->encoding = files[1]->ft->encoding; + } else { + f->signal = files[1]->signal; /* file (which is not open yet). */ + f->encoding = files[1]->encoding; + } + } + files[j]->ft = sox_open_read(f->filename, &f->signal, &f->encoding, f->filetype); + if (!files[j]->ft) + /* sox_open_read() will call lsx_warn for most errors. + * Rely on that printing something. */ + exit(2); + if (show_progress == sox_option_default && + (files[j]->ft->handler.flags & SOX_FILE_DEVICE) != 0 && + (files[j]->ft->handler.flags & SOX_FILE_PHONY) == 0) + show_progress = sox_option_yes; + } + + if (replay_gain_mode == RG_default) + replay_gain_mode = is_player? + input_count > 1 && /* Simple heuristic to determine if */ + cmp_comment_text( /* replay-gain should be in album mode */ + sox_find_comment(files[0]->ft->oob.comments, "artist"), + sox_find_comment(files[1]->ft->oob.comments, "artist")) && + cmp_comment_text( + sox_find_comment(files[0]->ft->oob.comments, "album"), + sox_find_comment(files[1]->ft->oob.comments, "album"))? + RG_album : RG_track : RG_off; + + for (i = 0; i < input_count; i++) + set_replay_gain(files[i]->ft->oob.comments, files[i]); + + setsig(SIGINT, SIG_DFL); + + /* Loop through the rest of the arguments looking for effects */ + add_eff_chain(); + parse_effects(argc, argv); + eff_chain_count++; + /* Note: Purposely not calling add_eff_chain() to save some + * memory although it would be more consistent to do so. + */ + + /* Not the best way for users to do this; now deprecated in favour of soxi. */ + if (!show_progress && !nuser_effects[current_eff_chain] && + ofile->filetype && !strcmp(ofile->filetype, "null")) { + for (i = 0; i < input_count; i++) + report_file_info(files[i]); + exit(0); + } + + if (!sox_globals.repeatable) {/* Re-seed PRNG? */ + struct timeval now; + gettimeofday(&now, NULL); + sox_globals.ranqd1 = (int32_t)(now.tv_sec - now.tv_usec); + } + + /* Save things that sox_sequence needs to be reinitialised for each segued + * block of input files.*/ + ofile_signal_options = ofile->signal; + ofile_encoding_options = ofile->encoding; + + /* If user specified an effects filename then use that file + * to load user effects. Free any previously specified options + * from the command line. + */ + if (effects_filename) + { + read_user_effects(effects_filename); + } + + for (;;) { + err = process(); + + if (err == SOX_EOF || user_abort || current_input >= input_count) + break; + + if (advance_eff_chain() == SOX_EOF) + break; + + if (!save_output_eff) + { + sox_close(ofile->ft); + ofile->ft = NULL; + } + } + + sox_delete_effects_chain(effects_chain); + delete_eff_chains(); + + for (i = 0; i < file_count; ++i) + if (files[i]->ft->clips != 0) + lsx_warn(i < input_count?"`%s' input clipped %" PRIu64 " samples" : + "`%s' output clipped %" PRIu64 " samples; decrease volume?", + (files[i]->ft->handler.flags & SOX_FILE_DEVICE)? + files[i]->ft->handler.names[0] : files[i]->ft->filename, + files[i]->ft->clips); + + if (mixing_clips > 0) + lsx_warn("mix-combining clipped %" PRIu64 " samples; decrease volume?", mixing_clips); + + for (i = 0; i < file_count; i++) + if (files[i]->volume_clips > 0) + lsx_warn("`%s' balancing clipped %" PRIu64 " samples; decrease volume?", + files[i]->filename, files[i]->volume_clips); + + if (show_progress) { + if (user_abort) + fprintf(stderr, "Aborted.\n"); + else if (user_skip && sox_mode != sox_rec) + fprintf(stderr, "Skipped.\n"); + else + fprintf(stderr, "Done.\n"); + } + + success = 1; /* Signal success to cleanup so the output file isn't removed. */ + + cleanup(); + + return !!err; +} diff --git a/app/src/main/cpp/sox/sox.h b/app/src/main/cpp/sox/sox.h new file mode 100644 index 0000000..bac5035 --- /dev/null +++ b/app/src/main/cpp/sox/sox.h @@ -0,0 +1,2603 @@ +/* libSoX Library Public Interface + * + * Copyright 1999-2012 Chris Bagwell and SoX Contributors. + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Chris Bagwell And SoX Contributors are not responsible for + * the consequences of using this software. + */ + +/** @file +Contains the interface exposed to clients of the libSoX library. +Symbols starting with "sox_" or "SOX_" are part of the public interface for +libSoX clients (applications that consume libSoX). Symbols starting with +"lsx_" or "LSX_" are internal use by libSoX and plugins. +LSX_ and lsx_ symbols should not be used by libSoX-based applications. +*/ + +#ifndef SOX_H +#define SOX_H /**< Client API: This macro is defined if sox.h has been included. */ + +#include +#include +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif + +/* Suppress warnings from use of type long long. */ +#if defined __GNUC__ +#pragma GCC system_header +#endif + +#if defined __GNUC__ +#define LSX_GCC(maj, min) \ + ((__GNUC__ > (maj)) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min))) +#else +#define LSX_GCC(maj, min) 0 +#endif + +#if LSX_GCC(4,9) +#define _Ret_ __attribute__ ((returns_nonnull)) +#define _Ret_valid_ _Ret_ +#define _Ret_z_ _Ret_ +#endif + +/***************************************************************************** +API decoration macros: +Mostly for documentation purposes. For some compilers, decorations also affect +code generation, influence compiler warnings or activate compiler +optimizations. +*****************************************************************************/ + +/** +Plugins API: +Attribute required on all functions exported by libSoX and on all function +pointer types used by the libSoX API. +*/ +#if defined __GNUC__ && defined __i386__ +#define LSX_API __attribute__ ((cdecl)) /* libSoX function */ +#elif _MSC_VER +#define LSX_API __cdecl /* libSoX function */ +#else +#define LSX_API /* libSoX function */ +#endif + +/** +Plugins API: +Attribute applied to a parameter or local variable to suppress warnings about +the variable being unused (especially in macro-generated code). +*/ +#ifdef __GNUC__ +#define LSX_UNUSED __attribute__ ((unused)) /* Parameter or local variable is intentionally unused. */ +#else +#define LSX_UNUSED /* Parameter or local variable is intentionally unused. */ +#endif + +/** +Plugins API: +LSX_PRINTF12: Attribute applied to a function to indicate that it requires +a printf-style format string for arg1 and that printf parameters start at +arg2. +*/ +#ifdef __GNUC__ +#define LSX_PRINTF12 __attribute__ ((format (printf, 1, 2))) /* Function has printf-style arguments. */ +#else +#define LSX_PRINTF12 /* Function has printf-style arguments. */ +#endif + +/** +Plugins API: +Attribute applied to a function to indicate that it has no side effects and +depends only its input parameters and global memory. If called repeatedly, it +returns the same result each time. +*/ +#ifdef __GNUC__ +#define LSX_RETURN_PURE __attribute__ ((pure)) /* Function is pure. */ +#else +#define LSX_RETURN_PURE /* Function is pure. */ +#endif + +/** +Plugins API: +Attribute applied to a function to indicate that the +return value is always a pointer to a valid object (never NULL). +*/ +#ifdef _Ret_ +#define LSX_RETURN_VALID _Ret_ /* Function always returns a valid object (never NULL). */ +#else +#define LSX_RETURN_VALID /* Function always returns a valid object (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a function to indicate that the return value is always a +pointer to a valid array (never NULL). +*/ +#ifdef _Ret_valid_ +#define LSX_RETURN_ARRAY _Ret_valid_ /* Function always returns a valid array (never NULL). */ +#else +#define LSX_RETURN_ARRAY /* Function always returns a valid array (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a function to indicate that the return value is always a +pointer to a valid 0-terminated array (never NULL). +*/ +#ifdef _Ret_z_ +#define LSX_RETURN_VALID_Z _Ret_z_ /* Function always returns a 0-terminated array (never NULL). */ +#else +#define LSX_RETURN_VALID_Z /* Function always returns a 0-terminated array (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a function to indicate that the returned pointer may be +null. +*/ +#ifdef _Ret_opt_ +#define LSX_RETURN_OPT _Ret_opt_ /* Function may return NULL. */ +#else +#define LSX_RETURN_OPT /* Function may return NULL. */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to one const element of the pointed-to type (never NULL). +*/ +#ifdef _In_ +#define LSX_PARAM_IN _In_ /* Required const pointer to a valid object (never NULL). */ +#else +#define LSX_PARAM_IN /* Required const pointer to a valid object (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to a const 0-terminated string (never NULL). +*/ +#ifdef _In_z_ +#define LSX_PARAM_IN_Z _In_z_ /* Required const pointer to 0-terminated string (never NULL). */ +#else +#define LSX_PARAM_IN_Z /* Required const pointer to 0-terminated string (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a const +pointer to a 0-terminated printf format string. +*/ +#ifdef _Printf_format_string_ +#define LSX_PARAM_IN_PRINTF _Printf_format_string_ /* Required const pointer to 0-terminated printf format string (never NULL). */ +#else +#define LSX_PARAM_IN_PRINTF /* Required const pointer to 0-terminated printf format string (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to (len) const initialized elements of the pointed-to type, where +(len) is the name of another parameter. +@param len The parameter that contains the number of elements in the array. +*/ +#ifdef _In_count_ +#define LSX_PARAM_IN_COUNT(len) _In_count_(len) /* Required const pointer to (len) valid objects (never NULL). */ +#else +#define LSX_PARAM_IN_COUNT(len) /* Required const pointer to (len) valid objects (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to (len) const bytes of initialized data, where (len) is the name of +another parameter. +@param len The parameter that contains the number of bytes in the array. +*/ +#ifdef _In_bytecount_ +#define LSX_PARAM_IN_BYTECOUNT(len) _In_bytecount_(len) /* Required const pointer to (len) bytes of data (never NULL). */ +#else +#define LSX_PARAM_IN_BYTECOUNT(len) /* Required const pointer to (len) bytes of data (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is either NULL +or a valid pointer to one const element of the pointed-to type. +*/ +#ifdef _In_opt_ +#define LSX_PARAM_IN_OPT _In_opt_ /* Optional const pointer to a valid object (may be NULL). */ +#else +#define LSX_PARAM_IN_OPT /* Optional const pointer to a valid object (may be NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is either NULL +or a valid pointer to a const 0-terminated string. +*/ +#ifdef _In_opt_z_ +#define LSX_PARAM_IN_OPT_Z _In_opt_z_ /* Optional const pointer to 0-terminated string (may be NULL). */ +#else +#define LSX_PARAM_IN_OPT_Z /* Optional const pointer to 0-terminated string (may be NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to one initialized element of the pointed-to type (never NULL). The +function may modify the element. +*/ +#ifdef _Inout_ +#define LSX_PARAM_INOUT _Inout_ /* Required pointer to a valid object (never NULL). */ +#else +#define LSX_PARAM_INOUT /* Required pointer to a valid object (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to (len) initialized elements of the pointed-to type (never NULL). The +function may modify the elements. +@param len The parameter that contains the number of elements in the array. +*/ +#ifdef _Inout_count_x_ +#define LSX_PARAM_INOUT_COUNT(len) _Inout_count_x_(len) /* Required pointer to (len) valid objects (never NULL). */ +#else +#define LSX_PARAM_INOUT_COUNT(len) /* Required pointer to (len) valid objects (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to memory sufficient for one element of the pointed-to type (never +NULL). The function will initialize the element. +*/ +#ifdef _Out_ +#define LSX_PARAM_OUT _Out_ /* Required pointer to an object to be initialized (never NULL). */ +#else +#define LSX_PARAM_OUT /* Required pointer to an object to be initialized (never NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to memory sufficient for (len) bytes of data (never NULL), where (len) +is the name of another parameter. The function may write up to len bytes of +data to this memory. +@param len The parameter that contains the number of bytes in the array. +*/ +#ifdef _Out_bytecap_ +#define LSX_PARAM_OUT_BYTECAP(len) _Out_bytecap_(len) /* Required pointer to writable buffer with room for len bytes. */ +#else +#define LSX_PARAM_OUT_BYTECAP(len) /* Required pointer to writable buffer with room for len bytes. */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to memory sufficient for (len) elements of the pointed-to type (never +NULL), where (len) is the name of another parameter. On return, (filled) +elements will have been initialized, where (filled) is either the dereference +of another pointer parameter (for example "*written") or the "return" +parameter (indicating that the function returns the number of elements +written). +@param len The parameter that contains the number of elements in the array. +@param filled The dereference of the parameter that receives the number of elements written to the array, or "return" if the value is returned. +*/ +#ifdef _Out_cap_post_count_ +#define LSX_PARAM_OUT_CAP_POST_COUNT(len,filled) _Out_cap_post_count_(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled) elements will have been initialized. */ +#else +#define LSX_PARAM_OUT_CAP_POST_COUNT(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled) elements will have been initialized. */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer to memory sufficient for (len) elements of the pointed-to type (never +NULL), where (len) is the name of another parameter. On return, (filled+1) +elements will have been initialized, with the last element having been +initialized to 0, where (filled) is either the dereference of another pointer +parameter (for example, "*written") or the "return" parameter (indicating that +the function returns the number of elements written). +@param len The parameter that contains the number of elements in the array. +@param filled The dereference of the parameter that receives the number of elements written to the array (not counting the terminating null), or "return" if the value is returned. +*/ +#ifdef _Out_z_cap_post_count_ +#define LSX_PARAM_OUT_Z_CAP_POST_COUNT(len,filled) _Out_z_cap_post_count_(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled+1) elements will have been initialized, and the array will be 0-terminated. */ +#else +#define LSX_PARAM_OUT_Z_CAP_POST_COUNT(len,filled) /* Required pointer to buffer for (len) elements (never NULL); on return, (filled+1) elements will have been initialized, and the array will be 0-terminated. */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is either NULL +or a valid pointer to memory sufficient for one element of the pointed-to +type. The function will initialize the element. +*/ +#ifdef _Out_opt_ +#define LSX_PARAM_OUT_OPT _Out_opt_ /* Optional pointer to an object to be initialized (may be NULL). */ +#else +#define LSX_PARAM_OUT_OPT /* Optional pointer to an object to be initialized (may be NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer (never NULL) to another pointer which may be NULL when the function is +invoked. +*/ +#ifdef _Deref_pre_maybenull_ +#define LSX_PARAM_DEREF_PRE_MAYBENULL _Deref_pre_maybenull_ /* Required pointer (never NULL) to another pointer (may be NULL). */ +#else +#define LSX_PARAM_DEREF_PRE_MAYBENULL /* Required pointer (never NULL) to another pointer (may be NULL). */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer (never NULL) to another pointer which will be NULL when the function +returns. +*/ +#ifdef _Deref_post_null_ +#define LSX_PARAM_DEREF_POST_NULL _Deref_post_null_ /* Required pointer (never NULL) to another pointer, which will be NULL on exit. */ +#else +#define LSX_PARAM_DEREF_POST_NULL /* Required pointer (never NULL) to another pointer, which will be NULL on exit. */ +#endif + +/** +Plugins API: +Attribute applied to a parameter to indicate that the parameter is a valid +pointer (never NULL) to another pointer which will be non-NULL when the +function returns. +*/ +#ifdef _Deref_post_notnull_ +#define LSX_PARAM_DEREF_POST_NOTNULL _Deref_post_notnull_ /* Required pointer (never NULL) to another pointer, which will be valid (not NULL) on exit. */ +#else +#define LSX_PARAM_DEREF_POST_NOTNULL /* Required pointer (never NULL) to another pointer, which will be valid (not NULL) on exit. */ +#endif + +/** +Plugins API: +Expression that "uses" a potentially-unused variable to avoid compiler +warnings (especially in macro-generated code). +*/ +#ifdef _PREFAST_ +#define LSX_USE_VAR(x) ((void)(x=0)) /* During static analysis, initialize unused variables to 0. */ +#else +#define LSX_USE_VAR(x) ((void)(x)) /* Parameter or variable is intentionally unused. */ +#endif + +/** +Plugins API: +Compile-time assertion. Causes a compile error if the expression is false. +@param e The expression to test. If expression is false, compilation will fail. +@param f A unique identifier for the test, for example foo_must_not_be_zero. +*/ +#define lsx_static_assert(e,f) enum {lsx_static_assert_##f = 1/((e) ? 1 : 0)} + +/***************************************************************************** +Basic typedefs: +*****************************************************************************/ + +/** +Client API: +Signed twos-complement 8-bit type. Typically defined as signed char. +*/ +typedef int8_t sox_int8_t; + +/** +Client API: +Unsigned 8-bit type. Typically defined as unsigned char. +*/ +typedef uint8_t sox_uint8_t; + +/** +Client API: +Signed twos-complement 16-bit type. Typically defined as short. +*/ +typedef int16_t sox_int16_t; + +/** +Client API: +Unsigned 16-bit type. Typically defined as unsigned short. +*/ +typedef uint16_t sox_uint16_t; + +/** +Client API: +Signed twos-complement 32-bit type. Typically defined as int. +*/ +typedef int32_t sox_int32_t; + +/** +Client API: +Unsigned 32-bit type. Typically defined as unsigned int. +*/ +typedef uint32_t sox_uint32_t; + +/** +Client API: +Signed twos-complement 64-bit type. Typically defined as long or long long. +*/ +typedef int64_t sox_int64_t; + +/** +Client API: +Unsigned 64-bit type. Typically defined as unsigned long or unsigned long long. +*/ +typedef uint64_t sox_uint64_t; + +/** +Client API: +Alias for sox_int32_t (beware of the extra byte). +*/ +typedef sox_int32_t sox_int24_t; + +/** +Client API: +Alias for sox_uint32_t (beware of the extra byte). +*/ +typedef sox_uint32_t sox_uint24_t; + +/** +Client API: +Native SoX audio sample type (alias for sox_int32_t). +*/ +typedef sox_int32_t sox_sample_t; + +/** +Client API: +Samples per second is stored as a double. +*/ +typedef double sox_rate_t; + +/** +Client API: +File's metadata, access via sox_*_comments functions. +*/ +typedef char * * sox_comments_t; + +/***************************************************************************** +Enumerations: +*****************************************************************************/ + +/** +Client API: +Boolean type, assignment (but not necessarily binary) compatible with C++ bool. +*/ +typedef enum sox_bool { + sox_bool_dummy = -1, /* Ensure a signed type */ + sox_false, /**< False = 0. */ + sox_true /**< True = 1. */ +} sox_bool; + +/** +Client API: +no, yes, or default (default usually implies some kind of auto-detect logic). +*/ +typedef enum sox_option_t { + sox_option_no, /**< Option specified as no = 0. */ + sox_option_yes, /**< Option specified as yes = 1. */ + sox_option_default /**< Option unspecified = 2. */ +} sox_option_t; + +/** +Client API: +The libSoX-specific error codes. +libSoX functions may return these codes or others that map from errno codes. +*/ +enum sox_error_t { + SOX_SUCCESS = 0, /**< Function succeeded = 0 */ + SOX_EOF = -1, /**< End Of File or other error = -1 */ + SOX_EHDR = 2000, /**< Invalid Audio Header = 2000 */ + SOX_EFMT, /**< Unsupported data format = 2001 */ + SOX_ENOMEM, /**< Can't alloc memory = 2002 */ + SOX_EPERM, /**< Operation not permitted = 2003 */ + SOX_ENOTSUP, /**< Operation not supported = 2004 */ + SOX_EINVAL /**< Invalid argument = 2005 */ +}; + +/** +Client API: +Flags indicating whether optional features are present in this build of libSoX. +*/ +typedef enum sox_version_flags_t { + sox_version_none = 0, /**< No special features = 0. */ + sox_version_have_popen = 1, /**< popen = 1. */ + sox_version_have_magic = 2, /**< magic = 2. */ + sox_version_have_threads = 4, /**< threads = 4. */ + sox_version_have_memopen = 8 /**< memopen = 8. */ +} sox_version_flags_t; + +/** +Client API: +Format of sample data. +*/ +typedef enum sox_encoding_t { + SOX_ENCODING_UNKNOWN , /**< encoding has not yet been determined */ + + SOX_ENCODING_SIGN2 , /**< signed linear 2's comp: Mac */ + SOX_ENCODING_UNSIGNED , /**< unsigned linear: Sound Blaster */ + SOX_ENCODING_FLOAT , /**< floating point (binary format) */ + SOX_ENCODING_FLOAT_TEXT, /**< floating point (text format) */ + SOX_ENCODING_FLAC , /**< FLAC compression */ + SOX_ENCODING_HCOM , /**< Mac FSSD files with Huffman compression */ + SOX_ENCODING_WAVPACK , /**< WavPack with integer samples */ + SOX_ENCODING_WAVPACKF , /**< WavPack with float samples */ + SOX_ENCODING_ULAW , /**< u-law signed logs: US telephony, SPARC */ + SOX_ENCODING_ALAW , /**< A-law signed logs: non-US telephony, Psion */ + SOX_ENCODING_G721 , /**< G.721 4-bit ADPCM */ + SOX_ENCODING_G723 , /**< G.723 3 or 5 bit ADPCM */ + SOX_ENCODING_CL_ADPCM , /**< Creative Labs 8 --> 2,3,4 bit Compressed PCM */ + SOX_ENCODING_CL_ADPCM16, /**< Creative Labs 16 --> 4 bit Compressed PCM */ + SOX_ENCODING_MS_ADPCM , /**< Microsoft Compressed PCM */ + SOX_ENCODING_IMA_ADPCM , /**< IMA Compressed PCM */ + SOX_ENCODING_OKI_ADPCM , /**< Dialogic/OKI Compressed PCM */ + SOX_ENCODING_DPCM , /**< Differential PCM: Fasttracker 2 (xi) */ + SOX_ENCODING_DWVW , /**< Delta Width Variable Word */ + SOX_ENCODING_DWVWN , /**< Delta Width Variable Word N-bit */ + SOX_ENCODING_GSM , /**< GSM 6.10 33byte frame lossy compression */ + SOX_ENCODING_MP3 , /**< MP3 compression */ + SOX_ENCODING_VORBIS , /**< Vorbis compression */ + SOX_ENCODING_AMR_WB , /**< AMR-WB compression */ + SOX_ENCODING_AMR_NB , /**< AMR-NB compression */ + SOX_ENCODING_CVSD , /**< Continuously Variable Slope Delta modulation */ + SOX_ENCODING_LPC10 , /**< Linear Predictive Coding */ + SOX_ENCODING_OPUS , /**< Opus compression */ + + SOX_ENCODINGS /**< End of list marker */ +} sox_encoding_t; + +/** +Client API: +Flags for sox_encodings_info_t: lossless/lossy1/lossy2. +*/ +typedef enum sox_encodings_flags_t { + sox_encodings_none = 0, /**< no flags specified (implies lossless encoding) = 0. */ + sox_encodings_lossy1 = 1, /**< encode, decode: lossy once = 1. */ + sox_encodings_lossy2 = 2 /**< encode, decode, encode, decode: lossy twice = 2. */ +} sox_encodings_flags_t; + +/** +Client API: +Type of plot. +*/ +typedef enum sox_plot_t { + sox_plot_off, /**< No plot = 0. */ + sox_plot_octave, /**< Octave plot = 1. */ + sox_plot_gnuplot, /**< Gnuplot plot = 2. */ + sox_plot_data /**< Plot data = 3. */ +} sox_plot_t; + +/** +Client API: +Loop modes: upper 4 bits mask the loop blass, lower 4 bits describe +the loop behaviour, for example single shot, bidirectional etc. +*/ +enum sox_loop_flags_t { + sox_loop_none = 0, /**< single-shot = 0 */ + sox_loop_forward = 1, /**< forward loop = 1 */ + sox_loop_forward_back = 2, /**< forward/back loop = 2 */ + sox_loop_8 = 32, /**< 8 loops (??) = 32 */ + sox_loop_sustain_decay = 64 /**< AIFF style, one sustain & one decay loop = 64 */ +}; + +/** +Plugins API: +Is file a real file, a pipe, or a url? +*/ +typedef enum lsx_io_type +{ + lsx_io_file, /**< File is a real file = 0. */ + lsx_io_pipe, /**< File is a pipe (no seeking) = 1. */ + lsx_io_url /**< File is a URL (no seeking) = 2. */ +} lsx_io_type; + +/***************************************************************************** +Macros: +*****************************************************************************/ + +/** +Client API: +Compute a 32-bit integer API version from three 8-bit parts. +@param a Major version. +@param b Minor version. +@param c Revision or build number. +@returns 32-bit integer API version 0x000a0b0c. +*/ +#define SOX_LIB_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +/** +Client API: +The API version of the sox.h file. It is not meant to follow the version +number of SoX but it has historically. Please do not count on +SOX_LIB_VERSION_CODE staying in sync with the libSoX version. +*/ +#define SOX_LIB_VERSION_CODE SOX_LIB_VERSION(14, 4, 2) + +/** +Client API: +Returns the smallest (negative) value storable in a twos-complement signed +integer with the specified number of bits, cast to an unsigned integer; +for example, SOX_INT_MIN(8) = 0x80, SOX_INT_MIN(16) = 0x8000, etc. +@param bits Size of value for which to calculate minimum. +@returns the smallest (negative) value storable in a twos-complement signed +integer with the specified number of bits, cast to an unsigned integer. +*/ +#define SOX_INT_MIN(bits) (1 <<((bits)-1)) + +/** +Client API: +Returns the largest (positive) value storable in a twos-complement signed +integer with the specified number of bits, cast to an unsigned integer; +for example, SOX_INT_MAX(8) = 0x7F, SOX_INT_MAX(16) = 0x7FFF, etc. +@param bits Size of value for which to calculate maximum. +@returns the largest (positive) value storable in a twos-complement signed +integer with the specified number of bits, cast to an unsigned integer. +*/ +#define SOX_INT_MAX(bits) (((unsigned)-1)>>(33-(bits))) + +/** +Client API: +Returns the largest value storable in an unsigned integer with the specified +number of bits; for example, SOX_UINT_MAX(8) = 0xFF, +SOX_UINT_MAX(16) = 0xFFFF, etc. +@param bits Size of value for which to calculate maximum. +@returns the largest value storable in an unsigned integer with the specified +number of bits. +*/ +#define SOX_UINT_MAX(bits) (SOX_INT_MIN(bits)|SOX_INT_MAX(bits)) + +/** +Client API: +Returns 0x7F. +*/ +#define SOX_INT8_MAX SOX_INT_MAX(8) + +/** +Client API: +Returns 0x7FFF. +*/ +#define SOX_INT16_MAX SOX_INT_MAX(16) + +/** +Client API: +Returns 0x7FFFFF. +*/ +#define SOX_INT24_MAX SOX_INT_MAX(24) + +/** +Client API: +Returns 0x7FFFFFFF. +*/ +#define SOX_INT32_MAX SOX_INT_MAX(32) + +/** +Client API: +Bits in a sox_sample_t = 32. +*/ +#define SOX_SAMPLE_PRECISION 32 + +/** +Client API: +Max value for sox_sample_t = 0x7FFFFFFF. +*/ +#define SOX_SAMPLE_MAX (sox_sample_t)SOX_INT_MAX(32) + +/** +Client API: +Min value for sox_sample_t = 0x80000000. +*/ +#define SOX_SAMPLE_MIN (sox_sample_t)SOX_INT_MIN(32) + + +/* Conversions: Linear PCM <--> sox_sample_t + * + * I/O Input sox_sample_t Clips? Input sox_sample_t Clips? + * Format Minimum Minimum I O Maximum Maximum I O + * ------ --------- ------------ -- -- -------- ------------ -- -- + * Float -inf -1 y n inf 1 - 5e-10 y n + * Int8 -128 -128 n n 127 127.9999999 n y + * Int16 -32768 -32768 n n 32767 32767.99998 n y + * Int24 -8388608 -8388608 n n 8388607 8388607.996 n y + * Int32 -2147483648 -2147483648 n n 2147483647 2147483647 n n + * + * Conversions are as accurate as possible (with rounding). + * + * Rounding: halves toward +inf, all others to nearest integer. + * + * Clips? shows whether on not there is the possibility of a conversion + * clipping to the minimum or maximum value when inputing from or outputing + * to a given type. + * + * Unsigned integers are converted to and from signed integers by flipping + * the upper-most bit then treating them as signed integers. + */ + +/** +Client API: +Declares the temporary local variables that are required when using SOX +conversion macros. +*/ +#define SOX_SAMPLE_LOCALS sox_sample_t sox_macro_temp_sample LSX_UNUSED; \ + double sox_macro_temp_double LSX_UNUSED + +/** +Client API: +Sign bit for sox_sample_t = 0x80000000. +*/ +#define SOX_SAMPLE_NEG SOX_INT_MIN(32) + +/** +Client API: +Converts sox_sample_t to an unsigned integer of width (bits). +@param bits Width of resulting sample (1 through 32). +@param d Input sample to be converted. +@param clips Variable that is incremented if the result is too big. +@returns Unsigned integer of width (bits). +*/ +#define SOX_SAMPLE_TO_UNSIGNED(bits,d,clips) \ + (sox_uint##bits##_t)(SOX_SAMPLE_TO_SIGNED(bits,d,clips) ^ SOX_INT_MIN(bits)) + +/** +Client API: +Converts sox_sample_t to a signed integer of width (bits). +@param bits Width of resulting sample (1 through 32). +@param d Input sample to be converted. +@param clips Variable that is incremented if the result is too big. +@returns Signed integer of width (bits). +*/ +#define SOX_SAMPLE_TO_SIGNED(bits,d,clips) \ + (sox_int##bits##_t)( \ + LSX_USE_VAR(sox_macro_temp_double), \ + sox_macro_temp_sample = (d), \ + sox_macro_temp_sample > SOX_SAMPLE_MAX - (1 << (31-bits)) ? \ + ++(clips), SOX_INT_MAX(bits) : \ + ((sox_uint32_t)(sox_macro_temp_sample + (1 << (31-bits)))) >> (32-bits)) + +/** +Client API: +Converts signed integer of width (bits) to sox_sample_t. +@param bits Width of input sample (1 through 32). +@param d Input sample to be converted. +@returns SoX native sample value. +*/ +#define SOX_SIGNED_TO_SAMPLE(bits,d) ((sox_sample_t)(d) << (32-bits)) + +/** +Client API: +Converts unsigned integer of width (bits) to sox_sample_t. +@param bits Width of input sample (1 through 32). +@param d Input sample to be converted. +@returns SoX native sample value. +*/ +#define SOX_UNSIGNED_TO_SAMPLE(bits,d) \ + (SOX_SIGNED_TO_SAMPLE(bits,d) ^ SOX_SAMPLE_NEG) + +/** +Client API: +Converts unsigned 8-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_UNSIGNED_8BIT_TO_SAMPLE(d,clips) SOX_UNSIGNED_TO_SAMPLE(8,d) + +/** +Client API: +Converts signed 8-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_SIGNED_8BIT_TO_SAMPLE(d,clips) SOX_SIGNED_TO_SAMPLE(8,d) + +/** +Client API: +Converts unsigned 16-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_UNSIGNED_16BIT_TO_SAMPLE(d,clips) SOX_UNSIGNED_TO_SAMPLE(16,d) + +/** +Client API: +Converts signed 16-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_SIGNED_16BIT_TO_SAMPLE(d,clips) SOX_SIGNED_TO_SAMPLE(16,d) + +/** +Client API: +Converts unsigned 24-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_UNSIGNED_24BIT_TO_SAMPLE(d,clips) SOX_UNSIGNED_TO_SAMPLE(24,d) + +/** +Client API: +Converts signed 24-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_SIGNED_24BIT_TO_SAMPLE(d,clips) SOX_SIGNED_TO_SAMPLE(24,d) + +/** +Client API: +Converts unsigned 32-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_UNSIGNED_32BIT_TO_SAMPLE(d,clips) \ + ((sox_sample_t)(d) ^ SOX_SAMPLE_NEG) + +/** +Client API: +Converts signed 32-bit integer to sox_sample_t. +@param d Input sample to be converted. +@param clips The parameter is not used. +@returns SoX native sample value. +*/ +#define SOX_SIGNED_32BIT_TO_SAMPLE(d,clips) (sox_sample_t)(d) + +/** +Client API: +Converts 32-bit float to sox_sample_t. +@param d Input sample to be converted, range [-1, 1). +@param clips Variable to increment if the input sample is too large or too small. +@returns SoX native sample value. +*/ +#define SOX_FLOAT_32BIT_TO_SAMPLE(d,clips) SOX_FLOAT_64BIT_TO_SAMPLE(d, clips) + +/** +Client API: +Converts 64-bit float to sox_sample_t. +@param d Input sample to be converted, range [-1, 1). +@param clips Variable to increment if the input sample is too large or too small. +@returns SoX native sample value. +*/ +#define SOX_FLOAT_64BIT_TO_SAMPLE(d, clips) \ + (sox_sample_t)( \ + LSX_USE_VAR(sox_macro_temp_sample), \ + sox_macro_temp_double = (d) * (SOX_SAMPLE_MAX + 1.0), \ + sox_macro_temp_double < 0 ? \ + sox_macro_temp_double <= SOX_SAMPLE_MIN - 0.5 ? \ + ++(clips), SOX_SAMPLE_MIN : \ + sox_macro_temp_double - 0.5 : \ + sox_macro_temp_double >= SOX_SAMPLE_MAX + 0.5 ? \ + sox_macro_temp_double > SOX_SAMPLE_MAX + 1.0 ? \ + ++(clips), SOX_SAMPLE_MAX : \ + SOX_SAMPLE_MAX : \ + sox_macro_temp_double + 0.5 \ + ) + +/** +Client API: +Converts SoX native sample to an unsigned 8-bit integer. +@param d Input sample to be converted. +@param clips Variable to increment if input sample is too large. +*/ +#define SOX_SAMPLE_TO_UNSIGNED_8BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(8,d,clips) + +/** +Client API: +Converts SoX native sample to an signed 8-bit integer. +@param d Input sample to be converted. +@param clips Variable to increment if input sample is too large. +*/ +#define SOX_SAMPLE_TO_SIGNED_8BIT(d,clips) SOX_SAMPLE_TO_SIGNED(8,d,clips) + +/** +Client API: +Converts SoX native sample to an unsigned 16-bit integer. +@param d Input sample to be converted. +@param clips Variable to increment if input sample is too large. +*/ +#define SOX_SAMPLE_TO_UNSIGNED_16BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(16,d,clips) + +/** +Client API: +Converts SoX native sample to a signed 16-bit integer. +@param d Input sample to be converted. +@param clips Variable to increment if input sample is too large. +*/ +#define SOX_SAMPLE_TO_SIGNED_16BIT(d,clips) SOX_SAMPLE_TO_SIGNED(16,d,clips) + +/** +Client API: +Converts SoX native sample to an unsigned 24-bit integer. +@param d Input sample to be converted. +@param clips Variable to increment if input sample is too large. +*/ +#define SOX_SAMPLE_TO_UNSIGNED_24BIT(d,clips) SOX_SAMPLE_TO_UNSIGNED(24,d,clips) + +/** +Client API: +Converts SoX native sample to a signed 24-bit integer. +@param d Input sample to be converted. +@param clips Variable to increment if input sample is too large. +*/ +#define SOX_SAMPLE_TO_SIGNED_24BIT(d,clips) SOX_SAMPLE_TO_SIGNED(24,d,clips) + +/** +Client API: +Converts SoX native sample to an unsigned 32-bit integer. +@param d Input sample to be converted. +@param clips The parameter is not used. +*/ +#define SOX_SAMPLE_TO_UNSIGNED_32BIT(d,clips) (sox_uint32_t)((d)^SOX_SAMPLE_NEG) + +/** +Client API: +Converts SoX native sample to a signed 32-bit integer. +@param d Input sample to be converted. +@param clips The parameter is not used. +*/ +#define SOX_SAMPLE_TO_SIGNED_32BIT(d,clips) (sox_int32_t)(d) + +/** +Client API: +Converts SoX native sample to a 32-bit float. +@param d Input sample to be converted. +@param clips The parameter is not used. +*/ +#define SOX_SAMPLE_TO_FLOAT_32BIT(d,clips) ((d)*(1.0 / (SOX_SAMPLE_MAX + 1.0))) + +/** +Client API: +Converts SoX native sample to a 64-bit float. +@param d Input sample to be converted. +@param clips The parameter is not used. +*/ +#define SOX_SAMPLE_TO_FLOAT_64BIT(d,clips) ((d)*(1.0 / (SOX_SAMPLE_MAX + 1.0))) + +/** +Client API: +Clips a value of a type that is larger then sox_sample_t (for example, int64) +to sox_sample_t's limits and increment a counter if clipping occurs. +@param samp Value (lvalue) to be clipped, updated as necessary. +@param clips Value (lvalue) that is incremented if clipping is needed. +*/ +#define SOX_SAMPLE_CLIP_COUNT(samp, clips) \ + do { \ + if (samp > SOX_SAMPLE_MAX) \ + { samp = SOX_SAMPLE_MAX; clips++; } \ + else if (samp < SOX_SAMPLE_MIN) \ + { samp = SOX_SAMPLE_MIN; clips++; } \ + } while (0) + +/** +Client API: +Clips a value of a type that is larger then sox_sample_t (for example, int64) +to sox_sample_t's limits and increment a counter if clipping occurs. +@param d Value (rvalue) to be clipped. +@param clips Value (lvalue) that is incremented if clipping is needed. +@returns Clipped value. +*/ +#define SOX_ROUND_CLIP_COUNT(d, clips) \ + ((d) < 0? (d) <= SOX_SAMPLE_MIN - 0.5? ++(clips), SOX_SAMPLE_MIN: (d) - 0.5 \ + : (d) >= SOX_SAMPLE_MAX + 0.5? ++(clips), SOX_SAMPLE_MAX: (d) + 0.5) + +/** +Client API: +Clips a value to the limits of a signed integer of the specified width +and increment a counter if clipping occurs. +@param bits Width (in bits) of target integer type. +@param i Value (rvalue) to be clipped. +@param clips Value (lvalue) that is incremented if clipping is needed. +@returns Clipped value. +*/ +#define SOX_INTEGER_CLIP_COUNT(bits,i,clips) ( \ + (i) >(1 << ((bits)-1))- 1? ++(clips),(1 << ((bits)-1))- 1 : \ + (i) <-1 << ((bits)-1) ? ++(clips),-1 << ((bits)-1) : (i)) + +/** +Client API: +Clips a value to the limits of a 16-bit signed integer and increment a counter +if clipping occurs. +@param i Value (rvalue) to be clipped. +@param clips Value (lvalue) that is incremented if clipping is needed. +@returns Clipped value. +*/ +#define SOX_16BIT_CLIP_COUNT(i,clips) SOX_INTEGER_CLIP_COUNT(16,i,clips) + +/** +Client API: +Clips a value to the limits of a 24-bit signed integer and increment a counter +if clipping occurs. +@param i Value (rvalue) to be clipped. +@param clips Value (lvalue) that is incremented if clipping is needed. +@returns Clipped value. +*/ +#define SOX_24BIT_CLIP_COUNT(i,clips) SOX_INTEGER_CLIP_COUNT(24,i,clips) + +#define SOX_SIZE_MAX ((size_t)(-1)) /**< Client API: Maximum value of size_t. */ + +#define SOX_UNSPEC 0 /**< Client API: Members of sox_signalinfo_t are set to SOX_UNSPEC (= 0) if the actual value is not yet known. */ +#define SOX_UNKNOWN_LEN (sox_uint64_t)(-1) /**< Client API: sox_signalinfo_t.length is set to SOX_UNKNOWN_LEN (= -1) within the effects chain if the actual length is not known. Format handlers currently use SOX_UNSPEC instead. */ +#define SOX_IGNORE_LENGTH (sox_uint64_t)(-2) /**< Client API: sox_signalinfo_t.length is set to SOX_IGNORE_LENGTH (= -2) to indicate that a format handler should ignore length information in file headers. */ + +#define SOX_DEFAULT_CHANNELS 2 /**< Client API: Default channel count is 2 (stereo). */ +#define SOX_DEFAULT_RATE 48000 /**< Client API: Default rate is 48000Hz. */ +#define SOX_DEFAULT_PRECISION 16 /**< Client API: Default precision is 16 bits per sample. */ +#define SOX_DEFAULT_ENCODING SOX_ENCODING_SIGN2 /**< Client API: Default encoding is SIGN2 (linear 2's complement PCM). */ + +#define SOX_LOOP_NONE ((unsigned char)sox_loop_none) /**< Client API: single-shot = 0 */ +#define SOX_LOOP_8 ((unsigned char)sox_loop_8) /**< Client API: 8 loops = 32 */ +#define SOX_LOOP_SUSTAIN_DECAY ((unsigned char)sox_loop_sustain_decay) /**< Client API: AIFF style, one sustain & one decay loop = 64 */ + +#define SOX_MAX_NLOOPS 8 /**< Client API: Maximum number of loops supported by sox_oob_t = 8. */ + +#define SOX_FILE_NOSTDIO 0x0001 /**< Client API: Does not use stdio routines */ +#define SOX_FILE_DEVICE 0x0002 /**< Client API: File is an audio device */ +#define SOX_FILE_PHONY 0x0004 /**< Client API: Phony file/device (for example /dev/null) */ +#define SOX_FILE_REWIND 0x0008 /**< Client API: File should be rewound to write header */ +#define SOX_FILE_BIT_REV 0x0010 /**< Client API: Is file bit-reversed? */ +#define SOX_FILE_NIB_REV 0x0020 /**< Client API: Is file nibble-reversed? */ +#define SOX_FILE_ENDIAN 0x0040 /**< Client API: Is file format endian? */ +#define SOX_FILE_ENDBIG 0x0080 /**< Client API: For endian file format, is it big endian? */ +#define SOX_FILE_MONO 0x0100 /**< Client API: Do channel restrictions allow mono? */ +#define SOX_FILE_STEREO 0x0200 /**< Client API: Do channel restrictions allow stereo? */ +#define SOX_FILE_QUAD 0x0400 /**< Client API: Do channel restrictions allow quad? */ + +#define SOX_FILE_CHANS (SOX_FILE_MONO | SOX_FILE_STEREO | SOX_FILE_QUAD) /**< Client API: No channel restrictions */ +#define SOX_FILE_LIT_END (SOX_FILE_ENDIAN | 0) /**< Client API: File is little-endian */ +#define SOX_FILE_BIG_END (SOX_FILE_ENDIAN | SOX_FILE_ENDBIG) /**< Client API: File is big-endian */ + +#define SOX_EFF_CHAN 1 /**< Client API: Effect might alter the number of channels */ +#define SOX_EFF_RATE 2 /**< Client API: Effect might alter sample rate */ +#define SOX_EFF_PREC 4 /**< Client API: Effect does its own calculation of output sample precision (otherwise a default value is taken, depending on the presence of SOX_EFF_MODIFY) */ +#define SOX_EFF_LENGTH 8 /**< Client API: Effect might alter audio length (as measured in time units, not necessarily in samples) */ +#define SOX_EFF_MCHAN 16 /**< Client API: Effect handles multiple channels internally */ +#define SOX_EFF_NULL 32 /**< Client API: Effect does nothing (can be optimized out of chain) */ +#define SOX_EFF_DEPRECATED 64 /**< Client API: Effect will soon be removed from SoX */ +#define SOX_EFF_GAIN 128 /**< Client API: Effect does not support gain -r */ +#define SOX_EFF_MODIFY 256 /**< Client API: Effect does not modify sample values (but might remove or duplicate samples or insert zeros) */ +#define SOX_EFF_ALPHA 512 /**< Client API: Effect is experimental/incomplete */ +#define SOX_EFF_INTERNAL 1024 /**< Client API: Effect present in libSoX but not valid for use by SoX command-line tools */ + +/** +Client API: +When used as the "whence" parameter of sox_seek, indicates that the specified +offset is relative to the beginning of the file. +*/ +#define SOX_SEEK_SET 0 + +/***************************************************************************** +Forward declarations: +*****************************************************************************/ + +typedef struct sox_format_t sox_format_t; +typedef struct sox_effect_t sox_effect_t; +typedef struct sox_effect_handler_t sox_effect_handler_t; +typedef struct sox_format_handler_t sox_format_handler_t; + +/***************************************************************************** +Function pointers: +*****************************************************************************/ + +/** +Client API: +Callback to write a message to an output device (console or log file), +used by sox_globals_t.output_message_handler. +*/ +typedef void (LSX_API * sox_output_message_handler_t)( + unsigned level, /**< 1 = FAIL, 2 = WARN, 3 = INFO, 4 = DEBUG, 5 = DEBUG_MORE, 6 = DEBUG_MOST. */ + LSX_PARAM_IN_Z char const * filename, /**< Source code __FILENAME__ from which message originates. */ + LSX_PARAM_IN_PRINTF char const * fmt, /**< Message format string. */ + LSX_PARAM_IN va_list ap /**< Message format parameters. */ + ); + +/** +Client API: +Callback to retrieve information about a format handler, +used by sox_format_tab_t.fn. +@returns format handler information. +*/ +typedef sox_format_handler_t const * (LSX_API * sox_format_fn_t)(void); + +/** +Client API: +Callback to get information about an effect handler, +used by the table returned from sox_get_effect_fns(void). +@returns Pointer to information about an effect handler. +*/ +typedef sox_effect_handler_t const * (LSX_API *sox_effect_fn_t)(void); + +/** +Client API: +Callback to initialize reader (decoder), used by +sox_format_handler.startread. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_format_handler_startread)( + LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */ + ); + +/** +Client API: +Callback to read (decode) a block of samples, +used by sox_format_handler.read. +@returns number of samples read, or 0 if unsuccessful. +*/ +typedef size_t (LSX_API * sox_format_handler_read)( + LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */ + LSX_PARAM_OUT_CAP_POST_COUNT(len,return) sox_sample_t *buf, /**< Buffer from which to read samples. */ + size_t len /**< Number of samples available in buf. */ + ); + +/** +Client API: +Callback to close reader (decoder), +used by sox_format_handler.stopread. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_format_handler_stopread)( + LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */ + ); + +/** +Client API: +Callback to initialize writer (encoder), +used by sox_format_handler.startwrite. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_format_handler_startwrite)( + LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */ + ); + +/** +Client API: +Callback to write (encode) a block of samples, +used by sox_format_handler.write. +@returns number of samples written, or 0 if unsuccessful. +*/ +typedef size_t (LSX_API * sox_format_handler_write)( + LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */ + LSX_PARAM_IN_COUNT(len) sox_sample_t const * buf, /**< Buffer to which samples are written. */ + size_t len /**< Capacity of buf, measured in samples. */ + ); + +/** +Client API: +Callback to close writer (decoder), +used by sox_format_handler.stopwrite. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_format_handler_stopwrite)( + LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */ + ); + +/** +Client API: +Callback to reposition reader, +used by sox_format_handler.seek. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_format_handler_seek)( + LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */ + sox_uint64_t offset /**< Sample offset to which reader should be positioned. */ + ); + +/** +Client API: +Callback to parse command-line arguments (called once per effect), +used by sox_effect_handler.getopts. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_effect_handler_getopts)( + LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect pointer. */ + int argc, /**< Number of arguments in argv. */ + LSX_PARAM_IN_COUNT(argc) char *argv[] /**< Array of command-line arguments. */ + ); + +/** +Client API: +Callback to initialize effect (called once per flow), +used by sox_effect_handler.start. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_effect_handler_start)( + LSX_PARAM_INOUT sox_effect_t * effp /**< Effect pointer. */ + ); + +/** +Client API: +Callback to process samples, +used by sox_effect_handler.flow. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_effect_handler_flow)( + LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect pointer. */ + LSX_PARAM_IN_COUNT(*isamp) sox_sample_t const * ibuf, /**< Buffer from which to read samples. */ + LSX_PARAM_OUT_CAP_POST_COUNT(*osamp,*osamp) sox_sample_t * obuf, /**< Buffer to which samples are written. */ + LSX_PARAM_INOUT size_t *isamp, /**< On entry, contains capacity of ibuf; on exit, contains number of samples consumed. */ + LSX_PARAM_INOUT size_t *osamp /**< On entry, contains capacity of obuf; on exit, contains number of samples written. */ + ); + +/** +Client API: +Callback to finish getting output after input is complete, +used by sox_effect_handler.drain. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_effect_handler_drain)( + LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect pointer. */ + LSX_PARAM_OUT_CAP_POST_COUNT(*osamp,*osamp) sox_sample_t *obuf, /**< Buffer to which samples are written. */ + LSX_PARAM_INOUT size_t *osamp /**< On entry, contains capacity of obuf; on exit, contains number of samples written. */ + ); + +/** +Client API: +Callback to shut down effect (called once per flow), +used by sox_effect_handler.stop. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_effect_handler_stop)( + LSX_PARAM_INOUT sox_effect_t * effp /**< Effect pointer. */ + ); + +/** +Client API: +Callback to shut down effect (called once per effect), +used by sox_effect_handler.kill. +@returns SOX_SUCCESS if successful. +*/ +typedef int (LSX_API * sox_effect_handler_kill)( + LSX_PARAM_INOUT sox_effect_t * effp /**< Effect pointer. */ + ); + +/** +Client API: +Callback called while flow is running (called once per buffer), +used by sox_flow_effects.callback. +@returns SOX_SUCCESS to continue, other value to abort flow. +*/ +typedef int (LSX_API * sox_flow_effects_callback)( + sox_bool all_done, + void * client_data + ); + +/** +Client API: +Callback for enumerating the contents of a playlist, +used by the sox_parse_playlist function. +@returns SOX_SUCCESS if successful, any other value to abort playlist enumeration. +*/ +typedef int (LSX_API * sox_playlist_callback_t)( + void * callback_data, + LSX_PARAM_IN_Z char const * filename + ); + +/***************************************************************************** +Structures: +*****************************************************************************/ + +/** +Client API: +Information about a build of libSoX, returned from the sox_version_info +function. +*/ +typedef struct sox_version_info_t { + size_t size; /**< structure size = sizeof(sox_version_info_t) */ + sox_version_flags_t flags; /**< feature flags = popen | magic | threads | memopen */ + sox_uint32_t version_code; /**< version number = 0x140400 */ + char const * version; /**< version string = sox_version(), for example, "14.4.0" */ + char const * version_extra;/**< version extra info or null = "PACKAGE_EXTRA", for example, "beta" */ + char const * time; /**< build time = "__DATE__ __TIME__", for example, "Jan 7 2010 03:31:50" */ + char const * distro; /**< distro or null = "DISTRO", for example, "Debian" */ + char const * compiler; /**< compiler info or null, for example, "msvc 160040219" */ + char const * arch; /**< arch, for example, "1248 48 44 L OMP" */ + /* new info should be added at the end for version backwards-compatibility. */ +} sox_version_info_t; + +/** +Client API: +Global parameters (for effects & formats), returned from the sox_get_globals +function. +*/ +typedef struct sox_globals_t { +/* public: */ + unsigned verbosity; /**< messages are only written if globals.verbosity >= message.level */ + sox_output_message_handler_t output_message_handler; /**< client-specified message output callback */ + sox_bool repeatable; /**< true to use pre-determined timestamps and PRNG seed */ + + /** + Default size (in bytes) used by libSoX for blocks of sample data. + Plugins should use similarly-sized buffers to get best performance. + */ + size_t bufsiz; + + /** + Default size (in bytes) used by libSoX for blocks of input sample data. + Plugins should use similarly-sized buffers to get best performance. + */ + size_t input_bufsiz; + + sox_int32_t ranqd1; /**< Can be used to re-seed libSoX's PRNG */ + + char const * stdin_in_use_by; /**< Private: tracks the name of the handler currently using stdin */ + char const * stdout_in_use_by; /**< Private: tracks the name of the handler currently using stdout */ + char const * subsystem; /**< Private: tracks the name of the handler currently writing an output message */ + char * tmp_path; /**< Private: client-configured path to use for temporary files */ + sox_bool use_magic; /**< Private: true if client has requested use of 'magic' file-type detection */ + sox_bool use_threads; /**< Private: true if client has requested parallel effects processing */ + + /** + Log to base 2 of minimum size (in bytes) used by libSoX for DFT (filtering). + Plugins should use similarly-sized DFTs to get best performance. + */ + size_t log2_dft_min_size; +} sox_globals_t; + +/** +Client API: +Signal parameters; members should be set to SOX_UNSPEC (= 0) if unknown. +*/ +typedef struct sox_signalinfo_t { + sox_rate_t rate; /**< samples per second, 0 if unknown */ + unsigned channels; /**< number of sound channels, 0 if unknown */ + unsigned precision; /**< bits per sample, 0 if unknown */ + sox_uint64_t length; /**< samples * chans in file, 0 if unknown, -1 if unspecified */ + double * mult; /**< Effects headroom multiplier; may be null */ +} sox_signalinfo_t; + +/** +Client API: +Basic information about an encoding. +*/ +typedef struct sox_encodings_info_t { + sox_encodings_flags_t flags; /**< lossy once (lossy1), lossy twice (lossy2), or lossless (none). */ + char const * name; /**< encoding name. */ + char const * desc; /**< encoding description. */ +} sox_encodings_info_t; + +/** +Client API: +Encoding parameters. +*/ +typedef struct sox_encodinginfo_t { + sox_encoding_t encoding; /**< format of sample numbers */ + unsigned bits_per_sample;/**< 0 if unknown or variable; uncompressed value if lossless; compressed value if lossy */ + double compression; /**< compression factor (where applicable) */ + + /** + Should bytes be reversed? If this is default during sox_open_read or + sox_open_write, libSoX will set them to either no or yes according to the + machine or format default. + */ + sox_option_t reverse_bytes; + + /** + Should nibbles be reversed? If this is default during sox_open_read or + sox_open_write, libSoX will set them to either no or yes according to the + machine or format default. + */ + sox_option_t reverse_nibbles; + + /** + Should bits be reversed? If this is default during sox_open_read or + sox_open_write, libSoX will set them to either no or yes according to the + machine or format default. + */ + sox_option_t reverse_bits; + + /** + If set to true, the format should reverse its default endianness. + */ + sox_bool opposite_endian; +} sox_encodinginfo_t; + +/** +Client API: +Looping parameters (out-of-band data). +*/ +typedef struct sox_loopinfo_t { + sox_uint64_t start; /**< first sample */ + sox_uint64_t length; /**< length */ + unsigned count; /**< number of repeats, 0=forever */ + unsigned char type; /**< 0=no, 1=forward, 2=forward/back (see sox_loop_* for valid values). */ +} sox_loopinfo_t; + +/** +Client API: +Instrument information. +*/ +typedef struct sox_instrinfo_t{ + signed char MIDInote; /**< for unity pitch playback */ + signed char MIDIlow; /**< MIDI pitch-bend low range */ + signed char MIDIhi; /**< MIDI pitch-bend high range */ + unsigned char loopmode; /**< 0=no, 1=forward, 2=forward/back (see sox_loop_* values) */ + unsigned nloops; /**< number of active loops (max SOX_MAX_NLOOPS). */ +} sox_instrinfo_t; + +/** +Client API: +File buffer info. Holds info so that data can be read in blocks. +*/ +typedef struct sox_fileinfo_t { + char *buf; /**< Pointer to data buffer */ + size_t size; /**< Size of buffer in bytes */ + size_t count; /**< Count read into buffer */ + size_t pos; /**< Position in buffer */ +} sox_fileinfo_t; + +/** +Client API: +Handler structure defined by each format. +*/ +struct sox_format_handler_t { + unsigned sox_lib_version_code; /**< Checked on load; must be 1st in struct*/ + char const * description; /**< short description of format */ + char const * const * names; /**< null-terminated array of filename extensions that are handled by this format */ + unsigned int flags; /**< File flags (SOX_FILE_* values). */ + sox_format_handler_startread startread; /**< called to initialize reader (decoder) */ + sox_format_handler_read read; /**< called to read (decode) a block of samples */ + sox_format_handler_stopread stopread; /**< called to close reader (decoder); may be null if no closing necessary */ + sox_format_handler_startwrite startwrite; /**< called to initialize writer (encoder) */ + sox_format_handler_write write; /**< called to write (encode) a block of samples */ + sox_format_handler_stopwrite stopwrite; /**< called to close writer (decoder); may be null if no closing necessary */ + sox_format_handler_seek seek; /**< called to reposition reader; may be null if not supported */ + + /** + Array of values indicating the encodings and precisions supported for + writing (encoding). Precisions specified with default precision first. + Encoding, precision, precision, ..., 0, repeat. End with one more 0. + Example: + unsigned const * formats = { + SOX_ENCODING_SIGN2, 16, 24, 0, // Support SIGN2 at 16 and 24 bits, default to 16 bits. + SOX_ENCODING_UNSIGNED, 8, 0, // Support UNSIGNED at 8 bits, default to 8 bits. + 0 // No more supported encodings. + }; + */ + unsigned const * write_formats; + + /** + Array of sample rates (samples per second) supported for writing (encoding). + NULL if all (or almost all) rates are supported. End with 0. + */ + sox_rate_t const * write_rates; + + /** + SoX will automatically allocate a buffer in which the handler can store data. + Specify the size of the buffer needed here. Usually this will be sizeof(your_struct). + The buffer will be allocated and zeroed before the call to startread/startwrite. + The buffer will be freed after the call to stopread/stopwrite. + The buffer will be provided via format.priv in each call to the handler. + */ + size_t priv_size; +}; + +/** +Client API: +Comments, instrument info, loop info (out-of-band data). +*/ +typedef struct sox_oob_t{ + /* Decoded: */ + sox_comments_t comments; /**< Comment strings in id=value format. */ + sox_instrinfo_t instr; /**< Instrument specification */ + sox_loopinfo_t loops[SOX_MAX_NLOOPS]; /**< Looping specification */ + + /* TBD: Non-decoded chunks, etc: */ +} sox_oob_t; + +/** +Client API: +Data passed to/from the format handler +*/ +struct sox_format_t { + char * filename; /**< File name */ + + /** + Signal specifications for reader (decoder) or writer (encoder): + sample rate, number of channels, precision, length, headroom multiplier. + Any info specified by the user is here on entry to startread or + startwrite. Info will be SOX_UNSPEC if the user provided no info. + At exit from startread, should be completely filled in, using + either data from the file's headers (if available) or whatever + the format is guessing/assuming (if header data is not available). + At exit from startwrite, should be completely filled in, using + either the data that was specified, or values chosen by the format + based on the format's defaults or capabilities. + */ + sox_signalinfo_t signal; + + /** + Encoding specifications for reader (decoder) or writer (encoder): + encoding (sample format), bits per sample, compression rate, endianness. + Should be filled in by startread. Values specified should be used + by startwrite when it is configuring the encoding parameters. + */ + sox_encodinginfo_t encoding; + + char * filetype; /**< Type of file, as determined by header inspection or libmagic. */ + sox_oob_t oob; /**< comments, instrument info, loop info (out-of-band data) */ + sox_bool seekable; /**< Can seek on this file */ + char mode; /**< Read or write mode ('r' or 'w') */ + sox_uint64_t olength; /**< Samples * chans written to file */ + sox_uint64_t clips; /**< Incremented if clipping occurs */ + int sox_errno; /**< Failure error code */ + char sox_errstr[256]; /**< Failure error text */ + void * fp; /**< File stream pointer */ + lsx_io_type io_type; /**< Stores whether this is a file, pipe or URL */ + sox_uint64_t tell_off; /**< Current offset within file */ + sox_uint64_t data_start; /**< Offset at which headers end and sound data begins (set by lsx_check_read_params) */ + sox_format_handler_t handler; /**< Format handler for this file */ + void * priv; /**< Format handler's private data area */ +}; + +/** +Client API: +Information about a loaded format handler, including the format name and a +function pointer that can be invoked to get additional information about the +format. +*/ +typedef struct sox_format_tab_t { + char *name; /**< Name of format handler */ + sox_format_fn_t fn; /**< Function to call to get format handler's information */ +} sox_format_tab_t; + +/** +Client API: +Global parameters for effects. +*/ +typedef struct sox_effects_globals_t { + sox_plot_t plot; /**< To help the user choose effect & options */ + sox_globals_t * global_info; /**< Pointer to associated SoX globals */ +} sox_effects_globals_t; + +/** +Client API: +Effect handler information. +*/ +struct sox_effect_handler_t { + char const * name; /**< Effect name */ + char const * usage; /**< Short explanation of parameters accepted by effect */ + unsigned int flags; /**< Combination of SOX_EFF_* flags */ + sox_effect_handler_getopts getopts; /**< Called to parse command-line arguments (called once per effect). */ + sox_effect_handler_start start; /**< Called to initialize effect (called once per flow). */ + sox_effect_handler_flow flow; /**< Called to process samples. */ + sox_effect_handler_drain drain; /**< Called to finish getting output after input is complete. */ + sox_effect_handler_stop stop; /**< Called to shut down effect (called once per flow). */ + sox_effect_handler_kill kill; /**< Called to shut down effect (called once per effect). */ + size_t priv_size; /**< Size of private data SoX should pre-allocate for effect */ +}; + +/** +Client API: +Effect information. +*/ +struct sox_effect_t { + sox_effects_globals_t * global_info; /**< global effect parameters */ + sox_signalinfo_t in_signal; /**< Information about the incoming data stream */ + sox_signalinfo_t out_signal; /**< Information about the outgoing data stream */ + sox_encodinginfo_t const * in_encoding; /**< Information about the incoming data encoding */ + sox_encodinginfo_t const * out_encoding; /**< Information about the outgoing data encoding */ + sox_effect_handler_t handler; /**< The handler for this effect */ + sox_uint64_t clips; /**< increment if clipping occurs */ + size_t flows; /**< 1 if MCHAN, number of chans otherwise */ + size_t flow; /**< flow number */ + void * priv; /**< Effect's private data area (each flow has a separate copy) */ + /* The following items are private to the libSoX effects chain functions. */ + sox_sample_t * obuf; /**< output buffer */ + size_t obeg; /**< output buffer: start of valid data section */ + size_t oend; /**< output buffer: one past valid data section (oend-obeg is length of current content) */ + size_t imin; /**< minimum input buffer content required for calling this effect's flow function; set via lsx_effect_set_imin() */ +}; + +/** +Client API: +Chain of effects to be applied to a stream. +*/ +typedef struct sox_effects_chain_t { + sox_effect_t **effects; /**< Table of effects to be applied to a stream */ + size_t length; /**< Number of effects to be applied */ + sox_effects_globals_t global_info; /**< Copy of global effects settings */ + sox_encodinginfo_t const * in_enc; /**< Input encoding */ + sox_encodinginfo_t const * out_enc; /**< Output encoding */ + /* The following items are private to the libSoX effects chain functions. */ + size_t table_size; /**< Size of effects table (including unused entries) */ + sox_sample_t *il_buf; /**< Channel interleave buffer */ +} sox_effects_chain_t; + +/***************************************************************************** +Functions: +*****************************************************************************/ + +/** +Client API: +Returns version number string of libSoX, for example, "14.4.0". +@returns The version number string of libSoX, for example, "14.4.0". +*/ +LSX_RETURN_VALID_Z +char const * +LSX_API +sox_version(void); + +/** +Client API: +Returns information about this build of libsox. +@returns Pointer to a version information structure. +*/ +LSX_RETURN_VALID LSX_RETURN_PURE +sox_version_info_t const * +LSX_API +sox_version_info(void); + +/** +Client API: +Returns a pointer to the structure with libSoX's global settings. +@returns a pointer to the structure with libSoX's global settings. +*/ +LSX_RETURN_VALID LSX_RETURN_PURE +sox_globals_t * +LSX_API +sox_get_globals(void); + +/** +Client API: +Deprecated macro that returns the structure with libSoX's global settings +as an lvalue. +*/ +#define sox_globals (*sox_get_globals()) + +/** +Client API: +Returns a pointer to the list of available encodings. +End of list indicated by name == NULL. +@returns pointer to the list of available encodings. +*/ +LSX_RETURN_ARRAY LSX_RETURN_PURE +sox_encodings_info_t const * +LSX_API +sox_get_encodings_info(void); + +/** +Client API: +Deprecated macro that returns the list of available encodings. +End of list indicated by name == NULL. +*/ +#define sox_encodings_info (sox_get_encodings_info()) + +/** +Client API: +Fills in an encodinginfo with default values. +*/ +void +LSX_API +sox_init_encodinginfo( + LSX_PARAM_OUT sox_encodinginfo_t * e /**< Pointer to uninitialized encoding info structure to be initialized. */ + ); + +/** +Client API: +Given an encoding (for example, SIGN2) and the encoded bits_per_sample (for +example, 16), returns the number of useful bits per sample in the decoded data +(for example, 16), or returns 0 to indicate that the value returned by the +format handler should be used instead of a pre-determined precision. +@returns the number of useful bits per sample in the decoded data (for example +16), or returns 0 to indicate that the value returned by the format handler +should be used instead of a pre-determined precision. +*/ +LSX_RETURN_PURE +unsigned +LSX_API +sox_precision( + sox_encoding_t encoding, /**< Encoding for which to lookup precision information. */ + unsigned bits_per_sample /**< The number of encoded bits per sample. */ + ); + +/** +Client API: +Returns the number of items in the metadata block. +@returns the number of items in the metadata block. +*/ +size_t +LSX_API +sox_num_comments( + LSX_PARAM_IN_OPT sox_comments_t comments /**< Metadata block. */ + ); + +/** +Client API: +Adds an "id=value" item to the metadata block. +*/ +void +LSX_API +sox_append_comment( + LSX_PARAM_DEREF_PRE_MAYBENULL LSX_PARAM_DEREF_POST_NOTNULL sox_comments_t * comments, /**< Metadata block. */ + LSX_PARAM_IN_Z char const * item /**< Item to be added in "id=value" format. */ + ); + +/** +Client API: +Adds a newline-delimited list of "id=value" items to the metadata block. +*/ +void +LSX_API +sox_append_comments( + LSX_PARAM_DEREF_PRE_MAYBENULL LSX_PARAM_DEREF_POST_NOTNULL sox_comments_t * comments, /**< Metadata block. */ + LSX_PARAM_IN_Z char const * items /**< Newline-separated list of items to be added, for example "id1=value1\\nid2=value2". */ + ); + +/** +Client API: +Duplicates the metadata block. +@returns the copied metadata block. +*/ +LSX_RETURN_OPT +sox_comments_t +LSX_API +sox_copy_comments( + LSX_PARAM_IN_OPT sox_comments_t comments /**< Metadata block to copy. */ + ); + +/** +Client API: +Frees the metadata block. +*/ +void +LSX_API +sox_delete_comments( + LSX_PARAM_DEREF_PRE_MAYBENULL LSX_PARAM_DEREF_POST_NULL sox_comments_t * comments /**< Metadata block. */ + ); + +/** +Client API: +If "id=value" is found, return value, else return null. +@returns value, or null if value not found. +*/ +LSX_RETURN_OPT +char const * +LSX_API +sox_find_comment( + LSX_PARAM_IN_OPT sox_comments_t comments, /**< Metadata block in which to search. */ + LSX_PARAM_IN_Z char const * id /**< Id for which to search */ + ); + +/** +Client API: +Find and load format handler plugins. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_format_init(void); + +/** +Client API: +Unload format handler plugins. +*/ +void +LSX_API +sox_format_quit(void); + +/** +Client API: +Initialize effects library. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_init(void); + +/** +Client API: +Close effects library and unload format handler plugins. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_quit(void); + +/** +Client API: +Returns the table of format handler names and functions. +@returns the table of format handler names and functions. +*/ +LSX_RETURN_ARRAY LSX_RETURN_PURE +sox_format_tab_t const * +LSX_API +sox_get_format_fns(void); + +/** +Client API: +Deprecated macro that returns the table of format handler names and functions. +*/ +#define sox_format_fns (sox_get_format_fns()) + +/** +Client API: +Opens a decoding session for a file. Returned handle must be closed with sox_close(). +@returns The handle for the new session, or null on failure. +*/ +LSX_RETURN_OPT +sox_format_t * +LSX_API +sox_open_read( + LSX_PARAM_IN_Z char const * path, /**< Path to file to be opened (required). */ + LSX_PARAM_IN_OPT sox_signalinfo_t const * signal, /**< Information already known about audio stream, or NULL if none. */ + LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information already known about sample encoding, or NULL if none. */ + LSX_PARAM_IN_OPT_Z char const * filetype /**< Previously-determined file type, or NULL to auto-detect. */ + ); + +/** +Client API: +Opens a decoding session for a memory buffer. Returned handle must be closed with sox_close(). +@returns The handle for the new session, or null on failure. +*/ +LSX_RETURN_OPT +sox_format_t * +LSX_API +sox_open_mem_read( + LSX_PARAM_IN_BYTECOUNT(buffer_size) void * buffer, /**< Pointer to audio data buffer (required). */ + size_t buffer_size,/**< Number of bytes to read from audio data buffer. */ + LSX_PARAM_IN_OPT sox_signalinfo_t const * signal, /**< Information already known about audio stream, or NULL if none. */ + LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information already known about sample encoding, or NULL if none. */ + LSX_PARAM_IN_OPT_Z char const * filetype /**< Previously-determined file type, or NULL to auto-detect. */ + ); + +/** +Client API: +Returns true if the format handler for the specified file type supports the specified encoding. +@returns true if the format handler for the specified file type supports the specified encoding. +*/ +sox_bool +LSX_API +sox_format_supports_encoding( + LSX_PARAM_IN_OPT_Z char const * path, /**< Path to file to be examined (required if filetype is NULL). */ + LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to use extension from path. */ + LSX_PARAM_IN sox_encodinginfo_t const * encoding /**< Encoding for which format handler should be queried. */ + ); + +/** +Client API: +Gets the format handler for a specified file type. +@returns The found format handler, or null if not found. +*/ +LSX_RETURN_OPT +sox_format_handler_t const * +LSX_API +sox_write_handler( + LSX_PARAM_IN_OPT_Z char const * path, /**< Path to file (required if filetype is NULL). */ + LSX_PARAM_IN_OPT_Z char const * filetype, /**< Filetype for which handler is needed, or NULL to use extension from path. */ + LSX_PARAM_OUT_OPT char const * * filetype1 /**< Receives the filetype that was detected. Pass NULL if not needed. */ + ); + +/** +Client API: +Opens an encoding session for a file. Returned handle must be closed with sox_close(). +@returns The new session handle, or null on failure. +*/ +LSX_RETURN_OPT +sox_format_t * +LSX_API +sox_open_write( + LSX_PARAM_IN_Z char const * path, /**< Path to file to be written (required). */ + LSX_PARAM_IN sox_signalinfo_t const * signal, /**< Information about desired audio stream (required). */ + LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information about desired sample encoding, or NULL to use defaults. */ + LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to auto-detect. */ + LSX_PARAM_IN_OPT sox_oob_t const * oob, /**< Out-of-band data to add to file, or NULL if none. */ + LSX_PARAM_IN_OPT sox_bool (LSX_API * overwrite_permitted)(LSX_PARAM_IN_Z char const * filename) /**< Called if file exists to determine whether overwrite is ok. */ + ); + +/** +Client API: +Opens an encoding session for a memory buffer. Returned handle must be closed with sox_close(). +@returns The new session handle, or null on failure. +*/ +LSX_RETURN_OPT +sox_format_t * +LSX_API +sox_open_mem_write( + LSX_PARAM_OUT_BYTECAP(buffer_size) void * buffer, /**< Pointer to audio data buffer that receives data (required). */ + LSX_PARAM_IN size_t buffer_size, /**< Maximum number of bytes to write to audio data buffer. */ + LSX_PARAM_IN sox_signalinfo_t const * signal, /**< Information about desired audio stream (required). */ + LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information about desired sample encoding, or NULL to use defaults. */ + LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to auto-detect. */ + LSX_PARAM_IN_OPT sox_oob_t const * oob /**< Out-of-band data to add to file, or NULL if none. */ + ); + +/** +Client API: +Opens an encoding session for a memstream buffer. Returned handle must be closed with sox_close(). +@returns The new session handle, or null on failure. +*/ +LSX_RETURN_OPT +sox_format_t * +LSX_API +sox_open_memstream_write( + LSX_PARAM_OUT char * * buffer_ptr, /**< Receives pointer to audio data buffer that receives data (required). */ + LSX_PARAM_OUT size_t * buffer_size_ptr, /**< Receives size of data written to audio data buffer (required). */ + LSX_PARAM_IN sox_signalinfo_t const * signal, /**< Information about desired audio stream (required). */ + LSX_PARAM_IN_OPT sox_encodinginfo_t const * encoding, /**< Information about desired sample encoding, or NULL to use defaults. */ + LSX_PARAM_IN_OPT_Z char const * filetype, /**< Previously-determined file type, or NULL to auto-detect. */ + LSX_PARAM_IN_OPT sox_oob_t const * oob /**< Out-of-band data to add to file, or NULL if none. */ + ); + +/** +Client API: +Reads samples from a decoding session into a sample buffer. +@returns Number of samples decoded, or 0 for EOF. +*/ +size_t +LSX_API +sox_read( + LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */ + LSX_PARAM_OUT_CAP_POST_COUNT(len,return) sox_sample_t *buf, /**< Buffer from which to read samples. */ + size_t len /**< Number of samples available in buf. */ + ); + +/** +Client API: +Writes samples to an encoding session from a sample buffer. +@returns Number of samples encoded. +*/ +size_t +LSX_API +sox_write( + LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */ + LSX_PARAM_IN_COUNT(len) sox_sample_t const * buf, /**< Buffer from which to read samples. */ + size_t len /**< Number of samples available in buf. */ + ); + +/** +Client API: +Closes an encoding or decoding session. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_close( + LSX_PARAM_INOUT sox_format_t * ft /**< Format pointer. */ + ); + +/** +Client API: +Sets the location at which next samples will be decoded. Returns SOX_SUCCESS if successful. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_seek( + LSX_PARAM_INOUT sox_format_t * ft, /**< Format pointer. */ + sox_uint64_t offset, /**< Sample offset at which to position reader. */ + int whence /**< Set to SOX_SEEK_SET. */ + ); + +/** +Client API: +Finds a format handler by name. +@returns Format handler data, or null if not found. +*/ +LSX_RETURN_OPT +sox_format_handler_t const * +LSX_API +sox_find_format( + LSX_PARAM_IN_Z char const * name, /**< Name of format handler to find. */ + sox_bool ignore_devices /**< Set to true to ignore device names. */ + ); + +/** +Client API: +Returns global parameters for effects +@returns global parameters for effects. +*/ +LSX_RETURN_VALID LSX_RETURN_PURE +sox_effects_globals_t * +LSX_API +sox_get_effects_globals(void); + +/** +Client API: +Deprecated macro that returns global parameters for effects. +*/ +#define sox_effects_globals (*sox_get_effects_globals()) + +/** +Client API: +Finds the effect handler with the given name. +@returns Effect pointer, or null if not found. +*/ +LSX_RETURN_OPT LSX_RETURN_PURE +sox_effect_handler_t const * +LSX_API +sox_find_effect( + LSX_PARAM_IN_Z char const * name /**< Name of effect to find. */ + ); + +/** +Client API: +Creates an effect using the given handler. +@returns The new effect, or null if not found. +*/ +LSX_RETURN_OPT +sox_effect_t * +LSX_API +sox_create_effect( + LSX_PARAM_IN sox_effect_handler_t const * eh /**< Handler to use for effect. */ + ); + +/** +Client API: +Applies the command-line options to the effect. +@returns the number of arguments consumed. +*/ +int +LSX_API +sox_effect_options( + LSX_PARAM_IN sox_effect_t *effp, /**< Effect pointer on which to set options. */ + int argc, /**< Number of arguments in argv. */ + LSX_PARAM_IN_COUNT(argc) char * const argv[] /**< Array of command-line options. */ + ); + +/** +Client API: +Returns an array containing the known effect handlers. +@returns An array containing the known effect handlers. +*/ +LSX_RETURN_VALID_Z LSX_RETURN_PURE +sox_effect_fn_t const * +LSX_API +sox_get_effect_fns(void); + +/** +Client API: +Deprecated macro that returns an array containing the known effect handlers. +*/ +#define sox_effect_fns (sox_get_effect_fns()) + +/** +Client API: +Initializes an effects chain. Returned handle must be closed with sox_delete_effects_chain(). +@returns Handle, or null on failure. +*/ +LSX_RETURN_OPT +sox_effects_chain_t * +LSX_API +sox_create_effects_chain( + LSX_PARAM_IN sox_encodinginfo_t const * in_enc, /**< Input encoding. */ + LSX_PARAM_IN sox_encodinginfo_t const * out_enc /**< Output encoding. */ + ); + +/** +Client API: +Closes an effects chain. +*/ +void +LSX_API +sox_delete_effects_chain( + LSX_PARAM_INOUT sox_effects_chain_t *ecp /**< Effects chain pointer. */ + ); + +/** +Client API: +Adds an effect to the effects chain, returns SOX_SUCCESS if successful. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_add_effect( + LSX_PARAM_INOUT sox_effects_chain_t * chain, /**< Effects chain to which effect should be added . */ + LSX_PARAM_INOUT sox_effect_t * effp, /**< Effect to be added. */ + LSX_PARAM_INOUT sox_signalinfo_t * in, /**< Input format. */ + LSX_PARAM_IN sox_signalinfo_t const * out /**< Output format. */ + ); + +/** +Client API: +Runs the effects chain, returns SOX_SUCCESS if successful. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_flow_effects( + LSX_PARAM_INOUT sox_effects_chain_t * chain, /**< Effects chain to run. */ + LSX_PARAM_IN_OPT sox_flow_effects_callback callback, /**< Callback for monitoring flow progress. */ + LSX_PARAM_IN_OPT void * client_data /**< Data to pass into callback. */ + ); + +/** +Client API: +Gets the number of clips that occurred while running an effects chain. +@returns the number of clips that occurred while running an effects chain. +*/ +sox_uint64_t +LSX_API +sox_effects_clips( + LSX_PARAM_IN sox_effects_chain_t * chain /**< Effects chain from which to read clip information. */ + ); + +/** +Client API: +Shuts down an effect (calls stop on each of its flows). +@returns the number of clips from all flows. +*/ +sox_uint64_t +LSX_API +sox_stop_effect( + LSX_PARAM_INOUT_COUNT(effp->flows) sox_effect_t * effp /**< Effect to stop. */ + ); + +/** +Client API: +Adds an already-initialized effect to the end of the chain. +*/ +void +LSX_API +sox_push_effect_last( + LSX_PARAM_INOUT sox_effects_chain_t * chain, /**< Effects chain to which effect should be added. */ + LSX_PARAM_INOUT sox_effect_t * effp /**< Effect to be added. */ + ); + +/** +Client API: +Removes and returns an effect from the end of the chain. +@returns the removed effect, or null if no effects. +*/ +LSX_RETURN_OPT +sox_effect_t * +LSX_API +sox_pop_effect_last( + LSX_PARAM_INOUT sox_effects_chain_t *chain /**< Effects chain from which to remove an effect. */ + ); + +/** +Client API: +Shut down and delete an effect. +*/ +void +LSX_API +sox_delete_effect( + LSX_PARAM_INOUT_COUNT(effp->flows) sox_effect_t *effp /**< Effect to be deleted. */ + ); + +/** +Client API: +Shut down and delete the last effect in the chain. +*/ +void +LSX_API +sox_delete_effect_last( + LSX_PARAM_INOUT sox_effects_chain_t *chain /**< Effects chain from which to remove the last effect. */ + ); + +/** +Client API: +Shut down and delete all effects in the chain. +*/ +void +LSX_API +sox_delete_effects( + LSX_PARAM_INOUT sox_effects_chain_t *chain /**< Effects chain from which to delete effects. */ + ); + +/** +Client API: +Gets the sample offset of the start of the trim, useful for efficiently +skipping the part that will be trimmed anyway (get trim start, seek, then +clear trim start). +@returns the sample offset of the start of the trim. +*/ +sox_uint64_t +LSX_API +sox_trim_get_start( + LSX_PARAM_IN sox_effect_t * effp /**< Trim effect. */ + ); + +/** +Client API: +Clears the start of the trim to 0. +*/ +void +LSX_API +sox_trim_clear_start( + LSX_PARAM_INOUT sox_effect_t * effp /**< Trim effect. */ + ); + +/** +Client API: +Returns true if the specified file is a known playlist file type. +@returns true if the specified file is a known playlist file type. +*/ +sox_bool +LSX_API +sox_is_playlist( + LSX_PARAM_IN_Z char const * filename /**< Name of file to examine. */ + ); + +/** +Client API: +Parses the specified playlist file. +@returns SOX_SUCCESS if successful. +*/ +int +LSX_API +sox_parse_playlist( + LSX_PARAM_IN sox_playlist_callback_t callback, /**< Callback to call for each item in the playlist. */ + void * p, /**< Data to pass to callback. */ + LSX_PARAM_IN char const * const listname /**< Filename of playlist file. */ + ); + +/** +Client API: +Converts a SoX error code into an error string. +@returns error string corresponding to the specified error code, +or a generic message if the error code is not recognized. +*/ +LSX_RETURN_VALID_Z LSX_RETURN_PURE +char const * +LSX_API +sox_strerror( + int sox_errno /**< Error code to look up. */ + ); + +/** +Client API: +Gets the basename of the specified file; for example, the basename of +"/a/b/c.d" would be "c". +@returns the number of characters written to base_buffer, excluding the null, +or 0 on failure. +*/ +size_t +LSX_API +sox_basename( + LSX_PARAM_OUT_Z_CAP_POST_COUNT(base_buffer_len,return) char * base_buffer, /**< Buffer into which basename should be written. */ + size_t base_buffer_len, /**< Size of base_buffer, in bytes. */ + LSX_PARAM_IN_Z char const * filename /**< Filename from which to extract basename. */ + ); + +/***************************************************************************** +Internal API: +WARNING - The items in this section are subject to instability. They only +exist in the public header because sox (the application) currently uses them. +These may be changed or removed in future versions of libSoX. +*****************************************************************************/ + +/** +Plugins API: +Print a fatal error in libSoX. +*/ +void +LSX_API +lsx_fail_impl( + LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */ + ...) + LSX_PRINTF12; + +/** +Plugins API: +Print a warning in libSoX. +*/ +void +LSX_API +lsx_warn_impl( + LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */ + ...) + LSX_PRINTF12; + +/** +Plugins API: +Print an informational message in libSoX. +*/ +void +LSX_API +lsx_report_impl( + LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */ + ...) + LSX_PRINTF12; + +/** +Plugins API: +Print a debug message in libSoX. +*/ +void +LSX_API +lsx_debug_impl( + LSX_PARAM_IN_PRINTF char const * fmt, /**< printf-style format string. */ + ...) + LSX_PRINTF12; + +/** +Plugins API: +Report a fatal error in libSoX; printf-style arguments must follow. +*/ +#define lsx_fail sox_get_globals()->subsystem=__FILE__,lsx_fail_impl + +/** +Plugins API: +Report a warning in libSoX; printf-style arguments must follow. +*/ +#define lsx_warn sox_get_globals()->subsystem=__FILE__,lsx_warn_impl + +/** +Plugins API: +Report an informational message in libSoX; printf-style arguments must follow. +*/ +#define lsx_report sox_get_globals()->subsystem=__FILE__,lsx_report_impl + +/** +Plugins API: +Report a debug message in libSoX; printf-style arguments must follow. +*/ +#define lsx_debug sox_get_globals()->subsystem=__FILE__,lsx_debug_impl + +/** +Plugins API: +String name and integer values for enumerated types (type metadata), for use +with LSX_ENUM_ITEM, lsx_find_enum_text, and lsx_find_enum_value. +*/ +typedef struct lsx_enum_item { + char const *text; /**< String name of enumeration. */ + unsigned value; /**< Integer value of enumeration. */ +} lsx_enum_item; + +/** +Plugins API: +Declares a static instance of an lsx_enum_item structure in format +{ "item", prefixitem }, for use in declaring lsx_enum_item[] arrays. +@param prefix The prefix to prepend to the item in the enumeration symbolic name. +@param item The user-visible text name of the item (must also be a valid C symbol name). +*/ +#define LSX_ENUM_ITEM(prefix, item) {#item, prefix##item}, + +/** +Plugins API: +Flags for use with lsx_find_enum_item. +*/ +enum +{ + lsx_find_enum_item_none = 0, /**< Default parameters (case-insensitive). */ + lsx_find_enum_item_case_sensitive = 1 /**< Enable case-sensitive search. */ +}; + +/** +Plugins API: +Looks up an enumeration by name in an array of lsx_enum_items. +@returns the corresponding item, or null if not found. +*/ +LSX_RETURN_OPT LSX_RETURN_PURE +lsx_enum_item const * +LSX_API +lsx_find_enum_text( + LSX_PARAM_IN_Z char const * text, /**< Name of enumeration to find. */ + LSX_PARAM_IN lsx_enum_item const * lsx_enum_items, /**< Array of items to search, with text == NULL for last item. */ + int flags /**< Search flags: 0 (case-insensitive) or lsx_find_enum_item_case_sensitive (case-sensitive). */ + ); + +/** +Plugins API: +Looks up an enumeration by value in an array of lsx_enum_items. +@returns the corresponding item, or null if not found. +*/ +LSX_RETURN_OPT LSX_RETURN_PURE +lsx_enum_item const * +LSX_API +lsx_find_enum_value( + unsigned value, /**< Enumeration value to find. */ + LSX_PARAM_IN lsx_enum_item const * lsx_enum_items /**< Array of items to search, with text == NULL for last item. */ + ); + +/** +Plugins API: +Looks up a command-line argument in a set of enumeration names, showing an +error message if the argument is not found in the set of names. +@returns The enumeration value corresponding to the matching enumeration, or +INT_MAX if the argument does not match any enumeration name. +*/ +LSX_RETURN_PURE +int +LSX_API +lsx_enum_option( + int c, /**< Option character to which arg is associated, for example with -a, c would be 'a'. */ + LSX_PARAM_IN_Z char const * arg, /**< Argument to find in enumeration list. */ + LSX_PARAM_IN lsx_enum_item const * items /**< Array of items to search, with text == NULL for last item. */ + ); + +/** +Plugins API: +Determines whether the specified string ends with the specified suffix (case-sensitive). +@returns true if the specified string ends with the specified suffix. +*/ +LSX_RETURN_PURE +sox_bool +LSX_API +lsx_strends( + LSX_PARAM_IN_Z char const * str, /**< String to search. */ + LSX_PARAM_IN_Z char const * end /**< Suffix to search for. */ + ); + +/** +Plugins API: +Finds the file extension for a filename. +@returns the file extension, not including the '.', or null if filename does +not have an extension. +*/ +LSX_RETURN_OPT LSX_RETURN_PURE +char const * +LSX_API +lsx_find_file_extension( + LSX_PARAM_IN_Z char const * pathname /**< Filename to search for extension. */ + ); + +/** +Plugins API: +Formats the specified number with up to three significant figures and adds a +metric suffix in place of the exponent, such as 1.23G. +@returns A static buffer with the formatted number, valid until the next time +this function is called (note: not thread safe). +*/ +LSX_RETURN_VALID_Z +char const * +LSX_API +lsx_sigfigs3( + double number /**< Number to be formatted. */ + ); + +/** +Plugins API: +Formats the specified number as a percentage, showing up to three significant +figures. +@returns A static buffer with the formatted number, valid until the next time +this function is called (note: not thread safe). +*/ +LSX_RETURN_VALID_Z +char const * +LSX_API +lsx_sigfigs3p( + double percentage /**< Number to be formatted. */ + ); + +/** +Plugins API: +Allocates, deallocates, or resizes; like C's realloc, except that this version +terminates the running application if unable to allocate the requested memory. +@returns New buffer, or null if buffer was freed. +*/ +LSX_RETURN_OPT +void * +LSX_API +lsx_realloc( + LSX_PARAM_IN_OPT void *ptr, /**< Pointer to be freed or resized, or null if allocating a new buffer. */ + size_t newsize /**< New size for buffer, or 0 to free the buffer. */ + ); + +/** +Plugins API: +Like strcmp, except that the characters are compared without regard to case. +@returns 0 (s1 == s2), negative (s1 < s2), or positive (s1 > s2). +*/ +LSX_RETURN_PURE +int +LSX_API +lsx_strcasecmp( + LSX_PARAM_IN_Z char const * s1, /**< First string. */ + LSX_PARAM_IN_Z char const * s2 /**< Second string. */ + ); + + +/** +Plugins API: +Like strncmp, except that the characters are compared without regard to case. +@returns 0 (s1 == s2), negative (s1 < s2), or positive (s1 > s2). +*/ +LSX_RETURN_PURE +int +LSX_API +lsx_strncasecmp( + LSX_PARAM_IN_Z char const * s1, /**< First string. */ + LSX_PARAM_IN_Z char const * s2, /**< Second string. */ + size_t n /**< Maximum number of characters to examine. */ + ); + +/** +Plugins API: +Is option argument unsupported, required, or optional. +*/ +typedef enum lsx_option_arg_t { + lsx_option_arg_none, /**< Option does not have an argument. */ + lsx_option_arg_required, /**< Option requires an argument. */ + lsx_option_arg_optional /**< Option can optionally be followed by an argument. */ +} lsx_option_arg_t; + +/** +Plugins API: +lsx_getopt_init options. +*/ +typedef enum lsx_getopt_flags_t { + lsx_getopt_flag_none = 0, /**< no flags (no output, not long-only) */ + lsx_getopt_flag_opterr = 1, /**< if set, invalid options trigger lsx_warn output */ + lsx_getopt_flag_longonly = 2 /**< if set, recognize -option as a long option */ +} lsx_getopt_flags_t; + +/** +Plugins API: +lsx_getopt long option descriptor. +*/ +typedef struct lsx_option_t { + char const * name; /**< Name of the long option. */ + lsx_option_arg_t has_arg; /**< Whether the long option supports an argument and, if so, whether the argument is required or optional. */ + int * flag; /**< Flag to set if argument is present. */ + int val; /**< Value to put in flag if argument is present. */ +} lsx_option_t; + +/** +Plugins API: +lsx_getopt session information (initialization data and state). +*/ +typedef struct lsx_getopt_t { + int argc; /**< IN argc: Number of arguments in argv */ + char * const * argv; /**< IN argv: Array of arguments */ + char const * shortopts;/**< IN shortopts: Short option characters */ + lsx_option_t const * longopts; /**< IN longopts: Array of long option descriptors */ + lsx_getopt_flags_t flags; /**< IN flags: Flags for longonly and opterr */ + char const * curpos; /**< INOUT curpos: Maintains state between calls to lsx_getopt */ + int ind; /**< INOUT optind: Maintains the index of next element to be processed */ + int opt; /**< OUT optopt: Receives the option character that caused error */ + char const * arg; /**< OUT optarg: Receives the value of the option's argument */ + int lngind; /**< OUT lngind: Receives the index of the matched long option or -1 if not a long option */ +} lsx_getopt_t; + +/** +Plugins API: +Initializes an lsx_getopt_t structure for use with lsx_getopt. +*/ +void +LSX_API +lsx_getopt_init( + LSX_PARAM_IN int argc, /**< Number of arguments in argv */ + LSX_PARAM_IN_COUNT(argc) char * const * argv, /**< Array of arguments */ + LSX_PARAM_IN_Z char const * shortopts, /**< Short options, for example ":abc:def::ghi" (+/- not supported) */ + LSX_PARAM_IN_OPT lsx_option_t const * longopts, /**< Array of long option descriptors */ + LSX_PARAM_IN lsx_getopt_flags_t flags, /**< Flags for longonly and opterr */ + LSX_PARAM_IN int first, /**< First argv to check (usually 1) */ + LSX_PARAM_OUT lsx_getopt_t * state /**< State object to be initialized */ + ); + +/** +Plugins API: +Gets the next option. Options are parameters that start with "-" or "--". +If no more options, returns -1. If unrecognized short option, returns '?'. +If a recognized short option is missing a required argument, +return (shortopts[0]==':' ? ':' : '?'). If successfully recognized short +option, return the recognized character. If successfully recognized long +option, returns (option.flag ? 0 : option.val). +Note: lsx_getopt does not permute the non-option arguments. +@returns option character (short), val or 0 (long), or -1 (no more). +*/ +int +LSX_API +lsx_getopt( + LSX_PARAM_INOUT lsx_getopt_t * state /**< The getopt state pointer. */ + ); + +/** +Plugins API: +Gets the file length, or 0 if the file is not seekable/normal. +@returns The file length, or 0 if the file is not seekable/normal. +*/ +sox_uint64_t +LSX_API +lsx_filelength( + LSX_PARAM_IN sox_format_t * ft + ); + +/* WARNING END */ + +#if defined(__cplusplus) +} +#endif + +#endif /* SOX_H */ diff --git a/app/src/main/cpp/sox/sox_i.h b/app/src/main/cpp/sox/sox_i.h new file mode 100644 index 0000000..c8552f9 --- /dev/null +++ b/app/src/main/cpp/sox/sox_i.h @@ -0,0 +1,416 @@ +/* libSoX Internal header + * + * This file is meant for libSoX internal use only + * + * Copyright 2001-2012 Chris Bagwell and SoX Contributors + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Chris Bagwell And SoX Contributors are not responsible for + * the consequences of using this software. + */ + +#ifndef SOX_I_H +#define SOX_I_H + +#include "soxomp.h" /* Note: soxomp.h includes soxconfig.h */ +#include "sox.h" + +#if defined HAVE_FMEMOPEN +#define _GNU_SOURCE +#endif + +#include +#include +#include + +#include "util.h" + +#if defined(LSX_EFF_ALIAS) +#undef lsx_debug +#undef lsx_fail +#undef lsx_report +#undef lsx_warn +#define lsx_debug sox_globals.subsystem=effp->handler.name,lsx_debug_impl +#define lsx_fail sox_globals.subsystem=effp->handler.name,lsx_fail_impl +#define lsx_report sox_globals.subsystem=effp->handler.name,lsx_report_impl +#define lsx_warn sox_globals.subsystem=effp->handler.name,lsx_warn_impl +#endif + +#define RANQD1 ranqd1(sox_globals.ranqd1) +#define DRANQD1 dranqd1(sox_globals.ranqd1) + +typedef enum {SOX_SHORT, SOX_INT, SOX_FLOAT, SOX_DOUBLE} sox_data_t; +typedef enum {SOX_WAVE_SINE, SOX_WAVE_TRIANGLE} lsx_wave_t; +lsx_enum_item const * lsx_get_wave_enum(void); + +/* Define fseeko and ftello for platforms lacking them */ +#ifndef HAVE_FSEEKO +#define fseeko fseek +#define ftello ftell +#endif + +#ifdef _FILE_OFFSET_BITS +assert_static(sizeof(off_t) == _FILE_OFFSET_BITS >> 3, OFF_T_BUILD_PROBLEM); +#endif + +FILE * lsx_tmpfile(void); + +void lsx_debug_more_impl(char const * fmt, ...) LSX_PRINTF12; +void lsx_debug_most_impl(char const * fmt, ...) LSX_PRINTF12; + +#define lsx_debug_more sox_get_globals()->subsystem=__FILE__,lsx_debug_more_impl +#define lsx_debug_most sox_get_globals()->subsystem=__FILE__,lsx_debug_most_impl + +/* Digitise one cycle of a wave and store it as + * a table of samples of a specified data-type. + */ +void lsx_generate_wave_table( + lsx_wave_t wave_type, + sox_data_t data_type, + void * table, /* Really of type indicated by data_type. */ + size_t table_size, /* Number of points on the x-axis. */ + double min, /* Minimum value on the y-axis. (e.g. -1) */ + double max, /* Maximum value on the y-axis. (e.g. +1) */ + double phase); /* Phase at 1st point; 0..2pi. (e.g. pi/2 for cosine) */ +char const * lsx_parsesamples(sox_rate_t rate, const char *str, uint64_t *samples, int def); +char const * lsx_parseposition(sox_rate_t rate, const char *str, uint64_t *samples, uint64_t latest, uint64_t end, int def); +int lsx_parse_note(char const * text, char * * end_ptr); +double lsx_parse_frequency_k(char const * text, char * * end_ptr, int key); +#define lsx_parse_frequency(a, b) lsx_parse_frequency_k(a, b, INT_MAX) +FILE * lsx_open_input_file(sox_effect_t * effp, char const * filename, sox_bool text_mode); + +void lsx_prepare_spline3(double const * x, double const * y, int n, + double start_1d, double end_1d, double * y_2d); +double lsx_spline3(double const * x, double const * y, double const * y_2d, + int n, double x1); + +double lsx_bessel_I_0(double x); +int lsx_set_dft_length(int num_taps); +void init_fft_cache(void); +void clear_fft_cache(void); +#define lsx_is_power_of_2(x) !(x < 2 || (x & (x - 1))) +void lsx_safe_rdft(int len, int type, double * d); +void lsx_safe_cdft(int len, int type, double * d); +void lsx_power_spectrum(int n, double const * in, double * out); +void lsx_power_spectrum_f(int n, float const * in, float * out); +void lsx_apply_hann_f(float h[], const int num_points); +void lsx_apply_hann(double h[], const int num_points); +void lsx_apply_hamming(double h[], const int num_points); +void lsx_apply_bartlett(double h[], const int num_points); +void lsx_apply_blackman(double h[], const int num_points, double alpha); +void lsx_apply_blackman_nutall(double h[], const int num_points); +double lsx_kaiser_beta(double att, double tr_bw); +void lsx_apply_kaiser(double h[], const int num_points, double beta); +void lsx_apply_dolph(double h[], const int num_points, double att); +double * lsx_make_lpf(int num_taps, double Fc, double beta, double rho, + double scale, sox_bool dc_norm); +void lsx_kaiser_params(double att, double Fc, double tr_bw, double * beta, int * num_taps); +double * lsx_design_lpf( + double Fp, /* End of pass-band */ + double Fs, /* Start of stop-band */ + double Fn, /* Nyquist freq; e.g. 0.5, 1, PI; < 0: dummy run */ + double att, /* Stop-band attenuation in dB */ + int * num_taps, /* 0: value will be estimated */ + int k, /* >0: number of phases; <0: num_taps ≡ 1 (mod -k) */ + double beta); /* <0: value will be estimated */ +void lsx_fir_to_phase(double * * h, int * len, + int * post_len, double phase0); +void lsx_plot_fir(double * h, int num_points, sox_rate_t rate, sox_plot_t type, char const * title, double y1, double y2); +void lsx_save_samples(sox_sample_t * const dest, double const * const src, + size_t const n, sox_uint64_t * const clips); +void lsx_load_samples(double * const dest, sox_sample_t const * const src, + size_t const n); + +#ifdef HAVE_BYTESWAP_H +#include +#define lsx_swapw(x) bswap_16(x) +#define lsx_swapdw(x) bswap_32(x) +#elif defined(_MSC_VER) +#define lsx_swapw(x) _byteswap_ushort(x) +#define lsx_swapdw(x) _byteswap_ulong(x) +#else +#define lsx_swapw(uw) (((uw >> 8) | (uw << 8)) & 0xffff) +#define lsx_swapdw(udw) ((udw >> 24) | ((udw >> 8) & 0xff00) | ((udw << 8) & 0xff0000) | (udw << 24)) +#endif + + + +/*------------------------ Implemented in libsoxio.c -------------------------*/ + +/* Read and write basic data types from "ft" stream. */ +size_t lsx_readbuf(sox_format_t * ft, void *buf, size_t len); +int lsx_skipbytes(sox_format_t * ft, size_t n); +int lsx_padbytes(sox_format_t * ft, size_t n); +size_t lsx_writebuf(sox_format_t * ft, void const *buf, size_t len); +int lsx_reads(sox_format_t * ft, char *c, size_t len); +int lsx_writes(sox_format_t * ft, char const * c); +void lsx_set_signal_defaults(sox_format_t * ft); +#define lsx_writechars(ft, chars, len) (lsx_writebuf(ft, chars, len) == len? SOX_SUCCESS : SOX_EOF) + +size_t lsx_read_3_buf(sox_format_t * ft, sox_uint24_t *buf, size_t len); +size_t lsx_read_b_buf(sox_format_t * ft, uint8_t *buf, size_t len); +size_t lsx_read_df_buf(sox_format_t * ft, double *buf, size_t len); +size_t lsx_read_dw_buf(sox_format_t * ft, uint32_t *buf, size_t len); +size_t lsx_read_qw_buf(sox_format_t * ft, uint64_t *buf, size_t len); +size_t lsx_read_f_buf(sox_format_t * ft, float *buf, size_t len); +size_t lsx_read_w_buf(sox_format_t * ft, uint16_t *buf, size_t len); + +size_t lsx_write_3_buf(sox_format_t * ft, sox_uint24_t *buf, size_t len); +size_t lsx_write_b_buf(sox_format_t * ft, uint8_t *buf, size_t len); +size_t lsx_write_df_buf(sox_format_t * ft, double *buf, size_t len); +size_t lsx_write_dw_buf(sox_format_t * ft, uint32_t *buf, size_t len); +size_t lsx_write_qw_buf(sox_format_t * ft, uint64_t *buf, size_t len); +size_t lsx_write_f_buf(sox_format_t * ft, float *buf, size_t len); +size_t lsx_write_w_buf(sox_format_t * ft, uint16_t *buf, size_t len); + +int lsx_read3(sox_format_t * ft, sox_uint24_t * u3); +int lsx_readb(sox_format_t * ft, uint8_t * ub); +int lsx_readchars(sox_format_t * ft, char * chars, size_t len); +int lsx_readdf(sox_format_t * ft, double * d); +int lsx_readdw(sox_format_t * ft, uint32_t * udw); +int lsx_readqw(sox_format_t * ft, uint64_t * udw); +int lsx_readf(sox_format_t * ft, float * f); +int lsx_readw(sox_format_t * ft, uint16_t * uw); + +#if 1 /* FIXME: use defines */ +UNUSED static int lsx_readsb(sox_format_t * ft, int8_t * sb) +{return lsx_readb(ft, (uint8_t *)sb);} +UNUSED static int lsx_readsw(sox_format_t * ft, int16_t * sw) +{return lsx_readw(ft, (uint16_t *)sw);} +#else +#define lsx_readsb(ft, sb) lsx_readb(ft, (uint8_t *)sb) +#define lsx_readsw(ft, sw) lsx_readb(ft, (uint16_t *)sw) +#endif + +int lsx_read_fields(sox_format_t *ft, uint32_t *len, const char *spec, ...); + +int lsx_write3(sox_format_t * ft, unsigned u3); +int lsx_writeb(sox_format_t * ft, unsigned ub); +int lsx_writedf(sox_format_t * ft, double d); +int lsx_writedw(sox_format_t * ft, unsigned udw); +int lsx_writeqw(sox_format_t * ft, uint64_t uqw); +int lsx_writef(sox_format_t * ft, double f); +int lsx_writew(sox_format_t * ft, unsigned uw); + +int lsx_writesb(sox_format_t * ft, signed); +int lsx_writesw(sox_format_t * ft, signed); + +int lsx_eof(sox_format_t * ft); +int lsx_error(sox_format_t * ft); +int lsx_flush(sox_format_t * ft); +int lsx_seeki(sox_format_t * ft, off_t offset, int whence); +int lsx_unreadb(sox_format_t * ft, unsigned ub); +/* uint64_t lsx_filelength(sox_format_t * ft); Temporarily Moved to sox.h. */ +off_t lsx_tell(sox_format_t * ft); +void lsx_clearerr(sox_format_t * ft); +void lsx_rewind(sox_format_t * ft); + +int lsx_offset_seek(sox_format_t * ft, off_t byte_offset, off_t to_sample); + +void lsx_fail_errno(sox_format_t *, int, const char *, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 3, 4))); +#else +; +#endif + +typedef struct sox_formats_globals { /* Global parameters (for formats) */ + sox_globals_t * global_info; +} sox_formats_globals; + + + +/*------------------------------ File Handlers -------------------------------*/ + +int lsx_check_read_params(sox_format_t * ft, unsigned channels, + sox_rate_t rate, sox_encoding_t encoding, unsigned bits_per_sample, + uint64_t num_samples, sox_bool check_length); +#define LSX_FORMAT_HANDLER(name) \ +sox_format_handler_t const * lsx_##name##_format_fn(void); \ +sox_format_handler_t const * lsx_##name##_format_fn(void) +#define div_bits(size, bits) ((uint64_t)(size) * 8 / bits) + +/* Raw I/O */ +int lsx_rawstartread(sox_format_t * ft); +size_t lsx_rawread(sox_format_t * ft, sox_sample_t *buf, size_t nsamp); +int lsx_rawstopread(sox_format_t * ft); +int lsx_rawstartwrite(sox_format_t * ft); +size_t lsx_rawwrite(sox_format_t * ft, const sox_sample_t *buf, size_t nsamp); +int lsx_rawseek(sox_format_t * ft, uint64_t offset); +int lsx_rawstart(sox_format_t * ft, sox_bool default_rate, sox_bool default_channels, sox_bool default_length, sox_encoding_t encoding, unsigned bits_per_sample); +#define lsx_rawstartread(ft) lsx_rawstart(ft, sox_false, sox_false, sox_false, SOX_ENCODING_UNKNOWN, 0) +#define lsx_rawstartwrite lsx_rawstartread +#define lsx_rawstopread NULL +#define lsx_rawstopwrite NULL + +extern sox_format_handler_t const * lsx_sndfile_format_fn(void); + +char * lsx_cat_comments(sox_comments_t comments); + +/*--------------------------------- Effects ----------------------------------*/ + +int lsx_flow_copy(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp); +int lsx_usage(sox_effect_t * effp); +char * lsx_usage_lines(char * * usage, char const * const * lines, size_t n); +#define EFFECT(f) extern sox_effect_handler_t const * lsx_##f##_effect_fn(void); +#include "effects.h" +#undef EFFECT + +#define NUMERIC_PARAMETER(name, min, max) { \ + char * end_ptr; \ + double d; \ + if (argc == 0) break; \ + d = strtod(*argv, &end_ptr); \ + if (end_ptr != *argv) { \ + if (d < min || d > max || *end_ptr != '\0') {\ + lsx_fail("parameter `%s' must be between %g and %g", #name, (double)min, (double)max); \ + return lsx_usage(effp); \ + } \ + p->name = d; \ + --argc, ++argv; \ + } \ +} + +#define TEXTUAL_PARAMETER(name, enum_table) { \ + lsx_enum_item const * e; \ + if (argc == 0) break; \ + e = lsx_find_enum_text(*argv, enum_table, 0); \ + if (e != NULL) { \ + p->name = e->value; \ + --argc, ++argv; \ + } \ +} + +#define GETOPT_LOCAL_NUMERIC(state, ch, name, min, max) case ch:{ \ + char * end_ptr; \ + double d = strtod(state.arg, &end_ptr); \ + if (end_ptr == state.arg || d < min || d > max || *end_ptr != '\0') {\ + lsx_fail("parameter `%s' must be between %g and %g", #name, (double)min, (double)max); \ + return lsx_usage(effp); \ + } \ + name = d; \ + break; \ +} +#define GETOPT_NUMERIC(state, ch, name, min, max) GETOPT_LOCAL_NUMERIC(state, ch, p->name, min, max) + +int lsx_effect_set_imin(sox_effect_t * effp, size_t imin); + +int lsx_effects_init(void); +int lsx_effects_quit(void); + +/*--------------------------------- Dynamic Library ----------------------------------*/ + +#if defined(HAVE_LIBLTDL) + #include + typedef lt_dlhandle lsx_dlhandle; +#else + struct lsx_dlhandle_tag; + typedef struct lsx_dlhandle_tag *lsx_dlhandle; +#endif + +typedef void (*lsx_dlptr)(void); + +typedef struct lsx_dlfunction_info +{ + const char* name; + lsx_dlptr static_func; + lsx_dlptr stub_func; +} lsx_dlfunction_info; + +int lsx_open_dllibrary( + int show_error_on_failure, + const char* library_description, + const char * const library_names[], + const lsx_dlfunction_info func_infos[], + lsx_dlptr selected_funcs[], + lsx_dlhandle* pdl); + +void lsx_close_dllibrary( + lsx_dlhandle dl); + +#define LSX_DLENTRIES_APPLY__(entries, f, x) entries(f, x) + +#define LSX_DLENTRY_TO_PTR__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ + func_return (*func_ptr) func_args; + +#define LSX_DLENTRIES_TO_FUNCTIONS__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ + func_return func_name func_args; + +/* LSX_DLENTRIES_TO_PTRS: Given an ENTRIES macro and the name of the dlhandle + variable, declares the corresponding function pointer variables and the + dlhandle variable. */ +#define LSX_DLENTRIES_TO_PTRS(entries, dlhandle) \ + LSX_DLENTRIES_APPLY__(entries, LSX_DLENTRY_TO_PTR__, 0) \ + lsx_dlhandle dlhandle + +/* LSX_DLENTRIES_TO_FUNCTIONS: Given an ENTRIES macro, declares the corresponding + functions. */ +#define LSX_DLENTRIES_TO_FUNCTIONS(entries) \ + LSX_DLENTRIES_APPLY__(entries, LSX_DLENTRIES_TO_FUNCTIONS__, 0) + +#define LSX_DLLIBRARY_OPEN1__(unused, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ + { #func_name, (lsx_dlptr)(static_func), (lsx_dlptr)(stub_func) }, + +#define LSX_DLLIBRARY_OPEN2__(ptr_container, func_return, func_name, func_args, static_func, stub_func, func_ptr) \ + (ptr_container)->func_ptr = (func_return (*)func_args)lsx_dlfunction_open_library_funcs[lsx_dlfunction_open_library_index++]; + +/* LSX_DLLIBRARY_OPEN: Input an ENTRIES macro, the library's description, + a null-terminated list of library names (i.e. { "libmp3-0", "libmp3", NULL }), + the name of the dlhandle variable, the name of the structure that contains + the function pointer and dlhandle variables, and the name of the variable in + which the result of the lsx_open_dllibrary call should be stored. This will + call lsx_open_dllibrary and copy the resulting function pointers into the + structure members. If the library cannot be opened, show a failure message. */ +#define LSX_DLLIBRARY_OPEN(ptr_container, dlhandle, entries, library_description, library_names, return_var) \ + LSX_DLLIBRARY_TRYOPEN(1, ptr_container, dlhandle, entries, library_description, library_names, return_var) + +/* LSX_DLLIBRARY_TRYOPEN: Input an ENTRIES macro, the library's description, + a null-terminated list of library names (i.e. { "libmp3-0", "libmp3", NULL }), + the name of the dlhandle variable, the name of the structure that contains + the function pointer and dlhandle variables, and the name of the variable in + which the result of the lsx_open_dllibrary call should be stored. This will + call lsx_open_dllibrary and copy the resulting function pointers into the + structure members. If the library cannot be opened, show a report or a failure + message, depending on whether error_on_failure is non-zero. */ +#define LSX_DLLIBRARY_TRYOPEN(error_on_failure, ptr_container, dlhandle, entries, library_description, library_names, return_var) \ + do { \ + lsx_dlfunction_info lsx_dlfunction_open_library_infos[] = { \ + LSX_DLENTRIES_APPLY__(entries, LSX_DLLIBRARY_OPEN1__, 0) \ + {NULL,NULL,NULL} }; \ + int lsx_dlfunction_open_library_index = 0; \ + lsx_dlptr lsx_dlfunction_open_library_funcs[sizeof(lsx_dlfunction_open_library_infos)/sizeof(lsx_dlfunction_open_library_infos[0])]; \ + (return_var) = lsx_open_dllibrary((error_on_failure), (library_description), (library_names), lsx_dlfunction_open_library_infos, lsx_dlfunction_open_library_funcs, &(ptr_container)->dlhandle); \ + LSX_DLENTRIES_APPLY__(entries, LSX_DLLIBRARY_OPEN2__, ptr_container) \ + } while(0) + +#define LSX_DLLIBRARY_CLOSE(ptr_container, dlhandle) \ + lsx_close_dllibrary((ptr_container)->dlhandle) + + /* LSX_DLENTRY_STATIC: For use in creating an ENTRIES macro. func is + expected to be available at link time. If not present, link will fail. */ +#define LSX_DLENTRY_STATIC(f,x, ret, func, args) f(x, ret, func, args, func, NULL, func) + + /* LSX_DLENTRY_DYNAMIC: For use in creating an ENTRIES macro. func need + not be available at link time (and if present, the link time version will + not be used). func will be loaded via dlsym. If this function is not + found in the shared library, the shared library will not be used. */ +#define LSX_DLENTRY_DYNAMIC(f,x, ret, func, args) f(x, ret, func, args, NULL, NULL, func) + + /* LSX_DLENTRY_STUB: For use in creating an ENTRIES macro. func need not + be available at link time (and if present, the link time version will not + be used). If using DL_LAME, the func may be loaded via dlopen/dlsym, but + if not found, the shared library will still be used if all of the + non-stub functions are found. If the function is not found via dlsym (or + if we are not loading any shared libraries), the stub will be used. This + assumes that the name of the stub function is the name of the function + + "_stub". */ +#define LSX_DLENTRY_STUB(f,x, ret, func, args) f(x, ret, func, args, NULL, func##_stub, func) + + /* LSX_DLFUNC_IS_STUB: returns true if the named function is a do-nothing + stub. Assumes that the name of the stub function is the name of the + function + "_stub". */ +#define LSX_DLFUNC_IS_STUB(ptr_container, func) ((ptr_container)->func == func##_stub) + +#endif diff --git a/app/src/main/cpp/sox/sox_sample_test.c b/app/src/main/cpp/sox/sox_sample_test.c new file mode 100644 index 0000000..0216ae8 --- /dev/null +++ b/app/src/main/cpp/sox/sox_sample_test.c @@ -0,0 +1,190 @@ +/* libSoX test code copyright (c) 2006 robs@users.sourceforge.net + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef NDEBUG /* Enable assert always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif +#include +#include +#include "sox.h" + +#define TEST_UINT(bits) \ + uint##bits = 0; \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,uint##bits); \ + assert(sample == SOX_SAMPLE_MIN); \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == 0 && clips == 0); \ + \ + uint##bits = 1; \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,uint##bits); \ + assert(sample > SOX_SAMPLE_MIN && sample < 0); \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == 1 && clips == 0); \ + \ + uint##bits = SOX_INT_MAX(bits); \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,uint##bits); \ + assert(sample * SOX_INT_MAX(bits) == SOX_UNSIGNED_TO_SAMPLE(bits,1)); \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == SOX_INT_MAX(bits) && clips == 0); \ + \ + sample =SOX_UNSIGNED_TO_SAMPLE(bits,1)+SOX_UNSIGNED_TO_SAMPLE(bits,SOX_INT_MAX(bits))/2; \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == 1 && clips == 0); \ + \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,1)+SOX_UNSIGNED_TO_SAMPLE(bits,SOX_INT_MAX(bits))/2-1; \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == 0 && clips == 0); \ + \ + uint##bits = (0^SOX_INT_MIN(bits)); \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,uint##bits); \ + assert(sample == 0); \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == (0^SOX_INT_MIN(bits)) && clips == 0); \ + \ + uint##bits = ((0^SOX_INT_MIN(bits))+1); \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,uint##bits); \ + assert(sample > 0 && sample < SOX_SAMPLE_MAX); \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == ((0^SOX_INT_MIN(bits))+1) && clips == 0); \ + \ + uint##bits = SOX_UINT_MAX(bits); \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,uint##bits); \ + assert(sample == SOX_INT_MAX(bits) * SOX_UNSIGNED_TO_SAMPLE(bits,((0^SOX_INT_MIN(bits))+1))); \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == SOX_UINT_MAX(bits) && clips == 0); \ + \ + sample =SOX_UNSIGNED_TO_SAMPLE(bits,SOX_UINT_MAX(bits))+SOX_UNSIGNED_TO_SAMPLE(bits,((0^SOX_INT_MIN(bits))+1))/2-1; \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == SOX_UINT_MAX(bits) && clips == 0); \ + \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,SOX_UINT_MAX(bits))+SOX_UNSIGNED_TO_SAMPLE(bits,((0^SOX_INT_MIN(bits))+1))/2; \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == SOX_UINT_MAX(bits) && --clips == 0); \ + \ + sample = SOX_SAMPLE_MAX; \ + uint##bits = SOX_SAMPLE_TO_UNSIGNED(bits,sample, clips); \ + assert(uint##bits == SOX_UINT_MAX(bits) && --clips == 0); \ + +#define TEST_SINT(bits) \ + int##bits = SOX_INT_MIN(bits); \ + sample = SOX_SIGNED_TO_SAMPLE(bits,int##bits); \ + assert(sample == SOX_SAMPLE_MIN); \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + int##bits = SOX_INT_MIN(bits)+1; \ + sample = SOX_SIGNED_TO_SAMPLE(bits,int##bits); \ + assert(sample > SOX_SAMPLE_MIN && sample < 0); \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + int##bits = SOX_UINT_MAX(bits) /* i.e. -1 */; \ + sample = SOX_SIGNED_TO_SAMPLE(bits,int##bits); \ + assert(sample * SOX_INT_MAX(bits) == SOX_SIGNED_TO_SAMPLE(bits,SOX_INT_MIN(bits)+1)); \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + int##bits = SOX_INT_MIN(bits)+1; \ + sample =SOX_UNSIGNED_TO_SAMPLE(bits,1)+SOX_UNSIGNED_TO_SAMPLE(bits,SOX_INT_MAX(bits))/2; \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + int##bits = SOX_INT_MIN(bits); \ + sample = SOX_UNSIGNED_TO_SAMPLE(bits,1)+SOX_UNSIGNED_TO_SAMPLE(bits,SOX_INT_MAX(bits))/2-1; \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + int##bits = 0; \ + sample = SOX_SIGNED_TO_SAMPLE(bits,int##bits); \ + assert(sample == 0); \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + int##bits = 1; \ + sample = SOX_SIGNED_TO_SAMPLE(bits,int##bits); \ + assert(sample > 0 && sample < SOX_SAMPLE_MAX); \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + int##bits = SOX_INT_MAX(bits); \ + sample = SOX_SIGNED_TO_SAMPLE(bits,int##bits); \ + assert(sample == SOX_INT_MAX(bits) * SOX_SIGNED_TO_SAMPLE(bits,1)); \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + sample =SOX_UNSIGNED_TO_SAMPLE(bits,SOX_UINT_MAX(bits))+SOX_UNSIGNED_TO_SAMPLE(bits,((0^SOX_INT_MIN(bits))+1))/2-1; \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && clips == 0); \ + \ + sample =SOX_UNSIGNED_TO_SAMPLE(bits,SOX_UINT_MAX(bits))+SOX_UNSIGNED_TO_SAMPLE(bits,((0^SOX_INT_MIN(bits))+1))/2; \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && --clips == 0); \ + \ + sample = SOX_SAMPLE_MAX; \ + int##bits##_2 = SOX_SAMPLE_TO_SIGNED(bits,sample, clips); \ + assert(int##bits##_2 == int##bits && --clips == 0); + +int main(void) +{ + sox_int8_t int8; + sox_int16_t int16; + sox_int24_t int24; + + sox_uint8_t uint8; + sox_uint16_t uint16; + sox_uint24_t uint24; + + sox_int8_t int8_2; + sox_int16_t int16_2; + sox_int24_t int24_2; + + sox_sample_t sample; + size_t clips = 0; + + double d; + SOX_SAMPLE_LOCALS; + + TEST_UINT(8) + TEST_UINT(16) + TEST_UINT(24) + + TEST_SINT(8) + TEST_SINT(16) + TEST_SINT(24) + + d = -1.000000001; + sample = SOX_FLOAT_64BIT_TO_SAMPLE(d, clips); + assert(sample == SOX_SAMPLE_MIN && --clips == 0); + + d = -1; + sample = SOX_FLOAT_64BIT_TO_SAMPLE(d, clips); + assert(sample == SOX_SAMPLE_MIN && clips == 0); + d = SOX_SAMPLE_TO_FLOAT_64BIT(sample,clips); + assert(d == -1 && clips == 0); + + d = 1; + sample = SOX_FLOAT_64BIT_TO_SAMPLE(d, clips); + assert(sample == SOX_SAMPLE_MAX && clips == 0); + d = SOX_SAMPLE_TO_FLOAT_64BIT(sample,clips); + assert(fabs(d - 1) < 1e-9 && clips == 0); + + d = 1.0000000001; + sample = SOX_FLOAT_64BIT_TO_SAMPLE(d, clips); + assert(sample == SOX_SAMPLE_MAX && --clips == 0); + + return 0; +} diff --git a/app/src/main/cpp/sox/soxomp.h b/app/src/main/cpp/sox/soxomp.h new file mode 100644 index 0000000..bca23c7 --- /dev/null +++ b/app/src/main/cpp/sox/soxomp.h @@ -0,0 +1,47 @@ +#include "soxconfig.h" + +#ifdef _OPENMP + #if _OPENMP >= 200805 /* OpenMP 3.0 */ + #define HAVE_OPENMP 1 + #endif + #if _OPENMP >= 201107 /* OpenMP 3.1 */ + #define HAVE_OPENMP_3_1 1 + #endif +#endif + +#ifdef HAVE_OPENMP + #include +#else + +typedef int omp_lock_t; +typedef int omp_nest_lock_t; + +#define omp_set_num_threads(int) (void)0 +#define omp_get_num_threads() 1 +#define omp_get_max_threads() 1 +#define omp_get_thread_num() 0 +#define omp_get_num_procs() 1 +#define omp_in_parallel() 1 + +#define omp_set_dynamic(int) (void)0 +#define omp_get_dynamic() 0 + +#define omp_set_nested(int) (void)0 +#define omp_get_nested() 0 + +#define omp_init_lock(omp_lock_t) (void)0 +#define omp_destroy_lock(omp_lock_t) (void)0 +#define omp_set_lock(omp_lock_t) (void)0 +#define omp_unset_lock(omp_lock_t) (void)0 +#define omp_test_lock(omp_lock_t) 0 + +#define omp_init_nest_lock(omp_nest_lock_t) (void)0 +#define omp_destroy_nest_lock(omp_nest_lock_t) (void)0 +#define omp_set_nest_lock(omp_nest_lock_t) (void)0 +#define omp_unset_nest_lock(omp_nest_lock_t) (void)0 +#define omp_test_nest_lock(omp_nest_lock_t) 0 + +#define omp_get_wtime() 0 +#define omp_get_wtick() 0 + +#endif diff --git a/app/src/main/cpp/sox/spectrogram.c b/app/src/main/cpp/sox/spectrogram.c new file mode 100644 index 0000000..3dcda69 --- /dev/null +++ b/app/src/main/cpp/sox/spectrogram.c @@ -0,0 +1,1009 @@ +/* libSoX effect: Spectrogram (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef NDEBUG /* Enable assert always. */ +#undef NDEBUG /* Must undef above assert.h or other that might include it. */ +#endif + +#include "sox_i.h" +#include "fft4g.h" +#include +#include +#ifdef HAVE_LIBPNG_PNG_H +#include +#else +#include +#endif +#include + +/* For SET_BINARY_MODE: */ +#include +#ifdef HAVE_IO_H + #include +#endif + +#define is_p2(x) !(x & (x - 1)) + +#define MAX_X_SIZE 200000 + +#if SSIZE_MAX < UINT32_MAX +#define MAX_Y_SIZE 16384 /* avoid multiplication overflow on 32-bit systems */ +#else +#define MAX_Y_SIZE 200000 +#endif + +typedef enum { + Window_Hann, + Window_Hamming, + Window_Bartlett, + Window_Rectangular, + Window_Kaiser, + Window_Dolph +} win_type_t; + +static const lsx_enum_item window_options[] = { + LSX_ENUM_ITEM(Window_,Hann) + LSX_ENUM_ITEM(Window_,Hamming) + LSX_ENUM_ITEM(Window_,Bartlett) + LSX_ENUM_ITEM(Window_,Rectangular) + LSX_ENUM_ITEM(Window_,Kaiser) + LSX_ENUM_ITEM(Window_,Dolph) + {0, 0} +}; + +typedef struct { + /* Parameters */ + double pixels_per_sec; + double window_adjust; + int x_size0; + int y_size; + int Y_size; + int dB_range; + int gain; + int spectrum_points; + int perm; + sox_bool monochrome; + sox_bool light_background; + sox_bool high_colour; + sox_bool slack_overlap; + sox_bool no_axes; + sox_bool normalize; + sox_bool raw; + sox_bool alt_palette; + sox_bool truncate; + win_type_t win_type; + const char *out_name; + const char *title; + const char *comment; + const char *duration_str; + const char *start_time_str; + sox_bool using_stdout; /* output image to stdout */ + + /* Shared work area */ + double *shared; + double **shared_ptr; + + /* Per-channel work area */ + int WORK; /* Start of work area is marked by this dummy variable. */ + uint64_t skip; + int dft_size; + int step_size; + int block_steps; + int block_num; + int rows; + int cols; + int read; + int x_size; + int end; + int end_min; + int last_end; + sox_bool truncated; + double *buf; /* [dft_size] */ + double *dft_buf; /* [dft_size] */ + double *window; /* [dft_size + 1] */ + double block_norm; + double max; + double *magnitudes; /* [dft_size / 2 + 1] */ + float *dBfs; +} priv_t; + +#define secs(cols) \ + ((double)(cols) * p->step_size * p->block_steps / effp->in_signal.rate) + +static const unsigned char alt_palette[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x05, + 0x00, 0x01, 0x08, 0x00, 0x01, 0x0a, 0x00, 0x01, 0x0b, + 0x00, 0x01, 0x0e, 0x01, 0x02, 0x10, 0x01, 0x02, 0x12, + 0x01, 0x02, 0x15, 0x01, 0x02, 0x16, 0x01, 0x02, 0x18, + 0x01, 0x03, 0x1b, 0x01, 0x03, 0x1d, 0x01, 0x03, 0x1f, + 0x01, 0x03, 0x20, 0x01, 0x03, 0x22, 0x01, 0x03, 0x24, + 0x01, 0x03, 0x25, 0x01, 0x03, 0x27, 0x01, 0x03, 0x28, + 0x01, 0x03, 0x2a, 0x01, 0x03, 0x2c, 0x01, 0x03, 0x2e, + 0x01, 0x03, 0x2f, 0x01, 0x03, 0x30, 0x01, 0x03, 0x32, + 0x01, 0x03, 0x34, 0x02, 0x03, 0x36, 0x04, 0x03, 0x38, + 0x05, 0x03, 0x39, 0x07, 0x03, 0x3b, 0x09, 0x03, 0x3d, + 0x0b, 0x03, 0x3f, 0x0e, 0x03, 0x41, 0x0f, 0x02, 0x42, + 0x11, 0x02, 0x44, 0x13, 0x02, 0x46, 0x15, 0x02, 0x48, + 0x17, 0x02, 0x4a, 0x18, 0x02, 0x4b, 0x1a, 0x02, 0x4d, + 0x1d, 0x02, 0x4f, 0x20, 0x02, 0x51, 0x24, 0x02, 0x53, + 0x28, 0x02, 0x55, 0x2b, 0x02, 0x57, 0x30, 0x02, 0x5a, + 0x33, 0x02, 0x5c, 0x37, 0x02, 0x5f, 0x3b, 0x02, 0x61, + 0x3e, 0x02, 0x63, 0x42, 0x02, 0x65, 0x45, 0x02, 0x68, + 0x49, 0x02, 0x6a, 0x4d, 0x02, 0x6c, 0x51, 0x02, 0x6e, + 0x55, 0x02, 0x70, 0x5a, 0x02, 0x72, 0x5f, 0x02, 0x74, + 0x63, 0x02, 0x75, 0x68, 0x02, 0x76, 0x6c, 0x02, 0x78, + 0x70, 0x03, 0x7a, 0x75, 0x03, 0x7c, 0x7a, 0x03, 0x7d, + 0x7e, 0x03, 0x7e, 0x83, 0x03, 0x80, 0x87, 0x03, 0x82, + 0x8c, 0x03, 0x84, 0x90, 0x03, 0x85, 0x93, 0x03, 0x83, + 0x96, 0x03, 0x80, 0x98, 0x03, 0x7e, 0x9b, 0x03, 0x7c, + 0x9e, 0x03, 0x7a, 0xa0, 0x03, 0x78, 0xa3, 0x03, 0x75, + 0xa6, 0x03, 0x73, 0xa9, 0x03, 0x71, 0xab, 0x03, 0x6f, + 0xae, 0x03, 0x6d, 0xb1, 0x03, 0x6a, 0xb3, 0x03, 0x68, + 0xb6, 0x03, 0x66, 0xba, 0x03, 0x62, 0xbc, 0x03, 0x5e, + 0xc0, 0x03, 0x5a, 0xc3, 0x03, 0x56, 0xc7, 0x03, 0x52, + 0xca, 0x03, 0x4e, 0xcd, 0x03, 0x4a, 0xd1, 0x03, 0x46, + 0xd4, 0x03, 0x43, 0xd7, 0x03, 0x3e, 0xdb, 0x03, 0x3a, + 0xde, 0x03, 0x36, 0xe2, 0x03, 0x32, 0xe4, 0x03, 0x2f, + 0xe6, 0x07, 0x2d, 0xe8, 0x0d, 0x2c, 0xea, 0x11, 0x2b, + 0xec, 0x17, 0x2a, 0xed, 0x1b, 0x29, 0xee, 0x20, 0x28, + 0xf0, 0x26, 0x27, 0xf2, 0x2a, 0x26, 0xf4, 0x2f, 0x24, + 0xf5, 0x34, 0x23, 0xf6, 0x39, 0x23, 0xf8, 0x3e, 0x21, + 0xfa, 0x43, 0x20, 0xfc, 0x49, 0x20, 0xfc, 0x4f, 0x22, + 0xfc, 0x56, 0x26, 0xfc, 0x5d, 0x2a, 0xfc, 0x64, 0x2c, + 0xfc, 0x6b, 0x30, 0xfc, 0x72, 0x33, 0xfc, 0x7a, 0x37, + 0xfd, 0x81, 0x3b, 0xfd, 0x88, 0x3e, 0xfd, 0x8f, 0x42, + 0xfd, 0x96, 0x45, 0xfd, 0x9e, 0x49, 0xfd, 0xa5, 0x4d, + 0xfd, 0xac, 0x50, 0xfd, 0xb1, 0x54, 0xfd, 0xb7, 0x58, + 0xfd, 0xbc, 0x5c, 0xfd, 0xc1, 0x61, 0xfd, 0xc6, 0x65, + 0xfd, 0xcb, 0x69, 0xfd, 0xd0, 0x6d, 0xfe, 0xd5, 0x71, + 0xfe, 0xda, 0x76, 0xfe, 0xdf, 0x7a, 0xfe, 0xe4, 0x7e, + 0xfe, 0xe9, 0x82, 0xfe, 0xee, 0x86, 0xfe, 0xf3, 0x8b, + 0xfd, 0xf5, 0x8f, 0xfc, 0xf6, 0x93, 0xfb, 0xf7, 0x98, + 0xfa, 0xf7, 0x9c, 0xf9, 0xf8, 0xa1, 0xf8, 0xf9, 0xa5, + 0xf7, 0xf9, 0xaa, 0xf6, 0xfa, 0xae, 0xf5, 0xfa, 0xb3, + 0xf4, 0xfb, 0xb7, 0xf3, 0xfc, 0xbc, 0xf1, 0xfd, 0xc0, + 0xf0, 0xfd, 0xc5, 0xf0, 0xfe, 0xc9, 0xef, 0xfe, 0xcc, + 0xef, 0xfe, 0xcf, 0xf0, 0xfe, 0xd1, 0xf0, 0xfe, 0xd4, + 0xf0, 0xfe, 0xd6, 0xf0, 0xfe, 0xd8, 0xf0, 0xfe, 0xda, + 0xf1, 0xff, 0xdd, 0xf1, 0xff, 0xdf, 0xf1, 0xff, 0xe1, + 0xf1, 0xff, 0xe4, 0xf1, 0xff, 0xe6, 0xf2, 0xff, 0xe8, +}; +#define alt_palette_len (array_length(alt_palette) / 3) + +static int getopts(sox_effect_t *effp, int argc, char **argv) +{ + priv_t *p = effp->priv; + uint64_t dummy; + const char *next; + int c; + lsx_getopt_t optstate; + + lsx_getopt_init(argc, argv, "+S:d:x:X:y:Y:z:Z:q:p:W:w:st:c:AarmnlhTo:", + NULL, lsx_getopt_flag_none, 1, &optstate); + + p->dB_range = 120; + p->spectrum_points = 249; + p->perm = 1; + p->out_name = "spectrogram.png"; + p->comment = "Created by SoX"; + + while ((c = lsx_getopt(&optstate)) != -1) { + switch (c) { + GETOPT_NUMERIC(optstate, 'x', x_size0, 100, MAX_X_SIZE) + GETOPT_NUMERIC(optstate, 'X', pixels_per_sec, 1, 5000) + GETOPT_NUMERIC(optstate, 'y', y_size, 64, MAX_Y_SIZE) + GETOPT_NUMERIC(optstate, 'Y', Y_size, 130, MAX_Y_SIZE) + GETOPT_NUMERIC(optstate, 'z', dB_range, 20, 180) + GETOPT_NUMERIC(optstate, 'Z', gain, -100, 100) + GETOPT_NUMERIC(optstate, 'q', spectrum_points, 0, p->spectrum_points) + GETOPT_NUMERIC(optstate, 'p', perm, 1, 6) + GETOPT_NUMERIC(optstate, 'W', window_adjust, -10, 10) + case 'w': p->win_type = lsx_enum_option(c, optstate.arg, window_options); + break; + case 's': p->slack_overlap = sox_true; break; + case 'A': p->alt_palette = sox_true; break; + case 'a': p->no_axes = sox_true; break; + case 'r': p->raw = sox_true; break; + case 'm': p->monochrome = sox_true; break; + case 'n': p->normalize = sox_true; break; + case 'l': p->light_background = sox_true; break; + case 'h': p->high_colour = sox_true; break; + case 'T': p->truncate = sox_true; break; + case 't': p->title = optstate.arg; break; + case 'c': p->comment = optstate.arg; break; + case 'o': p->out_name = optstate.arg; break; + case 'S': + next = lsx_parseposition(0, optstate.arg, NULL, 0, 0, '='); + if (next && !*next) { + p->start_time_str = lsx_strdup(optstate.arg); + break; + } + return lsx_usage(effp); + case 'd': + next = lsx_parsesamples(1e5, optstate.arg, &dummy, 't'); + if (next && !*next) { + p->duration_str = lsx_strdup(optstate.arg); + break; + } + return lsx_usage(effp); + default: + lsx_fail("invalid option `-%c'", optstate.opt); + return lsx_usage(effp); + } + } + + if (!!p->x_size0 + !!p->pixels_per_sec + !!p->duration_str > 2) { + lsx_fail("only two of -x, -X, -d may be given"); + return SOX_EOF; + } + + if (p->y_size && p->Y_size) { + lsx_fail("only one of -y, -Y may be given"); + return SOX_EOF; + } + + p->gain = -p->gain; + --p->perm; + p->spectrum_points += 2; + if (p->alt_palette) + p->spectrum_points = min(p->spectrum_points, alt_palette_len); + p->shared_ptr = &p->shared; + + if (!strcmp(p->out_name, "-")) { + if (effp->global_info->global_info->stdout_in_use_by) { + lsx_fail("stdout already in use by `%s'", + effp->global_info->global_info->stdout_in_use_by); + return SOX_EOF; + } + effp->global_info->global_info->stdout_in_use_by = effp->handler.name; + p->using_stdout = sox_true; + } + + return optstate.ind != argc || p->win_type == INT_MAX ? + lsx_usage(effp) : SOX_SUCCESS; +} + +static double make_window(priv_t *p, int end) +{ + double sum = 0; + double *w = end < 0 ? p->window : p->window + end; + double beta; + int n = 1 + p->dft_size - abs(end); + int i; + + if (end) + memset(p->window, 0, sizeof(*p->window) * (p->dft_size + 1)); + + for (i = 0; i < n; ++i) + w[i] = 1; + + switch (p->win_type) { + case Window_Hann: lsx_apply_hann(w, n); break; + case Window_Hamming: lsx_apply_hamming(w, n); break; + case Window_Bartlett: lsx_apply_bartlett(w, n); break; + case Window_Rectangular: break; + case Window_Kaiser: + beta = lsx_kaiser_beta((p->dB_range + p->gain) * + (1.1 + p->window_adjust / 50), .1); + lsx_apply_kaiser(w, n, beta); + break; + default: + lsx_apply_dolph(w, n, (p->dB_range + p->gain) * + (1.005 + p->window_adjust / 50) + 6); + } + + for (i = 0; i < p->dft_size; ++i) + sum += p->window[i]; + + /* empirical small window adjustment */ + for (--n, i = 0; i < p->dft_size; ++i) + p->window[i] *= 2 / sum * sqr((double)n / p->dft_size); + + return sum; +} + +static double *rdft_init(size_t n) +{ + double *q = lsx_malloc(2 * (n / 2 + 1) * n * sizeof(*q)); + double *p = q; + int i, j; + + for (j = 0; j <= n / 2; ++j) { + for (i = 0; i < n; ++i) { + *p++ = cos(2 * M_PI * j * i / n); + *p++ = sin(2 * M_PI * j * i / n); + } + } + + return q; +} + +#define _ re += in[i] * *q++, im += in[i++] * *q++, +static void rdft_p(const double *q, const double *in, double *out, int n) +{ + int i, j; + + for (j = 0; j <= n / 2; ++j) { + double re = 0, im = 0; + + for (i = 0; i < (n & ~7);) + _ _ _ _ _ _ _ _ (void)0; + + while (i < n) + _ (void)0; + + *out++ += re * re + im * im; + } +} + +static int start(sox_effect_t *effp) +{ + priv_t *p = effp->priv; + double actual; + double duration = 0.0; + double start_time = 0.0; + double pixels_per_sec = p->pixels_per_sec; + uint64_t d; + + memset(&p->WORK, 0, sizeof(*p) - field_offset(priv_t, WORK)); + + if (p->duration_str) { + lsx_parsesamples(effp->in_signal.rate, p->duration_str, &d, 't'); + duration = d / effp->in_signal.rate; + } + + if (p->start_time_str) { + uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN; + + if (!lsx_parseposition(effp->in_signal.rate, p->start_time_str, &d, + 0, in_length, '=') || d == SOX_UNKNOWN_LEN) { + lsx_fail("-S option: audio length is unknown"); + return SOX_EOF; + } + + start_time = d / effp->in_signal.rate; + p->skip = d; + } + + p->x_size = p->x_size0; + + while (sox_true) { + if (!pixels_per_sec && p->x_size && duration) + pixels_per_sec = min(5000, p->x_size / duration); + else if (!p->x_size && pixels_per_sec && duration) + p->x_size = min(MAX_X_SIZE, (int)(pixels_per_sec * duration + .5)); + + if (!duration && effp->in_signal.length != SOX_UNKNOWN_LEN) { + duration = effp->in_signal.length / + (effp->in_signal.rate * effp->in_signal.channels); + duration -= start_time; + if (duration <= 0) + duration = 1; + continue; + } else if (!p->x_size) { + p->x_size = 800; + continue; + } else if (!pixels_per_sec) { + pixels_per_sec = 100; + continue; + } + break; + } + + if (p->y_size) { + p->dft_size = 2 * (p->y_size - 1); + if (!is_p2(p->dft_size) && !effp->flow) + p->shared = rdft_init(p->dft_size); + } else { + int y = max(32, (p->Y_size? p->Y_size : 550) / effp->in_signal.channels - 2); + for (p->dft_size = 128; p->dft_size <= y; p->dft_size <<= 1); + } + + /* Now that dft_size is set, allocate variable-sized elements of priv_t */ + p->buf = lsx_calloc(p->dft_size, sizeof(*p->buf)); + p->dft_buf = lsx_calloc(p->dft_size, sizeof(*p->dft_buf)); + p->window = lsx_calloc(p->dft_size + 1, sizeof(*p->window)); + p->magnitudes = lsx_calloc(p->dft_size / 2 + 1, sizeof(*p->magnitudes)); + + if (is_p2(p->dft_size) && !effp->flow) + lsx_safe_rdft(p->dft_size, 1, p->dft_buf); + + lsx_debug("duration=%g x_size=%i pixels_per_sec=%g dft_size=%i", + duration, p->x_size, pixels_per_sec, p->dft_size); + + p->end = p->dft_size; + p->rows = (p->dft_size >> 1) + 1; + actual = make_window(p, p->last_end = 0); + lsx_debug("window_density=%g", actual / p->dft_size); + p->step_size = (p->slack_overlap ? sqrt(actual * p->dft_size) : actual) + 0.5; + p->block_steps = effp->in_signal.rate / pixels_per_sec; + p->step_size = + p->block_steps / ceil((double)p->block_steps / p->step_size) + 0.5; + p->block_steps = floor((double)p->block_steps / p->step_size + 0.5); + p->block_norm = 1.0 / p->block_steps; + actual = effp->in_signal.rate / p->step_size / p->block_steps; + if (!effp->flow && actual != pixels_per_sec) + lsx_report("actual pixels/s = %g", actual); + lsx_debug("step_size=%i block_steps=%i", p->step_size, p->block_steps); + p->max = -p->dB_range; + p->read = (p->step_size - p->dft_size) / 2; + + return SOX_SUCCESS; +} + +static int do_column(sox_effect_t *effp) +{ + priv_t *p = effp->priv; + int i; + + if (p->cols == p->x_size) { + p->truncated = sox_true; + if (!effp->flow) + lsx_report("PNG truncated at %g seconds", secs(p->cols)); + return p->truncate ? SOX_EOF : SOX_SUCCESS; + } + + ++p->cols; + p->dBfs = lsx_realloc(p->dBfs, p->cols * p->rows * sizeof(*p->dBfs)); + + /* FIXME: allocate in larger steps (for several columns) */ + for (i = 0; i < p->rows; ++i) { + double dBfs = 10 * log10(p->magnitudes[i] * p->block_norm); + p->dBfs[(p->cols - 1) * p->rows + i] = dBfs + p->gain; + p->max = max(dBfs, p->max); + } + + memset(p->magnitudes, 0, p->rows * sizeof(*p->magnitudes)); + p->block_num = 0; + + return SOX_SUCCESS; +} + +static int flow(sox_effect_t *effp, + const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t *p = effp->priv; + size_t len = *isamp = *osamp = min(*isamp, *osamp); + int i; + + memcpy(obuf, ibuf, len * sizeof(*obuf)); /* Pass on audio unaffected */ + + if (p->skip) { + if (p->skip >= len) { + p->skip -= len; + return SOX_SUCCESS; + } + ibuf += p->skip; + len -= p->skip; + p->skip = 0; + } + + while (!p->truncated) { + if (p->read == p->step_size) { + memmove(p->buf, p->buf + p->step_size, + (p->dft_size - p->step_size) * sizeof(*p->buf)); + p->read = 0; + } + + for (; len && p->read < p->step_size; --len, ++p->read, --p->end) + p->buf[p->dft_size - p->step_size + p->read] = + SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf++,); + + if (p->read != p->step_size) + break; + + if ((p->end = max(p->end, p->end_min)) != p->last_end) + make_window(p, p->last_end = p->end); + + for (i = 0; i < p->dft_size; ++i) + p->dft_buf[i] = p->buf[i] * p->window[i]; + + if (is_p2(p->dft_size)) { + lsx_safe_rdft(p->dft_size, 1, p->dft_buf); + p->magnitudes[0] += sqr(p->dft_buf[0]); + + for (i = 1; i < p->dft_size >> 1; ++i) + p->magnitudes[i] += sqr(p->dft_buf[2*i]) + sqr(p->dft_buf[2*i+1]); + + p->magnitudes[p->dft_size >> 1] += sqr(p->dft_buf[1]); + } + else + rdft_p(*p->shared_ptr, p->dft_buf, p->magnitudes, p->dft_size); + + if (++p->block_num == p->block_steps && do_column(effp) == SOX_EOF) + return SOX_EOF; + } + + return SOX_SUCCESS; +} + +static int drain(sox_effect_t *effp, sox_sample_t *obuf_, size_t *osamp) +{ + priv_t *p = effp->priv; + + if (!p->truncated) { + sox_sample_t * ibuf = lsx_calloc(p->dft_size, sizeof(*ibuf)); + sox_sample_t * obuf = lsx_calloc(p->dft_size, sizeof(*obuf)); + size_t isamp = (p->dft_size - p->step_size) / 2; + int left_over = (isamp + p->read) % p->step_size; + + if (left_over >= p->step_size >> 1) + isamp += p->step_size - left_over; + + lsx_debug("cols=%i left=%i end=%i", p->cols, p->read, p->end); + + p->end = 0, p->end_min = -p->dft_size; + + if (flow(effp, ibuf, obuf, &isamp, &isamp) == SOX_SUCCESS && p->block_num) { + p->block_norm *= (double)p->block_steps / p->block_num; + do_column(effp); + } + + lsx_debug("flushed cols=%i left=%i end=%i", p->cols, p->read, p->end); + free(obuf); + free(ibuf); + } + + *osamp = 0; + + return SOX_SUCCESS; +} + +enum { + Background, + Text, + Labels, + Grid, + fixed_palette +}; + +static unsigned colour(const priv_t *p, double x) +{ + unsigned c = x < -p->dB_range ? 0 : x >= 0 ? p->spectrum_points - 1 : + 1 + (1 + x / p->dB_range) * (p->spectrum_points - 2); + return fixed_palette + c; +} + +static void make_palette(const priv_t *p, png_color *palette) +{ + static const unsigned char black[] = { 0x00, 0x00, 0x00 }; + static const unsigned char dgrey[] = { 0x3f, 0x3f, 0x3f }; + static const unsigned char mgrey[] = { 0x7f, 0x7f, 0x7f }; + static const unsigned char lgrey[] = { 0xbf, 0xbf, 0xbf }; + static const unsigned char white[] = { 0xff, 0xff, 0xff }; + static const unsigned char lbgnd[] = { 0xdd, 0xd8, 0xd0 }; + static const unsigned char mbgnd[] = { 0xdf, 0xdf, 0xdf }; + int i; + + if (p->light_background) { + memcpy(palette++, p->monochrome ? mbgnd : lbgnd, 3); + memcpy(palette++, black, 3); + memcpy(palette++, dgrey, 3); + memcpy(palette++, dgrey, 3); + } else { + memcpy(palette++, black, 3); + memcpy(palette++, white, 3); + memcpy(palette++, lgrey, 3); + memcpy(palette++, mgrey, 3); + } + + for (i = 0; i < p->spectrum_points; ++i) { + double c[3]; + double x = (double)i / (p->spectrum_points - 1); + int at = p->light_background ? p->spectrum_points - 1 - i : i; + + if (p->monochrome) { + c[2] = c[1] = c[0] = x; + if (p->high_colour) { + c[(1 + p->perm) % 3] = x < .4? 0 : 5 / 3. * (x - .4); + if (p->perm < 3) + c[(2 + p->perm) % 3] = x < .4? 0 : 5 / 3. * (x - .4); + } + palette[at].red = .5 + 255 * c[0]; + palette[at].green= .5 + 255 * c[1]; + palette[at].blue = .5 + 255 * c[2]; + continue; + } + + if (p->high_colour) { + static const int states[3][7] = { + { 4, 5, 0, 0, 2, 1, 1 }, + { 0, 0, 2, 1, 1, 3, 2 }, + { 4, 1, 1, 3, 0, 0, 2 }, + }; + int j, phase_num = min(7 * x, 6); + + for (j = 0; j < 3; ++j) { + switch (states[j][phase_num]) { + case 0: c[j] = 0; break; + case 1: c[j] = 1; break; + case 2: c[j] = sin((7 * x - phase_num) * M_PI / 2); break; + case 3: c[j] = cos((7 * x - phase_num) * M_PI / 2); break; + case 4: c[j] = 7 * x - phase_num; break; + case 5: c[j] = 1 - (7 * x - phase_num); break; + } + } + } else if (p->alt_palette) { + int n = (double)i / (p->spectrum_points - 1) * (alt_palette_len - 1) + .5; + c[0] = alt_palette[3 * n + 0] / 255.; + c[1] = alt_palette[3 * n + 1] / 255.; + c[2] = alt_palette[3 * n + 2] / 255.; + } else { + if (x < .13) c[0] = 0; + else if (x < .73) c[0] = 1 * sin((x - .13) / .60 * M_PI / 2); + else c[0] = 1; + if (x < .60) c[1] = 0; + else if (x < .91) c[1] = 1 * sin((x - .60) / .31 * M_PI / 2); + else c[1] = 1; + if (x < .60) c[2] = .5 * sin((x - .00) / .60 * M_PI); + else if (x < .78) c[2] = 0; + else c[2] = (x - .78) / .22; + } + + palette[at].red = .5 + 255 * c[p->perm % 3]; + palette[at].green= .5 + 255 * c[(1 + p->perm + (p->perm % 2)) % 3]; + palette[at].blue = .5 + 255 * c[(2 + p->perm - (p->perm % 2)) % 3]; + } +} + +static const Bytef fixed[] = { + 0x78, 0xda, 0x65, 0x54, 0xa1, 0xb6, 0xa5, 0x30, 0x0c, 0x44, 0x56, 0x56, + 0x3e, 0x59, 0xf9, 0x24, 0x72, 0x65, 0x25, 0x32, 0x9f, 0x80, 0x7c, 0x32, + 0x12, 0x59, 0x59, 0x89, 0x44, 0x22, 0x2b, 0xdf, 0x27, 0x3c, 0x79, 0xe5, + 0xca, 0xfd, 0x0c, 0x64, 0xe5, 0x66, 0x92, 0x94, 0xcb, 0x9e, 0x9d, 0x7b, + 0xb8, 0xe4, 0x4c, 0xa7, 0x61, 0x9a, 0x04, 0xa6, 0xe9, 0x81, 0x64, 0x98, + 0x92, 0xc4, 0x44, 0xf4, 0x5e, 0x20, 0xea, 0xf2, 0x53, 0x22, 0x6d, 0xe7, + 0xc9, 0x9f, 0x9f, 0x17, 0x34, 0x4b, 0xa3, 0x98, 0x32, 0xb5, 0x1d, 0x0b, + 0xf9, 0x3c, 0xf3, 0x79, 0xec, 0x5f, 0x96, 0x67, 0xec, 0x8c, 0x29, 0x65, + 0x20, 0xa5, 0x38, 0xe1, 0x0f, 0x10, 0x4a, 0x34, 0x8d, 0x5b, 0x7a, 0x3c, + 0xb9, 0xbf, 0xf7, 0x00, 0x33, 0x34, 0x40, 0x7f, 0xd8, 0x63, 0x97, 0x84, + 0x20, 0x49, 0x72, 0x2e, 0x05, 0x24, 0x55, 0x80, 0xb0, 0x94, 0xd6, 0x53, + 0x0f, 0x80, 0x3d, 0x5c, 0x6b, 0x10, 0x51, 0x41, 0xdc, 0x25, 0xe2, 0x10, + 0x2a, 0xc3, 0x50, 0x9c, 0x89, 0xf6, 0x1e, 0x23, 0xf8, 0x52, 0xbe, 0x5f, + 0xce, 0x73, 0x2d, 0xe5, 0x92, 0x44, 0x6c, 0x7a, 0xf3, 0x6d, 0x79, 0x2a, + 0x3b, 0x8f, 0xfb, 0xe6, 0x7a, 0xb7, 0xe3, 0x9e, 0xf4, 0xa6, 0x9e, 0xf5, + 0xa1, 0x39, 0xc5, 0x70, 0xdb, 0xb7, 0x13, 0x28, 0x87, 0xb5, 0xdb, 0x9b, + 0xd5, 0x59, 0xe2, 0xa3, 0xb5, 0xef, 0xb2, 0x8d, 0xb3, 0x74, 0xb9, 0x24, + 0xbe, 0x96, 0x65, 0x61, 0xb9, 0x2e, 0xf7, 0x26, 0xd0, 0xe7, 0x82, 0x5f, + 0x9c, 0x17, 0xff, 0xe5, 0x92, 0xab, 0x3f, 0xe2, 0x32, 0xf4, 0x87, 0x79, + 0xae, 0x9e, 0x12, 0x39, 0xd9, 0x1b, 0x0c, 0xfe, 0x97, 0xb6, 0x22, 0xee, + 0xab, 0x6a, 0xf6, 0xf3, 0xe7, 0xdc, 0x55, 0x53, 0x1c, 0x5d, 0xf9, 0x3f, + 0xad, 0xf9, 0xde, 0xfa, 0x7a, 0xb5, 0x76, 0x1c, 0x96, 0xa7, 0x1a, 0xd4, + 0x8f, 0xdc, 0xdf, 0xcf, 0x55, 0x34, 0x0e, 0xce, 0x7b, 0x4e, 0xf8, 0x19, + 0xf5, 0xef, 0x69, 0x4c, 0x99, 0x79, 0x1b, 0x79, 0xb4, 0x89, 0x44, 0x37, + 0xdf, 0x04, 0xa4, 0xb1, 0x90, 0x44, 0xe6, 0x01, 0xb1, 0xef, 0xed, 0x3e, + 0x03, 0xe2, 0x93, 0xf3, 0x00, 0xc3, 0xbf, 0x0c, 0x5b, 0x8c, 0x41, 0x2c, + 0x70, 0x1c, 0x60, 0xad, 0xed, 0xf4, 0x1f, 0xfa, 0x94, 0xe2, 0xbf, 0x0c, + 0x87, 0xad, 0x1e, 0x5f, 0x56, 0x07, 0x1c, 0xa1, 0x5e, 0xce, 0x57, 0xaf, + 0x7f, 0x08, 0xa2, 0xc0, 0x1c, 0x0c, 0xbe, 0x1b, 0x3f, 0x2f, 0x39, 0x5f, + 0xd9, 0x66, 0xe6, 0x1e, 0x15, 0x59, 0x29, 0x98, 0x31, 0xaf, 0xa1, 0x34, + 0x7c, 0x1d, 0xf5, 0x9f, 0xe2, 0x34, 0x6b, 0x03, 0xa4, 0x03, 0xa2, 0xb1, + 0x06, 0x08, 0xbd, 0x3e, 0x7a, 0x24, 0xf8, 0x8d, 0x3a, 0xb8, 0xf3, 0x77, + 0x1e, 0x2f, 0xb5, 0x6b, 0x46, 0x0b, 0x10, 0x6f, 0x36, 0xa2, 0xc1, 0xf4, + 0xde, 0x17, 0xd5, 0xaf, 0xd1, 0xf4, 0x66, 0x73, 0x99, 0x8d, 0x47, 0x1a, + 0x3d, 0xaf, 0xc5, 0x44, 0x69, 0xc4, 0x5e, 0x7f, 0xc4, 0x52, 0xf4, 0x51, + 0x3d, 0x95, 0xfb, 0x1b, 0xd0, 0xfd, 0xfd, 0xfa, 0x80, 0xdf, 0x1f, 0xfc, + 0x7d, 0xdc, 0xdf, 0x10, 0xf4, 0xc8, 0x28, 0x5d, 0xc4, 0xb7, 0x62, 0x7f, + 0xd6, 0x59, 0x72, 0x6a, 0xca, 0xbf, 0xfb, 0x9b, 0x1f, 0xe0, +}; + +static unsigned char *font; + +#define font_x 5 +#define font_y 12 +#define font_X (font_x + 1) + +#define pixel(x,y) pixels[(y) * cols + (x)] +#define print_at(x,y,c,t) print_at_(pixels,cols,x,y,c,t,0) +#define print_up(x,y,c,t) print_at_(pixels,cols,x,y,c,t,1) + +static void print_at_(png_byte *pixels, int cols, int x, int y, int c, + const char *text, int orientation) +{ + for (; *text; ++text) { + int pos = ((*text < ' ' || *text > '~'? '~' + 1 : *text) - ' ') * font_y; + int i, j; + + for (i = 0; i < font_y; ++i) { + unsigned line = font[pos++]; + for (j = 0; j < font_x; ++j, line <<= 1) { + if (line & 0x80) { + switch (orientation) { + case 0: pixel(x + j, y - i) = c; break; + case 1: pixel(x + i, y + j) = c; break; + } + } + } + } + + switch (orientation) { + case 0: x += font_X; break; + case 1: y += font_X; break; + } + } +} + +static int axis(double to, int max_steps, double *limit, char **prefix) +{ + double scale = 1, step = max(1, 10 * to); + int i, prefix_num = 0; + + if (max_steps) { + double try; + double log_10 = HUGE_VAL; + double min_step = (to *= 10) / max_steps; + + for (i = 5; i; i >>= 1) { + if ((try = ceil(log10(min_step * i))) <= log_10) { + step = pow(10., log_10 = try) / i; + log_10 -= i > 1; + } + } + + prefix_num = floor(log_10 / 3); + scale = pow(10., -3. * prefix_num); + } + + *prefix = "pnum-kMGTPE" + prefix_num + (prefix_num? 4 : 11); + *limit = to * scale; + + return step * scale + .5; +} + +#define below 48 +#define left 58 +#define between 37 +#define spectrum_width 14 +#define right 35 + +static int stop(sox_effect_t *effp) /* only called, by end(), on flow 0 */ +{ + priv_t *p = effp->priv; + FILE *file; + uLong font_len = 96 * font_y; + int chans = effp->in_signal.channels; + int c_rows = p->rows * chans + chans - 1; + int rows = p->raw? c_rows : below + c_rows + 30 + 20 * !!p->title; + int cols = p->raw? p->cols : left + p->cols + between + spectrum_width + right; + png_byte *pixels = lsx_malloc(cols * rows * sizeof(*pixels)); + png_bytepp png_rows = lsx_malloc(rows * sizeof(*png_rows)); + png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0,0); + png_infop png_info = png_create_info_struct(png); + png_color palette[256]; + int i, j, k; + int base; + int step; + int tick_len = 3 - p->no_axes; + char text[200]; + char *prefix; + double limit; + float autogain = 0.0; /* Is changed if the -n flag was supplied */ + + free(p->shared); + + if (p->using_stdout) { + SET_BINARY_MODE(stdout); + file = stdout; + } else { + file = fopen(p->out_name, "wb"); + if (!file) { + lsx_fail("failed to create `%s': %s", p->out_name, strerror(errno)); + goto error; + } + } + + lsx_debug("signal-max=%g", p->max); + + font = lsx_malloc(font_len); + assert(uncompress(font, &font_len, fixed, sizeof(fixed)) == Z_OK); + + make_palette(p, palette); + memset(pixels, Background, cols * rows * sizeof(*pixels)); + + png_init_io(png, file); + png_set_PLTE(png, png_info, palette, fixed_palette + p->spectrum_points); + png_set_IHDR(png, png_info, cols, rows, 8, + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + for (j = 0; j < rows; ++j) /* Put (0,0) at bottom-left of PNG */ + png_rows[rows - 1 - j] = pixels + j * cols; + + /* Spectrogram */ + + if (p->normalize) + /* values are already in dB, so we subtract the maximum value + * (which will normally be negative) to raise the maximum to 0.0. + */ + autogain = -p->max; + + for (k = 0; k < chans; ++k) { + priv_t *q = (effp - effp->flow + k)->priv; + + if (p->normalize) { + float *fp = q->dBfs; + for (i = p->rows * p->cols; i > 0; i--) + *fp++ += autogain; + } + + base = !p->raw * below + (chans - 1 - k) * (p->rows + 1); + + for (j = 0; j < p->rows; ++j) { + for (i = 0; i < p->cols; ++i) + pixel(!p->raw * left + i, base + j) = colour(p, q->dBfs[i*p->rows + j]); + + if (!p->raw && !p->no_axes) /* Y-axis lines */ + pixel(left - 1, base + j) = pixel(left + p->cols, base + j) = Grid; + } + + if (!p->raw && !p->no_axes) /* X-axis lines */ + for (i = -1; i <= p->cols; ++i) + pixel(left + i, base - 1) = pixel(left + i, base + p->rows) = Grid; + } + + if (!p->raw) { + if (p->title && (i = strlen(p->title) * font_X) < cols + 1) /* Title */ + print_at((cols - i) / 2, rows - font_y, Text, p->title); + + if (strlen(p->comment) * font_X < cols + 1) /* Footer comment */ + print_at(1, font_y, Text, p->comment); + + /* X-axis */ + step = axis(secs(p->cols), p->cols / (font_X * 9 / 2), &limit, &prefix); + sprintf(text, "Time (%.1ss)", prefix); /* Axis label */ + print_at(left + (p->cols - font_X * strlen(text)) / 2, 24, Text, text); + + for (i = 0; i <= limit; i += step) { + int x = limit ? (double)i / limit * p->cols + .5 : 0; + int y; + + for (y = 0; y < tick_len; ++y) /* Ticks */ + pixel(left-1+x, below-1-y) = pixel(left-1+x, below+c_rows+y) = Grid; + + if (step == 5 && (i%10)) + continue; + + sprintf(text, "%g", .1 * i); /* Tick labels */ + x = left + x - 3 * strlen(text); + print_at(x, below - 6, Labels, text); + print_at(x, below + c_rows + 14, Labels, text); + } + + /* Y-axis */ + step = axis(effp->in_signal.rate / 2, + (p->rows - 1) / ((font_y * 3 + 1) >> 1), &limit, &prefix); + sprintf(text, "Frequency (%.1sHz)", prefix); /* Axis label */ + print_up(10, below + (c_rows - font_X * strlen(text)) / 2, Text, text); + + for (k = 0; k < chans; ++k) { + base = below + k * (p->rows + 1); + + for (i = 0; i <= limit; i += step) { + int y = limit ? (double)i / limit * (p->rows - 1) + .5 : 0; + int x; + + for (x = 0; x < tick_len; ++x) /* Ticks */ + pixel(left-1-x, base+y) = pixel(left+p->cols+x, base+y) = Grid; + + if ((step == 5 && (i%10)) || (!i && k && chans > 1)) + continue; + + sprintf(text, i?"%5g":" DC", .1 * i); /* Tick labels */ + print_at(left - 4 - font_X * 5, base + y + 5, Labels, text); + sprintf(text, i?"%g":"DC", .1 * i); + print_at(left + p->cols + 6, base + y + 5, Labels, text); + } + } + + /* Z-axis */ + k = min(400, c_rows); + base = below + (c_rows - k) / 2; + print_at(cols - right - 2 - font_X, base - 13, Text, "dBFS");/* Axis label */ + for (j = 0; j < k; ++j) { /* Spectrum */ + png_byte b = colour(p, p->dB_range * (j / (k - 1.) - 1)); + for (i = 0; i < spectrum_width; ++i) + pixel(cols - right - 1 - i, base + j) = b; + } + + step = 10 * ceil(p->dB_range / 10. * (font_y + 2) / (k - 1)); + + for (i = 0; i <= p->dB_range; i += step) { /* (Tick) labels */ + int y = (double)i / p->dB_range * (k - 1) + .5; + sprintf(text, "%+i", i - p->gain - p->dB_range - (int)(autogain+0.5)); + print_at(cols - right + 1, base + y + 5, Labels, text); + } + } + + free(font); + + png_set_rows(png, png_info, png_rows); + png_write_png(png, png_info, PNG_TRANSFORM_IDENTITY, NULL); + + if (!p->using_stdout) + fclose(file); + +error: + png_destroy_write_struct(&png, &png_info); + free(png_rows); + free(pixels); + free(p->dBfs); + free(p->buf); + free(p->dft_buf); + free(p->window); + free(p->magnitudes); + + return SOX_SUCCESS; +} + +static int end(sox_effect_t *effp) +{ + priv_t *p = effp->priv; + + if (effp->flow == 0) + return stop(effp); + + free(p->dBfs); + + return SOX_SUCCESS; +} + +const sox_effect_handler_t *lsx_spectrogram_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "spectrogram", + 0, + SOX_EFF_MODIFY, + getopts, + start, + flow, + drain, + end, + 0, + sizeof(priv_t) + }; + static const char *lines[] = { + "[options]", + "\t-x num\tX-axis size in pixels; default derived or 800", + "\t-X num\tX-axis pixels/second; default derived or 100", + "\t-y num\tY-axis size in pixels (per channel); slow if not 1 + 2^n", + "\t-Y num\tY-height total (i.e. not per channel); default 550", + "\t-z num\tZ-axis range in dB; default 120", + "\t-Z num\tZ-axis maximum in dBFS; default 0", + "\t-n\tSet Z-axis maximum to the brightest pixel", + "\t-q num\tZ-axis quantisation (0 - 249); default 249", + "\t-w name\tWindow: Hann(default)/Hamming/Bartlett/Rectangular/Kaiser/Dolph", + "\t-W num\tWindow adjust parameter (-10 - 10); applies only to Kaiser/Dolph", + "\t-s\tSlack overlap of windows", + "\t-a\tSuppress axis lines", + "\t-r\tRaw spectrogram; no axes or legends", + "\t-l\tLight background", + "\t-m\tMonochrome", + "\t-h\tHigh colour", + "\t-p num\tPermute colours (1 - 6); default 1", + "\t-A\tAlternative, inferior, fixed colour-set (for compatibility only)", + "\t-t text\tTitle text", + "\t-c text\tComment text", + "\t-o text\tOutput file name; default `spectrogram.png'", + "\t-d time\tAudio duration to fit to X-axis; e.g. 1:00, 48", + "\t-S position\tStart the spectrogram at the given input position", + }; + static char *usage; + handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); + return &handler; +} diff --git a/app/src/main/cpp/sox/speed.c b/app/src/main/cpp/sox/speed.c new file mode 100644 index 0000000..892675e --- /dev/null +++ b/app/src/main/cpp/sox/speed.c @@ -0,0 +1,73 @@ +/* libSoX Effect: Adjust the audio speed (pitch and tempo together) + * (c) 2006,8 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * + * Adjustment is given as the ratio of the new speed to the old speed, or as + * a number of cents (100ths of a semitone) to change. Speed change is + * actually performed by whichever resampling effect is in effect. + */ + +#include "sox_i.h" +#include + +typedef struct { + double factor; +} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *) effp->priv; + sox_bool is_cents = sox_false; + + --argc, ++argv; + if (argc == 1) { + char c, dummy; + int scanned = sscanf(*argv, "%lf%c %c", &p->factor, &c, &dummy); + if (scanned == 1 || (scanned == 2 && c == 'c')) { + is_cents |= scanned == 2; + if (is_cents || p->factor > 0) { + p->factor = is_cents? pow(2., p->factor / 1200) : p->factor; + return SOX_SUCCESS; + } + } + } + return lsx_usage(effp); +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + + if (p->factor == 1) + return SOX_EFF_NULL; + + effp->out_signal.rate = effp->in_signal.rate * p->factor; + + effp->out_signal.length = effp->in_signal.length; + /* audio length if measured in samples doesn't change */ + + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_speed_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "speed", "factor[c]", + SOX_EFF_MCHAN | SOX_EFF_RATE | SOX_EFF_LENGTH | SOX_EFF_MODIFY, + getopts, start, lsx_flow_copy, 0, 0, 0, sizeof(priv_t)}; + return &handler; +} diff --git a/app/src/main/cpp/sox/speexdsp.c b/app/src/main/cpp/sox/speexdsp.c new file mode 100644 index 0000000..309e560 --- /dev/null +++ b/app/src/main/cpp/sox/speexdsp.c @@ -0,0 +1,349 @@ +/* libSoX effect: SpeexDsp effect to apply processing from libspeexdsp. + * + * Copyright 1999-2009 Chris Bagwell And SoX Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#ifdef HAVE_SPEEXDSP + +#include +#include + +/* Private data for effect */ +typedef struct speexdsp_priv_t { + size_t buffer_end; /* Index of the end of the buffer. */ + size_t buffer_ipos; /* Index for the next input sample. */ + size_t buffer_opos; /* Index of the next sample that has not been drained. */ + int16_t* buffer; /* Work buffer. */ + SpeexPreprocessState* sps;/* DSP state. */ + size_t agc; /* Param: Automatic Gain Control target volume level: 0 to disable, or 1-100 (target volume). */ + size_t denoise; /* Param: Denoise: 0 to disable, or maximum noise attenuation in dB. */ + size_t dereverb; /* Param: Dereverb: 0 to disable, 1 to enable. */ + size_t frames_per_second; /* Param: Used to compute buffer size from sample rate. */ + size_t samples_per_frame; /* Param: Used to compute buffer size directly. Default is to use frames_per_second instead. */ +} priv_t; + +static int get_param( + int* pArgc, + char*** pArgv, + size_t* pParam, + size_t default_val, + size_t min_valid, + size_t max_valid) +{ + *pParam = default_val; + if (*pArgc > 1 && (*pArgv)[1][0] != '-') + { + char* arg_end; + *pParam = strtoul((*pArgv)[1], &arg_end, 0); + if (!arg_end || arg_end[0] || *pParam < min_valid || max_valid <= *pParam) + return 0; + + --*pArgc; + ++*pArgv; + } + + return 1; +} + +/* + * Process command-line options but don't do other + * initialization now: effp->in_signal & effp->out_signal are not + * yet filled in. + */ +static int getopts(sox_effect_t* effp, int argc, char** argv) +{ + priv_t* p = (priv_t*)effp->priv; + const size_t agcDefault = 100; + const size_t denoiseDefault = 15; + const size_t fpsDefault = 50; + + for (argc--, argv++; argc; argc--, argv++) + { + if (!strcasecmp("-agc", argv[0])) + { + /* AGC level argument is optional. If not specified, it defaults to agcDefault. + If specified, it must be from 0 to 100. */ + if (!get_param(&argc, &argv, &p->agc, agcDefault, 0, 100)) + { + lsx_fail("Invalid argument \"%s\" to -agc parameter - expected number from 0 to 100.", argv[1]); + return lsx_usage(effp); + } + } + else if (!strcasecmp("-denoise", argv[0])) + { + /* Denoise level argument is optional. If not specified, it defaults to denoiseDefault. + If specified, it must be from 0 to 100. */ + if (!get_param(&argc, &argv, &p->denoise, denoiseDefault, 0, 100)) + { + lsx_fail("Invalid argument \"%s\" to -denoise parameter - expected number from 0 to 100.", argv[1]); + return lsx_usage(effp); + } + } + else if (!strcasecmp("-dereverb", argv[0])) + { + p->dereverb = 1; + } + else if (!strcasecmp("-spf", argv[0])) + { + /* If samples_per_frame option is given, argument is required and must be + greater than 0. */ + if (!get_param(&argc, &argv, &p->samples_per_frame, 0, 1, 1000000000) || !p->samples_per_frame) + { + lsx_fail("Invalid argument \"%s\" to -spf parameter - expected positive number.", argv[1]); + return lsx_usage(effp); + } + } + else if (!strcasecmp("-fps", argv[0])) + { + /* If frames_per_second option is given, argument is required and must be + from 1 to 100. This will be used later to compute samples_per_frame once + we know the sample rate). */ + if (!get_param(&argc, &argv, &p->frames_per_second, 0, 1, 100) || !p->frames_per_second) + { + lsx_fail("Invalid argument \"%s\" to -fps parameter - expected number from 1 to 100.", argv[1]); + return lsx_usage(effp); + } + } + else + { + lsx_fail("Invalid parameter \"%s\".", argv[0]); + return lsx_usage(effp); + } + } + + if (!p->frames_per_second) + p->frames_per_second = fpsDefault; + + if (!p->agc && !p->denoise && !p->dereverb) + { + lsx_report("No features specified. Enabling default settings \"-agc %u -denoise %u\".", agcDefault, denoiseDefault); + p->agc = agcDefault; + p->denoise = denoiseDefault; + } + + return SOX_SUCCESS; +} + +/* + * Do anything required when you stop reading samples. + */ +static int stop(sox_effect_t* effp) +{ + priv_t* p = (priv_t*)effp->priv; + + if (p->sps) + { + speex_preprocess_state_destroy(p->sps); + p->sps = NULL; + } + + if (p->buffer) + { + free(p->buffer); + p->buffer = NULL; + } + + return SOX_SUCCESS; +} + +/* + * Prepare processing. + * Do all initializations. + */ +static int start(sox_effect_t* effp) +{ + priv_t* p = (priv_t*)effp->priv; + int result = SOX_SUCCESS; + spx_int32_t int_val; + float float_val; + + if (p->samples_per_frame) + { + p->buffer_end = p->samples_per_frame; + } + else + { + p->buffer_end = effp->in_signal.rate / p->frames_per_second; + if (!p->buffer_end) + { + lsx_fail("frames_per_second too large for the current sample rate."); + return SOX_EOF; + } + } + + p->buffer_opos = p->buffer_end; + effp->out_signal.precision = 16; + + p->buffer = lsx_malloc(p->buffer_end * sizeof(p->buffer[0])); + if (!p->buffer) + { + result = SOX_ENOMEM; + goto Done; + } + + p->sps = speex_preprocess_state_init((int)p->buffer_end, (int)(effp->in_signal.rate + .5)); + if (!p->sps) + { + lsx_fail("Failed to initialize preprocessor DSP."); + result = SOX_EOF; + goto Done; + } + + int_val = p->agc ? 1 : 2; + speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_AGC, &int_val); + if (p->agc) + { + float_val = p->agc * 327.68f; + speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_AGC_LEVEL, &float_val); + } + + int_val = p->denoise ? 1 : 2; + speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_DENOISE, &int_val); + if (p->denoise) + { + int_val = -(spx_int32_t)p->denoise; + speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &int_val); + } + + int_val = p->dereverb ? 1 : 2; + speex_preprocess_ctl(p->sps, SPEEX_PREPROCESS_SET_DEREVERB, &int_val); + +Done: + if (result != SOX_SUCCESS) + stop(effp); + + return result; +} + +/* + * Process up to *isamp samples from ibuf and produce up to *osamp samples + * in obuf. Write back the actual numbers of samples to *isamp and *osamp. + * Return SOX_SUCCESS or, if error occurs, SOX_EOF. + */ +static int flow( + sox_effect_t* effp, + const sox_sample_t* ibuf, + sox_sample_t* obuf, + size_t* isamp, + size_t* osamp) +{ + priv_t* p = (priv_t*)effp->priv; + size_t ibuf_pos = 0; + size_t ibuf_end = *isamp; + size_t obuf_pos = 0; + size_t obuf_end = *osamp; + size_t end_pos; + SOX_SAMPLE_LOCALS; + + for (;;) + { + /* Write any processed data in working buffer to the output buffer. */ + end_pos = obuf_pos + min(p->buffer_end - p->buffer_opos, obuf_end - obuf_pos); + for (; obuf_pos < end_pos; obuf_pos++, p->buffer_opos++) + obuf[obuf_pos] = SOX_SIGNED_16BIT_TO_SAMPLE(p->buffer[p->buffer_opos], dummy); + if (p->buffer_opos != p->buffer_end) + break; /* Output buffer is full and we still have more processed data. */ + + /* Fill working buffer from input buffer. */ + end_pos = ibuf_pos + min(p->buffer_end - p->buffer_ipos, ibuf_end - ibuf_pos); + for (; ibuf_pos < end_pos; ibuf_pos++, p->buffer_ipos++) + p->buffer[p->buffer_ipos] = SOX_SAMPLE_TO_SIGNED_16BIT(ibuf[ibuf_pos], effp->clips); + if (p->buffer_ipos != p->buffer_end) + break; /* Working buffer is not full and there is no more input data. */ + + speex_preprocess_run(p->sps, p->buffer); + p->buffer_ipos = 0; + p->buffer_opos = 0; + } + + *isamp = ibuf_pos; + *osamp = obuf_pos; + return SOX_SUCCESS; +} + +/* + * Drain out remaining samples if the effect generates any. + */ +static int drain(sox_effect_t* effp, sox_sample_t* obuf, size_t* osamp) +{ + priv_t* p = (priv_t*)effp->priv; + size_t obuf_pos = 0; + size_t obuf_end = *osamp; + size_t i; + size_t end_pos; + + /* Input that hasn't been processed yet? */ + if (p->buffer_ipos != 0) + { + /* DSP only works on full frames, so fill the remaining space with 0s. */ + for (i = p->buffer_ipos; i < p->buffer_end; i++) + p->buffer[i] = 0; + speex_preprocess_run(p->sps, p->buffer); + p->buffer_end = p->buffer_ipos; + p->buffer_ipos = 0; + p->buffer_opos = 0; + } + + end_pos = obuf_pos + min(p->buffer_end - p->buffer_opos, obuf_end - obuf_pos); + for (; obuf_pos < end_pos; obuf_pos++, p->buffer_opos++) + obuf[obuf_pos] = SOX_SIGNED_16BIT_TO_SAMPLE(p->buffer[p->buffer_opos], dummy); + + *osamp = obuf_pos; + return + p->buffer_opos != p->buffer_end + ? SOX_SUCCESS + : SOX_EOF; +} + +/* + * Function returning effect descriptor. This should be the only + * externally visible object. + */ +const sox_effect_handler_t* lsx_speexdsp_effect_fn(void) +{ + /* + * Effect descriptor. + * If no specific processing is needed for any of + * the 6 functions, then the function above can be deleted + * and NULL used in place of the its name below. + */ + static sox_effect_handler_t descriptor = { + "speexdsp", 0, SOX_EFF_PREC | SOX_EFF_GAIN | SOX_EFF_ALPHA, + getopts, start, flow, drain, stop, NULL, sizeof(priv_t) + }; + static char const * lines[] = { + "Uses the Speex DSP library to improve perceived sound quality.", + "If no options are specified, the -agc and -denoise features are enabled.", + "Options:", + "-agc [target_level] Enable automatic gain control, and optionally specify a", + " target volume level from 1-100 (default is 100).", + "-denoise [max_dB] Enable noise reduction, and optionally specify the max", + " attenuation (default is 15).", + "-dereverb Enable reverb reduction.", + "-fps frames_per_second Specify the number of frames per second from 1-100", + " (default is 20).", + "-spf samples_per_frame Specify the number of samples per frame. Default is to", + " use the -fps setting.", + }; + static char * usage; + descriptor.usage = lsx_usage_lines(&usage, lines, array_length(lines)); + return &descriptor; +} + +#endif /* HAVE_SPEEXDSP */ diff --git a/app/src/main/cpp/sox/sphere.c b/app/src/main/cpp/sox/sphere.c new file mode 100644 index 0000000..a3fd1c6 --- /dev/null +++ b/app/src/main/cpp/sox/sphere.c @@ -0,0 +1,199 @@ +/* libSoX NIST Sphere file format handler. + * + * August 7, 2000 + * + * Copyright (C) 2000 Chris Bagwell (cbagwell@sprynet.com) + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +static int start_read(sox_format_t * ft) +{ + unsigned long header_size_ul = 0, num_samples_ul = 0; + sox_encoding_t encoding = SOX_ENCODING_SIGN2; + size_t header_size, bytes_read; + size_t num_samples = 0; + unsigned bytes_per_sample = 0; + unsigned channels = 1; + unsigned rate = 16000; + char fldname[64], fldtype[16], fldsval[128]; + char * buf; + + /* Magic header */ + if (lsx_reads(ft, fldname, (size_t)8) || strncmp(fldname, "NIST_1A", (size_t)7) != 0) { + lsx_fail_errno(ft, SOX_EHDR, "Sphere header does not begin with magic word `NIST_1A'"); + return (SOX_EOF); + } + + if (lsx_reads(ft, fldsval, (size_t)8)) { + lsx_fail_errno(ft, SOX_EHDR, "Error reading Sphere header"); + return (SOX_EOF); + } + + /* Determine header size, and allocate a buffer large enough to hold it. */ + sscanf(fldsval, "%lu", &header_size_ul); + if (header_size_ul < 16) { + lsx_fail_errno(ft, SOX_EHDR, "Error reading Sphere header"); + return (SOX_EOF); + } + + buf = lsx_malloc(header_size = header_size_ul); + + /* Skip what we have read so far */ + header_size -= 16; + + if (lsx_reads(ft, buf, header_size) == SOX_EOF) { + lsx_fail_errno(ft, SOX_EHDR, "Error reading Sphere header"); + free(buf); + return (SOX_EOF); + } + + header_size -= (strlen(buf) + 1); + + while (strncmp(buf, "end_head", (size_t)8) != 0) { + if (strncmp(buf, "sample_n_bytes", (size_t)14) == 0) + sscanf(buf, "%63s %15s %u", fldname, fldtype, &bytes_per_sample); + else if (strncmp(buf, "channel_count", (size_t)13) == 0) + sscanf(buf, "%63s %15s %u", fldname, fldtype, &channels); + else if (strncmp(buf, "sample_count ", (size_t)13) == 0) + sscanf(buf, "%53s %15s %lu", fldname, fldtype, &num_samples_ul); + else if (strncmp(buf, "sample_rate ", (size_t)12) == 0) + sscanf(buf, "%53s %15s %u", fldname, fldtype, &rate); + else if (strncmp(buf, "sample_coding", (size_t)13) == 0) { + sscanf(buf, "%63s %15s %127s", fldname, fldtype, fldsval); + if (!strcasecmp(fldsval, "ulaw") || !strcasecmp(fldsval, "mu-law")) + encoding = SOX_ENCODING_ULAW; + else if (!strcasecmp(fldsval, "pcm")) + encoding = SOX_ENCODING_SIGN2; + else { + lsx_fail_errno(ft, SOX_EFMT, "sph: unsupported coding `%s'", fldsval); + free(buf); + return SOX_EOF; + } + } + else if (strncmp(buf, "sample_byte_format", (size_t)18) == 0) { + sscanf(buf, "%53s %15s %127s", fldname, fldtype, fldsval); + if (strcmp(fldsval, "01") == 0) /* Data is little endian. */ + ft->encoding.reverse_bytes = MACHINE_IS_BIGENDIAN; + else if (strcmp(fldsval, "10") == 0) /* Data is big endian. */ + ft->encoding.reverse_bytes = MACHINE_IS_LITTLEENDIAN; + else if (strcmp(fldsval, "1")) { + lsx_fail_errno(ft, SOX_EFMT, "sph: unsupported coding `%s'", fldsval); + free(buf); + return SOX_EOF; + } + } + + if (lsx_reads(ft, buf, header_size) == SOX_EOF) { + lsx_fail_errno(ft, SOX_EHDR, "Error reading Sphere header"); + free(buf); + return (SOX_EOF); + } + + header_size -= (strlen(buf) + 1); + } + + if (!bytes_per_sample) + bytes_per_sample = encoding == SOX_ENCODING_ULAW? 1 : 2; + + while (header_size) { + bytes_read = lsx_readbuf(ft, buf, header_size); + if (bytes_read == 0) { + free(buf); + return (SOX_EOF); + } + header_size -= bytes_read; + } + free(buf); + + if (ft->seekable) { + /* Check first four bytes of data to see if it's shorten compressed. */ + char shorten_check[4]; + + if (lsx_readchars(ft, shorten_check, sizeof(shorten_check))) + return SOX_EOF; + lsx_seeki(ft, -(off_t)sizeof(shorten_check), SEEK_CUR); + + if (!memcmp(shorten_check, "ajkg", sizeof(shorten_check))) { + lsx_fail_errno(ft, SOX_EFMT, + "File uses shorten compression, cannot handle this."); + return (SOX_EOF); + } + } + + num_samples = num_samples_ul; + return lsx_check_read_params(ft, channels, (sox_rate_t)rate, encoding, + bytes_per_sample << 3, (uint64_t)num_samples * channels, sox_true); +} + +static int write_header(sox_format_t * ft) +{ + char buf[128]; + uint64_t samples = (ft->olength ? ft->olength : ft->signal.length) / ft->signal.channels; + + lsx_writes(ft, "NIST_1A\n"); + lsx_writes(ft, " 1024\n"); + + if (samples) { + sprintf(buf, "sample_count -i %" PRIu64 "\n", samples); + lsx_writes(ft, buf); + } + + sprintf(buf, "sample_n_bytes -i %d\n", ft->encoding.bits_per_sample >> 3); + lsx_writes(ft, buf); + + sprintf(buf, "channel_count -i %d\n", ft->signal.channels); + lsx_writes(ft, buf); + + if (ft->encoding.bits_per_sample == 8) + sprintf(buf, "sample_byte_format -s1 1\n"); + else + sprintf(buf, "sample_byte_format -s2 %s\n", + ft->encoding.reverse_bytes != MACHINE_IS_BIGENDIAN ? "10" : "01"); + lsx_writes(ft, buf); + + sprintf(buf, "sample_rate -i %u\n", (unsigned) (ft->signal.rate + .5)); + lsx_writes(ft, buf); + + if (ft->encoding.encoding == SOX_ENCODING_ULAW) + lsx_writes(ft, "sample_coding -s4 ulaw\n"); + else + lsx_writes(ft, "sample_coding -s3 pcm\n"); + + lsx_writes(ft, "end_head\n"); + + lsx_padbytes(ft, 1024 - (size_t)lsx_tell(ft)); + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(sphere) +{ + static char const *const names[] = {"sph", "nist", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 8, 16, 24, 32, 0, + SOX_ENCODING_ULAW, 8, 0, + 0 + }; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "SPeech HEader Resources; defined by NIST", names, SOX_FILE_REWIND, + start_read, lsx_rawread, NULL, + write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, NULL, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/splice.c b/app/src/main/cpp/sox/splice.c new file mode 100644 index 0000000..880258b --- /dev/null +++ b/app/src/main/cpp/sox/splice.c @@ -0,0 +1,302 @@ +/* libSoX effect: splice audio Copyright (c) 2008-9 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +static double difference( + const sox_sample_t * a, const sox_sample_t * b, size_t length) +{ + double diff = 0; + size_t i = 0; + + #define _ diff += sqr((double)a[i] - b[i]), ++i; /* Loop optimisation */ + do {_ _ _ _ _ _ _ _} while (i < length); /* N.B. length ≡ 0 (mod 8) */ + #undef _ + return diff; +} + +/* Find where the two segments are most alike over the overlap period. */ +static size_t best_overlap_position(sox_sample_t const * f1, + sox_sample_t const * f2, uint64_t overlap, uint64_t search, size_t channels) +{ + size_t i, best_pos = 0; + double diff, least_diff = difference(f2, f1, (size_t) (channels * overlap)); + + for (i = 1; i < search; ++i) { /* linear search */ + diff = difference(f2 + channels * i, f1, (size_t) (channels * overlap)); + if (diff < least_diff) + least_diff = diff, best_pos = i; + } + return best_pos; +} + + +typedef struct { + enum {Cosine_2, Cosine_4, Triangular} fade_type; + unsigned nsplices; /* Number of splices requested */ + struct { + char * str; /* Command-line argument to parse for this splice */ + uint64_t overlap; /* Number of samples to overlap */ + uint64_t search; /* Number of samples to search */ + uint64_t start; /* Start splicing when in_pos equals this */ + } * splices; + + uint64_t in_pos; /* Number of samples read from the input stream */ + unsigned splices_pos; /* Number of splices completed so far */ + size_t buffer_pos; /* Number of samples through the current splice */ + size_t max_buffer_size; + sox_sample_t * buffer; + unsigned state; +} priv_t; + +static void splice(sox_effect_t * effp, const sox_sample_t * in1, const + sox_sample_t * in2, sox_sample_t * output, uint64_t overlap, size_t channels) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i, j, k = 0; + + if (p->fade_type == Cosine_4) { + double fade_step = M_PI_2 / overlap; + for (i = 0; i < overlap; ++i) { + double fade_in = sin(i * fade_step); + double fade_out = cos(i * fade_step); /* constant RMS level (`power') */ + for (j = 0; j < channels; ++j, ++k) { + double d = in1[k] * fade_out + in2[k] * fade_in; + output[k] = SOX_ROUND_CLIP_COUNT(d, effp->clips); /* Might clip */ + } + } + } + else if (p->fade_type == Cosine_2) { + double fade_step = M_PI / overlap; + for (i = 0; i < overlap; ++i) { + double fade_in = .5 - .5 * cos(i * fade_step); + double fade_out = 1 - fade_in; /* constant peak level (`gain') */ + for (j = 0; j < channels; ++j, ++k) { + double d = in1[k] * fade_out + in2[k] * fade_in; + output[k] = SOX_ROUND_CLIP_COUNT(d, effp->clips); /* Should not clip */ + } + } + } + else /* Triangular */ { + double fade_step = 1. / overlap; + for (i = 0; i < overlap; ++i) { + double fade_in = fade_step * i; + double fade_out = 1 - fade_in; /* constant peak level (`gain') */ + for (j = 0; j < channels; ++j, ++k) { + double d = in1[k] * fade_out + in2[k] * fade_in; + output[k] = SOX_ROUND_CLIP_COUNT(d, effp->clips); /* Should not clip */ + } + } + } +} + +static uint64_t do_splice(sox_effect_t * effp, + sox_sample_t * f, uint64_t overlap, uint64_t search, size_t channels) +{ + uint64_t offset = search? best_overlap_position( + f, f + overlap * channels, overlap, search, channels) : 0; + splice(effp, f, f + (overlap + offset) * channels, + f + (overlap + offset) * channels, overlap, channels); + return overlap + offset; +} + +static int parse(sox_effect_t * effp, char * * argv, sox_rate_t rate) +{ + priv_t * p = (priv_t *)effp->priv; + char const * next; + size_t i, buffer_size; + uint64_t last_seen = 0; + const uint64_t in_length = argv ? 0 : + (effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN); + + p->max_buffer_size = 0; + for (i = 0; i < p->nsplices; ++i) { + if (argv) /* 1st parse only */ + p->splices[i].str = lsx_strdup(argv[i]); + + p->splices[i].overlap = rate * 0.01 + .5; + p->splices[i].search = p->fade_type == Cosine_4? 0 : p->splices[i].overlap; + + next = lsx_parseposition(rate, p->splices[i].str, + argv ? NULL : &p->splices[i].start, last_seen, in_length, '='); + if (next == NULL) break; + last_seen = p->splices[i].start; + + if (*next == ',') { + next = lsx_parsesamples(rate, next + 1, &p->splices[i].overlap, 't'); + if (next == NULL) break; + p->splices[i].overlap *= 2; + if (*next == ',') { + next = lsx_parsesamples(rate, next + 1, &p->splices[i].search, 't'); + if (next == NULL) break; + p->splices[i].search *= 2; + } + } + if (*next != '\0') break; + p->splices[i].overlap = max(p->splices[i].overlap + 4, 16); + p->splices[i].overlap &= ~7; /* Make divisible by 8 for loop optimisation */ + + if (!argv) { + if (i > 0 && p->splices[i].start <= p->splices[i-1].start) break; + if (p->splices[i].start < p->splices[i].overlap) break; + p->splices[i].start -= p->splices[i].overlap; + buffer_size = 2 * p->splices[i].overlap + p->splices[i].search; + p->max_buffer_size = max(p->max_buffer_size, buffer_size); + } + } + if (i < p->nsplices) + return lsx_usage(effp); + return SOX_SUCCESS; +} + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + --argc, ++argv; + if (argc) { + if (!strcmp(*argv, "-t")) p->fade_type = Triangular, --argc, ++argv; + else if (!strcmp(*argv, "-q")) p->fade_type = Cosine_4 , --argc, ++argv; + else if (!strcmp(*argv, "-h")) p->fade_type = Cosine_2 , --argc, ++argv; + } + p->nsplices = argc; + p->splices = lsx_calloc(p->nsplices, sizeof(*p->splices)); + return parse(effp, argv, 1e5); /* No rate yet; parse with dummy */ +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + + parse(effp, 0, effp->in_signal.rate); /* Re-parse now rate is known */ + p->buffer = lsx_calloc(p->max_buffer_size * effp->in_signal.channels, sizeof(*p->buffer)); + p->in_pos = p->buffer_pos = p->splices_pos = 0; + p->state = p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start; + effp->out_signal.length = SOX_UNKNOWN_LEN; /* depends on input data */ + for (i = 0; i < p->nsplices; ++i) + if (p->splices[i].overlap) { + if (p->fade_type == Cosine_4 && effp->in_signal.mult) + *effp->in_signal.mult *= pow(.5, .5); + return SOX_SUCCESS; + } + return SOX_EFF_NULL; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t c, idone = 0, odone = 0; + *isamp /= effp->in_signal.channels; + *osamp /= effp->in_signal.channels; + + while (sox_true) { +copying: + if (p->state == 0) { + for (; idone < *isamp && odone < *osamp; ++idone, ++odone, ++p->in_pos) { + if (p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start) { + p->state = 1; + goto buffering; + } + for (c = 0; c < effp->in_signal.channels; ++c) + *obuf++ = *ibuf++; + } + break; + } + +buffering: + if (p->state == 1) { + size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->in_signal.channels; + for (; idone < *isamp; ++idone, ++p->in_pos) { + if (p->buffer_pos == buffer_size) { + p->buffer_pos = do_splice(effp, p->buffer, + p->splices[p->splices_pos].overlap, + p->splices[p->splices_pos].search, + (size_t)effp->in_signal.channels) * effp->in_signal.channels; + p->state = 2; + goto flushing; + break; + } + for (c = 0; c < effp->in_signal.channels; ++c) + p->buffer[p->buffer_pos++] = *ibuf++; + } + break; + } + +flushing: + if (p->state == 2) { + size_t buffer_size = (2 * p->splices[p->splices_pos].overlap + p->splices[p->splices_pos].search) * effp->in_signal.channels; + for (; odone < *osamp; ++odone) { + if (p->buffer_pos == buffer_size) { + p->buffer_pos = 0; + ++p->splices_pos; + p->state = p->splices_pos != p->nsplices && p->in_pos == p->splices[p->splices_pos].start; + goto copying; + } + for (c = 0; c < effp->in_signal.channels; ++c) + *obuf++ = p->buffer[p->buffer_pos++]; + } + break; + } + } + + *isamp = idone * effp->in_signal.channels; + *osamp = odone * effp->in_signal.channels; + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + size_t isamp = 0; + return flow(effp, 0, obuf, &isamp, osamp); +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + if (p->splices_pos != p->nsplices) + lsx_warn("Input audio too short; splices not made: %u", p->nsplices - p->splices_pos); + free(p->buffer); + return SOX_SUCCESS; +} + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + for (i = 0; i < p->nsplices; ++i) + free(p->splices[i].str); + free(p->splices); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_splice_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "splice", "[-h|-t|-q] {position[,excess[,leeway]]}" + "\n -h Half sine fade (default); constant gain (for correlated audio)" + "\n -t Triangular (linear) fade; constant gain (for correlated audio)" + "\n -q Quarter sine fade; constant power (for correlated audio e.g. x-fade)" + "\n position The length of part 1 (including the excess)" + "\n excess At the end of part 1 & the start of part2 (default 0.005)" + "\n leeway Before part2 (default 0.005; set to 0 for cross-fade)", + SOX_EFF_MCHAN | SOX_EFF_LENGTH, + create, start, flow, drain, stop, lsx_kill, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/stat.c b/app/src/main/cpp/sox/stat.c new file mode 100644 index 0000000..cdea27c --- /dev/null +++ b/app/src/main/cpp/sox/stat.c @@ -0,0 +1,336 @@ +/* libSoX statistics "effect" file. + * + * Compute various statistics on file and print them. + * + * Output is unmodified from input. + * + * July 5, 1991 + * Copyright 1991 Lance Norskog And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" + +#include + +/* Private data for stat effect */ +typedef struct { + double min, max, mid; + double asum; + double sum1, sum2; /* amplitudes */ + double dmin, dmax; + double dsum1, dsum2; /* deltas */ + double scale; /* scale-factor */ + double last; /* previous sample */ + uint64_t read; /* samples processed */ + int volume; + int srms; + int fft; + unsigned long bin[4]; + float *re_in; + float *re_out; + unsigned long fft_size; + unsigned long fft_offset; +} priv_t; + + +/* + * Process options + */ +static int sox_stat_getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * stat = (priv_t *) effp->priv; + + stat->scale = SOX_SAMPLE_MAX; + stat->volume = 0; + stat->srms = 0; + stat->fft = 0; + + --argc, ++argv; + for (; argc > 0; argc--, argv++) { + if (!(strcmp(*argv, "-v"))) + stat->volume = 1; + else if (!(strcmp(*argv, "-s"))) { + if (argc <= 1) { + lsx_fail("-s option: invalid argument"); + return SOX_EOF; + } + argc--, argv++; /* Move to next argument. */ + if (!sscanf(*argv, "%lf", &stat->scale)) { + lsx_fail("-s option: invalid argument"); + return SOX_EOF; + } + } else if (!(strcmp(*argv, "-rms"))) + stat->srms = 1; + else if (!(strcmp(*argv, "-freq"))) + stat->fft = 1; + else if (!(strcmp(*argv, "-d"))) + stat->volume = 2; + else { + lsx_fail("Summary effect: unknown option"); + return SOX_EOF; + } + } + + return SOX_SUCCESS; +} + +/* + * Prepare processing. + */ +static int sox_stat_start(sox_effect_t * effp) +{ + priv_t * stat = (priv_t *) effp->priv; + int i; + + stat->min = stat->max = stat->mid = 0; + stat->asum = 0; + stat->sum1 = stat->sum2 = 0; + + stat->dmin = stat->dmax = 0; + stat->dsum1 = stat->dsum2 = 0; + + stat->last = 0; + stat->read = 0; + + for (i = 0; i < 4; i++) + stat->bin[i] = 0; + + stat->fft_size = 4096; + stat->re_in = stat->re_out = NULL; + + if (stat->fft) { + stat->fft_offset = 0; + stat->re_in = lsx_malloc(sizeof(float) * stat->fft_size); + stat->re_out = lsx_malloc(sizeof(float) * (stat->fft_size / 2 + 1)); + } + + return SOX_SUCCESS; +} + +/* + * Print power spectrum to given stream + */ +static void print_power_spectrum(unsigned samples, double rate, float *re_in, float *re_out) +{ + float ffa = rate / samples; + unsigned i; + + lsx_power_spectrum_f((int)samples, re_in, re_out); + for (i = 0; i < samples / 2; i++) /* FIXME: should be <= samples / 2 */ + fprintf(stderr, "%f %f\n", ffa * i, re_out[i]); +} + +/* + * Processed signed long samples from ibuf to obuf. + * Return number of samples processed. + */ +static int sox_stat_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * stat = (priv_t *) effp->priv; + int done, x, len = min(*isamp, *osamp); + short count = 0; + + if (len) { + if (stat->read == 0) /* 1st sample */ + stat->min = stat->max = stat->mid = stat->last = (*ibuf)/stat->scale; + + if (stat->fft) { + for (x = 0; x < len; x++) { + SOX_SAMPLE_LOCALS; + stat->re_in[stat->fft_offset++] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[x], effp->clips); + + if (stat->fft_offset >= stat->fft_size) { + stat->fft_offset = 0; + print_power_spectrum((unsigned) stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out); + } + + } + } + + for (done = 0; done < len; done++) { + long lsamp = *ibuf++; + double delta, samp = (double)lsamp / stat->scale; + /* work in scaled levels for both sample and delta */ + stat->bin[(lsamp >> 30) + 2]++; + *obuf++ = lsamp; + + if (stat->volume == 2) { + fprintf(stderr,"%08lx ",lsamp); + if (count++ == 5) { + fprintf(stderr,"\n"); + count = 0; + } + } + + /* update min/max */ + if (stat->min > samp) + stat->min = samp; + else if (stat->max < samp) + stat->max = samp; + stat->mid = stat->min / 2 + stat->max / 2; + + stat->sum1 += samp; + stat->sum2 += samp*samp; + stat->asum += fabs(samp); + + delta = fabs(samp - stat->last); + if (delta < stat->dmin) + stat->dmin = delta; + else if (delta > stat->dmax) + stat->dmax = delta; + + stat->dsum1 += delta; + stat->dsum2 += delta*delta; + + stat->last = samp; + } + stat->read += len; + } + + *isamp = *osamp = len; + /* Process all samples */ + + return SOX_SUCCESS; +} + +/* + * Process tail of input samples. + */ +static int sox_stat_drain(sox_effect_t * effp, sox_sample_t *obuf UNUSED, size_t *osamp) +{ + priv_t * stat = (priv_t *) effp->priv; + + /* When we run out of samples, then we need to pad buffer with + * zeros and then run FFT one last time to process any unprocessed + * samples. + */ + if (stat->fft && stat->fft_offset) { + unsigned int x; + + for (x = stat->fft_offset; x < stat->fft_size; x++) + stat->re_in[x] = 0; + + print_power_spectrum((unsigned) stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out); + } + + *osamp = 0; + return SOX_EOF; +} + +/* + * Do anything required when you stop reading samples. + * Don't close input file! + */ +static int sox_stat_stop(sox_effect_t * effp) +{ + priv_t * stat = (priv_t *) effp->priv; + double amp, scale, rms = 0, freq; + double x, ct; + + ct = stat->read; + + if (stat->srms) { /* adjust results to units of rms */ + double f; + rms = sqrt(stat->sum2/ct); + f = 1.0/rms; + stat->max *= f; + stat->min *= f; + stat->mid *= f; + stat->asum *= f; + stat->sum1 *= f; + stat->sum2 *= f*f; + stat->dmax *= f; + stat->dmin *= f; + stat->dsum1 *= f; + stat->dsum2 *= f*f; + stat->scale *= rms; + } + + scale = stat->scale; + + amp = -stat->min; + if (amp < stat->max) + amp = stat->max; + + /* Just print the volume adjustment */ + if (stat->volume == 1 && amp > 0) { + fprintf(stderr, "%.3f\n", SOX_SAMPLE_MAX/(amp*scale)); + return SOX_SUCCESS; + } + if (stat->volume == 2) + fprintf(stderr, "\n\n"); + /* print out the info */ + fprintf(stderr, "Samples read: %12" PRIu64 "\n", stat->read); + fprintf(stderr, "Length (seconds): %12.6f\n", (double)stat->read/effp->in_signal.rate/effp->in_signal.channels); + if (stat->srms) + fprintf(stderr, "Scaled by rms: %12.6f\n", rms); + else + fprintf(stderr, "Scaled by: %12.1f\n", scale); + fprintf(stderr, "Maximum amplitude: %12.6f\n", stat->max); + fprintf(stderr, "Minimum amplitude: %12.6f\n", stat->min); + fprintf(stderr, "Midline amplitude: %12.6f\n", stat->mid); + fprintf(stderr, "Mean norm: %12.6f\n", stat->asum/ct); + fprintf(stderr, "Mean amplitude: %12.6f\n", stat->sum1/ct); + fprintf(stderr, "RMS amplitude: %12.6f\n", sqrt(stat->sum2/ct)); + + fprintf(stderr, "Maximum delta: %12.6f\n", stat->dmax); + fprintf(stderr, "Minimum delta: %12.6f\n", stat->dmin); + fprintf(stderr, "Mean delta: %12.6f\n", stat->dsum1/(ct-1)); + fprintf(stderr, "RMS delta: %12.6f\n", sqrt(stat->dsum2/(ct-1))); + freq = sqrt(stat->dsum2/stat->sum2)*effp->in_signal.rate/(M_PI*2); + fprintf(stderr, "Rough frequency: %12d\n", (int)freq); + + if (amp>0) + fprintf(stderr, "Volume adjustment: %12.3f\n", SOX_SAMPLE_MAX/(amp*scale)); + + if (stat->bin[2] == 0 && stat->bin[3] == 0) + fprintf(stderr, "\nProbably text, not sound\n"); + else { + + x = (float)(stat->bin[0] + stat->bin[3]) / (float)(stat->bin[1] + stat->bin[2]); + + if (x >= 3.0) { /* use opposite encoding */ + if (effp->in_encoding->encoding == SOX_ENCODING_UNSIGNED) + fprintf(stderr,"\nTry: -t raw -e signed-integer -b 8 \n"); + else + fprintf(stderr,"\nTry: -t raw -e unsigned-integer -b 8 \n"); + } else if (x <= 1.0 / 3.0) + ; /* correctly decoded */ + else if (x >= 0.5 && x <= 2.0) { /* use ULAW */ + if (effp->in_encoding->encoding == SOX_ENCODING_ULAW) + fprintf(stderr,"\nTry: -t raw -e unsigned-integer -b 8 \n"); + else + fprintf(stderr,"\nTry: -t raw -e mu-law -b 8 \n"); + } else + fprintf(stderr, "\nCan't guess the type\n"); + } + + /* Release FFT memory */ + free(stat->re_in); + free(stat->re_out); + + return SOX_SUCCESS; + +} + +static sox_effect_handler_t sox_stat_effect = { + "stat", + "[ -s N ] [ -rms ] [-freq] [ -v ] [ -d ]", + SOX_EFF_MCHAN | SOX_EFF_MODIFY, + sox_stat_getopts, + sox_stat_start, + sox_stat_flow, + sox_stat_drain, + sox_stat_stop, + NULL, sizeof(priv_t) +}; + +const sox_effect_handler_t *lsx_stat_effect_fn(void) +{ + return &sox_stat_effect; +} diff --git a/app/src/main/cpp/sox/stats.c b/app/src/main/cpp/sox/stats.c new file mode 100644 index 0000000..259daaa --- /dev/null +++ b/app/src/main/cpp/sox/stats.c @@ -0,0 +1,298 @@ +/* libSoX effect: stats (c) 2009 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include +#include + +typedef struct { + int scale_bits, hex_bits; + double time_constant, scale; + + double last, sigma_x, sigma_x2, avg_sigma_x2, min_sigma_x2, max_sigma_x2; + double min, max, mult, min_run, min_runs, max_run, max_runs; + off_t num_samples, tc_samples, min_count, max_count; + uint32_t mask; +} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *)effp->priv; + int c; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, "+x:b:w:s:", NULL, lsx_getopt_flag_none, 1, &optstate); + + p->time_constant = .05; + p->scale = 1; + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + GETOPT_NUMERIC(optstate, 'x', hex_bits , 2 , 32) + GETOPT_NUMERIC(optstate, 'b', scale_bits , 2 , 32) + GETOPT_NUMERIC(optstate, 'w', time_constant , .01 , 10) + GETOPT_NUMERIC(optstate, 's', scale , -99, 99) + default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); + } + if (p->hex_bits) + p->scale_bits = p->hex_bits; + return optstate.ind != argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + + p->last = 0; + p->mult = exp((-1 / p->time_constant / effp->in_signal.rate)); + p->tc_samples = 5 * p->time_constant * effp->in_signal.rate + .5; + p->sigma_x = p->sigma_x2 = p->avg_sigma_x2 = p->max_sigma_x2 = 0; + p->min = p->min_sigma_x2 = 2; + p->max = -p->min; + p->num_samples = 0; + p->mask = 0; + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * ilen, size_t * olen) +{ + priv_t * p = (priv_t *)effp->priv; + size_t len = *ilen = *olen = min(*ilen, *olen); + memcpy(obuf, ibuf, len * sizeof(*obuf)); + + for (; len--; ++ibuf, ++p->num_samples) { + double d = SOX_SAMPLE_TO_FLOAT_64BIT(*ibuf,); + + if (d < p->min) + p->min = d, p->min_count = 1, p->min_run = 1, p->min_runs = 0; + else if (d == p->min) { + ++p->min_count; + p->min_run = d == p->last? p->min_run + 1 : 1; + } + else if (p->last == p->min) + p->min_runs += sqr(p->min_run); + + if (d > p->max) + p->max = d, p->max_count = 1, p->max_run = 1, p->max_runs = 0; + else if (d == p->max) { + ++p->max_count; + p->max_run = d == p->last? p->max_run + 1 : 1; + } + else if (p->last == p->max) + p->max_runs += sqr(p->max_run); + + p->sigma_x += d; + p->sigma_x2 += sqr(d); + p->avg_sigma_x2 = p->avg_sigma_x2 * p->mult + (1 - p->mult) * sqr(d); + + if (p->num_samples >= p->tc_samples) { + if (p->avg_sigma_x2 > p->max_sigma_x2) + p->max_sigma_x2 = p->avg_sigma_x2; + if (p->avg_sigma_x2 < p->min_sigma_x2) + p->min_sigma_x2 = p->avg_sigma_x2; + } + p->last = d; + p->mask |= *ibuf; + } + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * olen) +{ + priv_t * p = (priv_t *)effp->priv; + + if (p->last == p->min) + p->min_runs += sqr(p->min_run); + if (p->last == p->max) + p->max_runs += sqr(p->max_run); + + (void)obuf, *olen = 0; + return SOX_SUCCESS; +} + +static unsigned bit_depth(uint32_t mask, double min, double max, unsigned * x) +{ + SOX_SAMPLE_LOCALS; + unsigned result = 32, dummy = 0; + + for (; result && !(mask & 1); --result, mask >>= 1); + if (x) + *x = result; + min = -fmax(fabs(min), fabs(max)); + mask = SOX_FLOAT_64BIT_TO_SAMPLE(min, dummy) << 1; + for (; result && (mask & SOX_SAMPLE_MIN); --result, mask <<= 1); + return result; +} + +static void output(priv_t const * p, double x) +{ + if (p->scale_bits) { + unsigned mult = 1 << (p->scale_bits - 1); + int i; + x = floor(x * mult + .5); + i = min(x, mult - 1.); + if (p->hex_bits) + if (x < 0) { + char buf[30]; + sprintf(buf, "%x", -i); + fprintf(stderr, " %*c%s", 9 - (int)strlen(buf), '-', buf); + } + else fprintf(stderr, " %9x", i); + else fprintf(stderr, " %9i", i); + } + else fprintf(stderr, " %9.*f", fabs(p->scale) < 10 ? 6 : 5, p->scale * x); +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + + if (!effp->flow) { + double min_runs = 0, max_count = 0, min = 2, max = -2, max_sigma_x = 0, sigma_x = 0, sigma_x2 = 0, min_sigma_x2 = 2, max_sigma_x2 = 0, avg_peak = 0; + off_t num_samples = 0, min_count = 0, max_runs = 0; + uint32_t mask = 0; + unsigned b1, b2, i, n = effp->flows > 1 ? effp->flows : 0; + + for (i = 0; i < effp->flows; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + min = min(min, q->min); + max = max(max, q->max); + if (q->num_samples < q->tc_samples) + q->min_sigma_x2 = q->max_sigma_x2 = q->sigma_x2 / q->num_samples; + min_sigma_x2 = min(min_sigma_x2, q->min_sigma_x2); + max_sigma_x2 = max(max_sigma_x2, q->max_sigma_x2); + sigma_x += q->sigma_x; + sigma_x2 += q->sigma_x2; + num_samples += q->num_samples; + mask |= q->mask; + if (fabs(q->sigma_x) > fabs(max_sigma_x)) + max_sigma_x = q->sigma_x; + min_count += q->min_count; + min_runs += q->min_runs; + max_count += q->max_count; + max_runs += q->max_runs; + avg_peak += max(-q->min, q->max); + } + avg_peak /= effp->flows; + + if (!num_samples) { + lsx_warn("no audio"); + return SOX_SUCCESS; + } + + if (n == 2) + fprintf(stderr, " Overall Left Right\n"); + else if (n) { + fprintf(stderr, " Overall"); + for (i = 0; i < n; ++i) + fprintf(stderr, " Ch%-3i", i + 1); + fprintf(stderr, "\n"); + } + + fprintf(stderr, "DC offset "); + output(p, max_sigma_x / p->num_samples); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + output(p, q->sigma_x / q->num_samples); + } + + fprintf(stderr, "\nMin level "); + output(p, min); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + output(p, q->min); + } + + fprintf(stderr, "\nMax level "); + output(p, max); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + output(p, q->max); + } + + fprintf(stderr, "\nPk lev dB %10.2f", linear_to_dB(max(-min, max))); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + fprintf(stderr, "%10.2f", linear_to_dB(max(-q->min, q->max))); + } + + fprintf(stderr, "\nRMS lev dB%10.2f", linear_to_dB(sqrt(sigma_x2 / num_samples))); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + fprintf(stderr, "%10.2f", linear_to_dB(sqrt(q->sigma_x2 / q->num_samples))); + } + + fprintf(stderr, "\nRMS Pk dB %10.2f", linear_to_dB(sqrt(max_sigma_x2))); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + fprintf(stderr, "%10.2f", linear_to_dB(sqrt(q->max_sigma_x2))); + } + + fprintf(stderr, "\nRMS Tr dB "); + if (min_sigma_x2 != 1) + fprintf(stderr, "%10.2f", linear_to_dB(sqrt(min_sigma_x2))); + else fprintf(stderr, " -"); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + if (q->min_sigma_x2 != 1) + fprintf(stderr, "%10.2f", linear_to_dB(sqrt(q->min_sigma_x2))); + else fprintf(stderr, " -"); + } + + if (effp->flows > 1) + fprintf(stderr, "\nCrest factor -"); + else fprintf(stderr, "\nCrest factor %7.2f", sigma_x2 ? avg_peak / sqrt(sigma_x2 / num_samples) : 1); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + fprintf(stderr, "%10.2f", q->sigma_x2? max(-q->min, q->max) / sqrt(q->sigma_x2 / q->num_samples) : 1); + } + + fprintf(stderr, "\nFlat factor%9.2f", linear_to_dB((min_runs + max_runs) / (min_count + max_count))); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + fprintf(stderr, " %9.2f", linear_to_dB((q->min_runs + q->max_runs) / (q->min_count + q->max_count))); + } + + fprintf(stderr, "\nPk count %9s", lsx_sigfigs3((min_count + max_count) / effp->flows)); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + fprintf(stderr, " %9s", lsx_sigfigs3((double)(q->min_count + q->max_count))); + } + + b1 = bit_depth(mask, min, max, &b2); + fprintf(stderr, "\nBit-depth %2u/%-2u", b1, b2); + for (i = 0; i < n; ++i) { + priv_t * q = (priv_t *)(effp - effp->flow + i)->priv; + b1 = bit_depth(q->mask, q->min, q->max, &b2); + fprintf(stderr, " %2u/%-2u", b1, b2); + } + + fprintf(stderr, "\nNum samples%9s", lsx_sigfigs3((double)p->num_samples)); + fprintf(stderr, "\nLength s %9.3f", p->num_samples / effp->in_signal.rate); + fprintf(stderr, "\nScale max "); + output(p, 1.); + fprintf(stderr, "\nWindow s %9.3f", p->time_constant); + fprintf(stderr, "\n"); + } + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_stats_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "stats", "[-b bits|-x bits|-s scale] [-w window-time]", SOX_EFF_MODIFY, + getopts, start, flow, drain, stop, NULL, sizeof(priv_t)}; + return &handler; +} diff --git a/app/src/main/cpp/sox/stretch.c b/app/src/main/cpp/sox/stretch.c new file mode 100644 index 0000000..61c4017 --- /dev/null +++ b/app/src/main/cpp/sox/stretch.c @@ -0,0 +1,326 @@ +/* libSoX Basic time stretcher. + * (c) march/april 2000 Fabien COELHO for sox. + * + * cross fade samples so as to go slower or faster. + * + * The filter is based on 6 parameters: + * - stretch factor f + * - window size w + * - input step i + * output step o=f*i + * - steady state of window s, ss = s*w + * + * I decided of the default values of these parameters based + * on some small non extensive tests. maybe better defaults + * can be suggested. + */ +#include "sox_i.h" + +#include +#include +#include + +#define DEFAULT_SLOW_SHIFT_RATIO 0.8 +#define DEFAULT_FAST_SHIFT_RATIO 1.0 + +#define DEFAULT_STRETCH_WINDOW 20.0 /* ms */ + +typedef enum { input_state, output_state } stretch_status_t; + +typedef struct { + /* options + * FIXME: maybe shift could be allowed > 1.0 with factor < 1.0 ??? + */ + double factor; /* strech factor. 1.0 means copy. */ + double window; /* window in ms */ + double shift; /* shift ratio wrt window. <1.0 */ + double fading; /* fading ratio wrt window. <0.5 */ + + /* internal stuff */ + stretch_status_t state; /* automaton status */ + + size_t segment; /* buffer size */ + size_t index; /* next available element */ + sox_sample_t *ibuf; /* input buffer */ + size_t ishift; /* input shift */ + + size_t oindex; /* next evailable element */ + double * obuf; /* output buffer */ + size_t oshift; /* output shift */ + + size_t overlap; /* fading size */ + double * fade_coefs; /* fading, 1.0 -> 0.0 */ + +} priv_t; + +/* + * Process options + */ +static int getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *) effp->priv; + --argc, ++argv; + + /* default options */ + p->factor = 1.0; /* default is no change */ + p->window = DEFAULT_STRETCH_WINDOW; + + if (argc > 0 && !sscanf(argv[0], "%lf", &p->factor)) { + lsx_fail("error while parsing factor"); + return lsx_usage(effp); + } + + if (argc > 1 && !sscanf(argv[1], "%lf", &p->window)) { + lsx_fail("error while parsing window size"); + return lsx_usage(effp); + } + + if (argc > 2) { + switch (argv[2][0]) { + case 'l': + case 'L': + break; + default: + lsx_fail("error while parsing fade type"); + return lsx_usage(effp); + } + } + + /* default shift depends whether we go slower or faster */ + p->shift = (p->factor <= 1.0) ? + DEFAULT_FAST_SHIFT_RATIO: DEFAULT_SLOW_SHIFT_RATIO; + + if (argc > 3 && !sscanf(argv[3], "%lf", &p->shift)) { + lsx_fail("error while parsing shift ratio"); + return lsx_usage(effp); + } + + if (p->shift > 1.0 || p->shift <= 0.0) { + lsx_fail("error with shift ratio value"); + return lsx_usage(effp); + } + + /* default fading stuff... + it makes sense for factor >= 0.5 */ + if (p->factor < 1.0) + p->fading = 1.0 - (p->factor * p->shift); + else + p->fading = 1.0 - p->shift; + if (p->fading > 0.5) + p->fading = 0.5; + + if (argc > 4 && !sscanf(argv[4], "%lf", &p->fading)) { + lsx_fail("error while parsing fading ratio"); + return lsx_usage(effp); + } + + if (p->fading > 0.5 || p->fading < 0.0) { + lsx_fail("error with fading ratio value"); + return lsx_usage(effp); + } + + return SOX_SUCCESS; +} + +/* + * Start processing + */ +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i; + + if (p->factor == 1) + return SOX_EFF_NULL; + + p->state = input_state; + + p->segment = (int)(effp->out_signal.rate * 0.001 * p->window); + /* start in the middle of an input to avoid initial fading... */ + p->index = p->segment / 2; + p->ibuf = lsx_malloc(p->segment * sizeof(sox_sample_t)); + + /* the shift ratio deal with the longest of ishift/oshift + hence ishift<=segment and oshift<=segment. */ + if (p->factor < 1.0) { + p->ishift = p->shift * p->segment; + p->oshift = p->factor * p->ishift; + } else { + p->oshift = p->shift * p->segment; + p->ishift = p->oshift / p->factor; + } + assert(p->ishift <= p->segment); + assert(p->oshift <= p->segment); + + p->oindex = p->index; /* start as synchronized */ + p->obuf = lsx_malloc(p->segment * sizeof(double)); + p->overlap = (int)(p->fading * p->segment); + p->fade_coefs = lsx_malloc(p->overlap * sizeof(double)); + + /* initialize buffers */ + for (i = 0; isegment; i++) + p->ibuf[i] = 0; + + for (i = 0; isegment; i++) + p->obuf[i] = 0.0; + + if (p->overlap>1) { + double slope = 1.0 / (p->overlap - 1); + p->fade_coefs[0] = 1.0; + for (i = 1; i < p->overlap - 1; i++) + p->fade_coefs[i] = slope * (p->overlap - i - 1); + p->fade_coefs[p->overlap - 1] = 0.0; + } else if (p->overlap == 1) + p->fade_coefs[0] = 1.0; + + lsx_debug("start: (factor=%g segment=%g shift=%g overlap=%g)\nstate=%d\n" + "segment=%" PRIuPTR "\nindex=%" PRIuPTR "\n" + "ishift=%" PRIuPTR "\noindex=%" PRIuPTR "\n" + "oshift=%" PRIuPTR "\noverlap=%" PRIuPTR, + p->factor, p->window, p->shift, p->fading, p->state, + p->segment, p->index, p->ishift, p->oindex, p->oshift, p->overlap); + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* TODO: calculate actual length */ + return SOX_SUCCESS; +} + +/* accumulates input ibuf to output obuf with fading fade_coefs */ +static void combine(priv_t * p) +{ + size_t i; + + /* fade in */ + for (i = 0; i < p->overlap; i++) + p->obuf[i] += p->fade_coefs[p->overlap - 1 - i] * p->ibuf[i]; + + /* steady state */ + for (; i < p->segment - p->overlap; i++) + p->obuf[i] += p->ibuf[i]; + + /* fade out */ + for (; isegment; i++) + p->obuf[i] += p->fade_coefs[i - p->segment + p->overlap] * p->ibuf[i]; +} + +/* + * Processes flow. + */ +static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * p = (priv_t *) effp->priv; + size_t iindex = 0, oindex = 0; + size_t i; + + while (iindex<*isamp && oindex<*osamp) { + if (p->state == input_state) { + size_t tocopy = min(*isamp-iindex, + p->segment-p->index); + + memcpy(p->ibuf + p->index, ibuf + iindex, tocopy * sizeof(sox_sample_t)); + + iindex += tocopy; + p->index += tocopy; + + if (p->index == p->segment) { + /* compute */ + combine(p); + + /* shift input */ + for (i = 0; i + p->ishift < p->segment; i++) + p->ibuf[i] = p->ibuf[i+p->ishift]; + + p->index -= p->ishift; + + /* switch to output state */ + p->state = output_state; + } + } + + if (p->state == output_state) { + while (p->oindex < p->oshift && oindex < *osamp) { + float f; + f = p->obuf[p->oindex++]; + SOX_SAMPLE_CLIP_COUNT(f, effp->clips); + obuf[oindex++] = f; + } + + if (p->oindex >= p->oshift && oindex<*osamp) { + p->oindex -= p->oshift; + + /* shift internal output buffer */ + for (i = 0; i + p->oshift < p->segment; i++) + p->obuf[i] = p->obuf[i + p->oshift]; + + /* pad with 0 */ + for (; i < p->segment; i++) + p->obuf[i] = 0.0; + + p->state = input_state; + } + } + } + + *isamp = iindex; + *osamp = oindex; + + return SOX_SUCCESS; +} + + +/* + * Drain buffer at the end + * maybe not correct ? end might be artificially faded? + */ +static int drain(sox_effect_t * effp, sox_sample_t *obuf, size_t *osamp) +{ + priv_t * p = (priv_t *) effp->priv; + size_t i; + size_t oindex = 0; + + if (p->state == input_state) { + for (i=p->index; isegment; i++) + p->ibuf[i] = 0; + + combine(p); + + p->state = output_state; + } + + while (oindex<*osamp && p->oindexindex) { + float f = p->obuf[p->oindex++]; + SOX_SAMPLE_CLIP_COUNT(f, effp->clips); + obuf[oindex++] = f; + } + + *osamp = oindex; + + if (p->oindex == p->index) + return SOX_EOF; + else + return SOX_SUCCESS; +} + + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + + free(p->ibuf); + free(p->obuf); + free(p->fade_coefs); + return SOX_SUCCESS; +} + +const sox_effect_handler_t *lsx_stretch_effect_fn(void) +{ + static const sox_effect_handler_t handler = { + "stretch", + "factor [window fade shift fading]\n" + " (expansion, frame in ms, lin/..., unit<1.0, unit<0.5)\n" + " (defaults: 1.0 20 lin ...)", + SOX_EFF_LENGTH, + getopts, start, flow, drain, stop, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/sunaudio.c b/app/src/main/cpp/sox/sunaudio.c new file mode 100644 index 0000000..c7cad10 --- /dev/null +++ b/app/src/main/cpp/sox/sunaudio.c @@ -0,0 +1,520 @@ +/* libSoX direct to Sun Audio Driver + * + * Added by Chris Bagwell (cbagwell@sprynet.com) on 2/26/96 + * Based on oss handler. + * + * Cleaned up changes of format somewhat in sunstartwrite on 03/31/98 + * + */ + +/* + * Copyright 1997 Chris Bagwell And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Rick Richardson, Lance Norskog And Sundry Contributors are not + * responsible for the consequences of using this software. + */ + +#include "sox_i.h" +#include "g711.h" + +#include +#include +#ifdef HAVE_SUN_AUDIOIO_H + #include +#else + #include +#endif +#include +#if !defined(__NetBSD__) && !defined(__OpenBSD__) +#include +#endif +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +typedef struct +{ + char* pOutput; + unsigned cOutput; + int device; + unsigned sample_shift; +} priv_t; + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int sunstartread(sox_format_t * ft) +{ + char const* szDevname; + priv_t* pPriv = (priv_t*)ft->priv; + + size_t samplesize, encoding; + audio_info_t audio_if; +#ifdef __SVR4 + audio_device_t audio_dev; +#endif + char simple_hw=0; + + lsx_set_signal_defaults(ft); + + if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) { + szDevname = "/dev/audio"; + } else { + szDevname = ft->filename; + } + + pPriv->device = open(szDevname, O_RDONLY); + if (pPriv->device < 0) { + lsx_fail_errno(ft, errno, "open failed for device %s", szDevname); + return SOX_EOF; + } + + if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) ft->encoding.encoding = SOX_ENCODING_ULAW; + +#ifdef __SVR4 + /* Read in old values, change to what we need and then send back */ + if (ioctl(pPriv->device, AUDIO_GETDEV, &audio_dev) < 0) { + lsx_fail_errno(ft,errno,"Unable to get information for device %s", szDevname); + return(SOX_EOF); + } + lsx_report("Hardware detected: %s",audio_dev.name); + if (strcmp("SUNW,am79c30",audio_dev.name) == 0) + { + simple_hw = 1; + } +#endif + + /* If simple hardware detected in force data to ulaw. */ + if (simple_hw) + { + if (ft->encoding.bits_per_sample == 8) + { + if (ft->encoding.encoding != SOX_ENCODING_ULAW && + ft->encoding.encoding != SOX_ENCODING_ALAW) + { + lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); + ft->encoding.encoding = SOX_ENCODING_ULAW; + } + } + else if (ft->encoding.bits_per_sample == 16) + { + lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); + ft->encoding.bits_per_sample = 8; + ft->encoding.encoding = SOX_ENCODING_ULAW; + } + } + + if (ft->encoding.bits_per_sample == 8) { + samplesize = 8; + pPriv->sample_shift = 0; + if (ft->encoding.encoding != SOX_ENCODING_ULAW && + ft->encoding.encoding != SOX_ENCODING_ALAW && + ft->encoding.encoding != SOX_ENCODING_SIGN2) { + lsx_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports ULAW, ALAW, and signed linear for bytes."); + return (SOX_EOF); + } + if ((ft->encoding.encoding == SOX_ENCODING_ULAW || + ft->encoding.encoding == SOX_ENCODING_ALAW) && + ft->signal.channels == 2) + { + lsx_report("Warning: only support mono for ULAW and ALAW data. Forcing to mono."); + ft->signal.channels = 1; + } + } + else if (ft->encoding.bits_per_sample == 16) { + samplesize = 16; + pPriv->sample_shift = 1; + if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { + lsx_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports signed linear for words."); + return(SOX_EOF); + } + } + else { + lsx_fail_errno(ft,SOX_EFMT,"Sun audio driver only supports bytes and words"); + return(SOX_EOF); + } + + if (ft->signal.channels == 0) + ft->signal.channels = 1; + else if (ft->signal.channels > 1) { + lsx_report("Warning: some Sun audio devices can not play stereo"); + lsx_report("at all or sometimes only with signed words. If the"); + lsx_report("sound seems sluggish then this is probably the case."); + lsx_report("Try forcing output to signed words or use the avg"); + lsx_report("filter to reduce the number of channels."); + ft->signal.channels = 2; + } + + /* Read in old values, change to what we need and then send back */ + if (ioctl(pPriv->device, AUDIO_GETINFO, &audio_if) < 0) { + lsx_fail_errno(ft,errno,"Unable to initialize %s", szDevname); + return(SOX_EOF); + } + audio_if.record.precision = samplesize; + audio_if.record.channels = ft->signal.channels; + audio_if.record.sample_rate = ft->signal.rate; + if (ft->encoding.encoding == SOX_ENCODING_ULAW) + encoding = AUDIO_ENCODING_ULAW; + else if (ft->encoding.encoding == SOX_ENCODING_ALAW) + encoding = AUDIO_ENCODING_ALAW; + else + encoding = AUDIO_ENCODING_LINEAR; + audio_if.record.encoding = encoding; + + ioctl(pPriv->device, AUDIO_SETINFO, &audio_if); + if (audio_if.record.precision != samplesize) { + lsx_fail_errno(ft,errno,"Unable to initialize sample size for %s", szDevname); + return(SOX_EOF); + } + if (audio_if.record.channels != ft->signal.channels) { + lsx_fail_errno(ft,errno,"Unable to initialize number of channels for %s", szDevname); + return(SOX_EOF); + } + if (audio_if.record.sample_rate != ft->signal.rate) { + lsx_fail_errno(ft,errno,"Unable to initialize rate for %s", szDevname); + return(SOX_EOF); + } + if (audio_if.record.encoding != encoding) { + lsx_fail_errno(ft,errno,"Unable to initialize encoding for %s", szDevname); + return(SOX_EOF); + } + /* Flush any data in the buffers - its probably in the wrong format */ +#if defined(__NetBSD__) || defined(__OpenBSD__) + ioctl(pPriv->device, AUDIO_FLUSH); +#elif defined __GLIBC__ + ioctl(pPriv->device, (unsigned long int)I_FLUSH, FLUSHR); +#else + ioctl(pPriv->device, I_FLUSH, FLUSHR); +#endif + + pPriv->cOutput = 0; + pPriv->pOutput = NULL; + + return (SOX_SUCCESS); +} + +static int sunstartwrite(sox_format_t * ft) +{ + size_t samplesize, encoding; + audio_info_t audio_if; +#ifdef __SVR4 + audio_device_t audio_dev; +#endif + char simple_hw=0; + char const* szDevname; + priv_t* pPriv = (priv_t*)ft->priv; + + if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) { + szDevname = "/dev/audio"; + } else { + szDevname = ft->filename; + } + + pPriv->device = open(szDevname, O_WRONLY); + if (pPriv->device < 0) { + lsx_fail_errno(ft, errno, "open failed for device: %s", szDevname); + return SOX_EOF; + } + +#ifdef __SVR4 + /* Read in old values, change to what we need and then send back */ + if (ioctl(pPriv->device, AUDIO_GETDEV, &audio_dev) < 0) { + lsx_fail_errno(ft,errno,"Unable to get device information."); + return(SOX_EOF); + } + lsx_report("Hardware detected: %s",audio_dev.name); + if (strcmp("SUNW,am79c30",audio_dev.name) == 0) + { + simple_hw = 1; + } +#endif + + if (simple_hw) + { + if (ft->encoding.bits_per_sample == 8) + { + if (ft->encoding.encoding != SOX_ENCODING_ULAW && + ft->encoding.encoding != SOX_ENCODING_ALAW) + { + lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); + ft->encoding.encoding = SOX_ENCODING_ULAW; + } + } + else if (ft->encoding.bits_per_sample == 16) + { + lsx_report("Warning: Detected simple hardware. Forcing output to ULAW"); + ft->encoding.bits_per_sample = 8; + ft->encoding.encoding = SOX_ENCODING_ULAW; + } + } + + if (ft->encoding.bits_per_sample == 8) + { + samplesize = 8; + pPriv->sample_shift = 0; + if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) + ft->encoding.encoding = SOX_ENCODING_ULAW; + else if (ft->encoding.encoding != SOX_ENCODING_ULAW && + ft->encoding.encoding != SOX_ENCODING_ALAW && + ft->encoding.encoding != SOX_ENCODING_SIGN2) { + lsx_report("Sun Audio driver only supports ULAW, ALAW, and Signed Linear for bytes."); + lsx_report("Forcing to ULAW"); + ft->encoding.encoding = SOX_ENCODING_ULAW; + } + if ((ft->encoding.encoding == SOX_ENCODING_ULAW || + ft->encoding.encoding == SOX_ENCODING_ALAW) && + ft->signal.channels == 2) + { + lsx_report("Warning: only support mono for ULAW and ALAW data. Forcing to mono."); + ft->signal.channels = 1; + } + + } + else if (ft->encoding.bits_per_sample == 16) { + samplesize = 16; + pPriv->sample_shift = 1; + if (ft->encoding.encoding == SOX_ENCODING_UNKNOWN) + ft->encoding.encoding = SOX_ENCODING_SIGN2; + else if (ft->encoding.encoding != SOX_ENCODING_SIGN2) { + lsx_report("Sun Audio driver only supports Signed Linear for words."); + lsx_report("Forcing to Signed Linear"); + ft->encoding.encoding = SOX_ENCODING_SIGN2; + } + } + else { + lsx_report("Sun Audio driver only supports bytes and words"); + ft->encoding.bits_per_sample = 16; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + samplesize = 16; + pPriv->sample_shift = 1; + } + + if (ft->signal.channels > 1) ft->signal.channels = 2; + + /* Read in old values, change to what we need and then send back */ + if (ioctl(pPriv->device, AUDIO_GETINFO, &audio_if) < 0) { + lsx_fail_errno(ft,errno,"Unable to initialize /dev/audio"); + return(SOX_EOF); + } + audio_if.play.precision = samplesize; + audio_if.play.channels = ft->signal.channels; + audio_if.play.sample_rate = ft->signal.rate; + if (ft->encoding.encoding == SOX_ENCODING_ULAW) + encoding = AUDIO_ENCODING_ULAW; + else if (ft->encoding.encoding == SOX_ENCODING_ALAW) + encoding = AUDIO_ENCODING_ALAW; + else + encoding = AUDIO_ENCODING_LINEAR; + audio_if.play.encoding = encoding; + + ioctl(pPriv->device, AUDIO_SETINFO, &audio_if); + if (audio_if.play.precision != samplesize) { + lsx_fail_errno(ft,errno,"Unable to initialize sample size for /dev/audio"); + return(SOX_EOF); + } + if (audio_if.play.channels != ft->signal.channels) { + lsx_fail_errno(ft,errno,"Unable to initialize number of channels for /dev/audio"); + return(SOX_EOF); + } + if (audio_if.play.sample_rate != ft->signal.rate) { + lsx_fail_errno(ft,errno,"Unable to initialize rate for /dev/audio"); + return(SOX_EOF); + } + if (audio_if.play.encoding != encoding) { + lsx_fail_errno(ft,errno,"Unable to initialize encoding for /dev/audio"); + return(SOX_EOF); + } + + pPriv->cOutput = sox_globals.bufsiz >> pPriv->sample_shift; + pPriv->pOutput = lsx_malloc((size_t)pPriv->cOutput << pPriv->sample_shift); + + return (SOX_SUCCESS); +} + +static int sunstop(sox_format_t* ft) +{ + priv_t* pPriv = (priv_t*)ft->priv; + if (pPriv->device >= 0) { + close(pPriv->device); + } + if (pPriv->pOutput) { + free(pPriv->pOutput); + } + return SOX_SUCCESS; +} + +typedef sox_uint16_t sox_uint14_t; +typedef sox_uint16_t sox_uint13_t; +typedef sox_int16_t sox_int14_t; +typedef sox_int16_t sox_int13_t; +#define SOX_ULAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_ulaw2linear16(d),clips) +#define SOX_ALAW_BYTE_TO_SAMPLE(d,clips) SOX_SIGNED_16BIT_TO_SAMPLE(sox_alaw2linear16(d),clips) +#define SOX_SAMPLE_TO_ULAW_BYTE(d,c) sox_14linear2ulaw(SOX_SAMPLE_TO_UNSIGNED(14,d,c) - 0x2000) +#define SOX_SAMPLE_TO_ALAW_BYTE(d,c) sox_13linear2alaw(SOX_SAMPLE_TO_UNSIGNED(13,d,c) - 0x1000) + +static size_t sunread(sox_format_t* ft, sox_sample_t* pOutput, size_t cOutput) +{ + priv_t* pPriv = (priv_t*)ft->priv; + char* pbOutput = (char*)pOutput; + size_t cbOutputLeft = cOutput << pPriv->sample_shift; + size_t i, cRead; + int cbRead; + SOX_SAMPLE_LOCALS; + LSX_USE_VAR(sox_macro_temp_double); + + while (cbOutputLeft) { + cbRead = read(pPriv->device, pbOutput, cbOutputLeft); + if (cbRead <= 0) { + if (cbRead < 0) { + lsx_fail_errno(ft, errno, "Error reading from device"); + return 0; + } + break; + } + cbOutputLeft -= cbRead; + pbOutput += cbRead; + } + + /* Convert in-place (backwards) */ + cRead = cOutput - (cbOutputLeft >> pPriv->sample_shift); + switch (pPriv->sample_shift) + { + case 0: + switch (ft->encoding.encoding) + { + case SOX_ENCODING_SIGN2: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_UNSIGNED_8BIT_TO_SAMPLE( + ((sox_uint8_t*)pOutput)[i - 1], + dummy); + } + break; + case SOX_ENCODING_ULAW: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_ULAW_BYTE_TO_SAMPLE( + ((sox_uint8_t*)pOutput)[i - 1], + dummy); + } + break; + case SOX_ENCODING_ALAW: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_ALAW_BYTE_TO_SAMPLE( + ((sox_uint8_t*)pOutput)[i - 1], + dummy); + } + break; + default: + return 0; + } + break; + case 1: + for (i = cRead; i != 0; i--) { + pOutput[i - 1] = SOX_SIGNED_16BIT_TO_SAMPLE( + ((sox_int16_t*)pOutput)[i - 1], + dummy); + } + break; + } + + return cRead; +} + +static size_t sunwrite( + sox_format_t* ft, + const sox_sample_t* pInput, + size_t cInput) +{ + priv_t* pPriv = (priv_t*)ft->priv; + size_t cInputRemaining = cInput; + unsigned cClips = 0; + SOX_SAMPLE_LOCALS; + + while (cInputRemaining) { + size_t cStride; + size_t i; + size_t cbStride; + int cbWritten; + + cStride = cInputRemaining; + if (cStride > pPriv->cOutput) { + cStride = pPriv->cOutput; + } + + switch (pPriv->sample_shift) + { + case 0: + switch (ft->encoding.encoding) + { + case SOX_ENCODING_SIGN2: + for (i = 0; i != cStride; i++) { + ((sox_uint8_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_UNSIGNED_8BIT(pInput[i], cClips); + } + break; + case SOX_ENCODING_ULAW: + for (i = 0; i != cStride; i++) { + ((sox_uint8_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_ULAW_BYTE(pInput[i], cClips); + } + break; + case SOX_ENCODING_ALAW: + for (i = 0; i != cStride; i++) { + ((sox_uint8_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_ALAW_BYTE(pInput[i], cClips); + } + break; + default: + return 0; + } + break; + case 1: + for (i = 0; i != cStride; i++) { + ((sox_int16_t*)pPriv->pOutput)[i] = + SOX_SAMPLE_TO_SIGNED_16BIT(pInput[i], cClips); + } + break; + } + + cbStride = cStride << pPriv->sample_shift; + i = 0; + do { + cbWritten = write(pPriv->device, &pPriv->pOutput[i], cbStride - i); + i += cbWritten; + if (cbWritten <= 0) { + lsx_fail_errno(ft, errno, "Error writing to device"); + return 0; + } + } while (i != cbStride); + + cInputRemaining -= cStride; + pInput += cStride; + } + + return cInput; +} + +LSX_FORMAT_HANDLER(sunau) +{ + static char const * const names[] = {"sunau", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_SIGN2, 8, 16, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Sun audio device driver", + names, SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + sunstartread, sunread, sunstop, + sunstartwrite, sunwrite, sunstop, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/swap.c b/app/src/main/cpp/sox/swap.c new file mode 100644 index 0000000..d39310c --- /dev/null +++ b/app/src/main/cpp/sox/swap.c @@ -0,0 +1,62 @@ +/* libSoX effect: swap pairs of audio channels + * + * First version written 01/2012 by Ulrich Klauer. + * Replaces an older swap effect originally written by Chris Bagwell + * on March 16, 1999. + * + * Copyright 2012 Chris Bagwell and SoX Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +static int start(sox_effect_t *effp) +{ + return effp->in_signal.channels >= 2 ? SOX_SUCCESS : SOX_EFF_NULL; +} + +static int flow(sox_effect_t *effp, const sox_sample_t *ibuf, + sox_sample_t *obuf, size_t *isamp, size_t *osamp) +{ + size_t len = min(*isamp, *osamp); + size_t channels = effp->in_signal.channels; + len /= channels; + *isamp = *osamp = len * channels; + + while (len--) { + size_t i; + for (i = 0; i + 1 < channels; i += 2) { + *obuf++ = ibuf[1]; + *obuf++ = ibuf[0]; + ibuf += 2; + } + if (channels % 2) + *obuf++ = *ibuf++; + } + + return SOX_SUCCESS; +} + +sox_effect_handler_t const *lsx_swap_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "swap", NULL, + SOX_EFF_MCHAN | SOX_EFF_MODIFY, + NULL, start, flow, NULL, NULL, NULL, + 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/synth.c b/app/src/main/cpp/sox/synth.c new file mode 100644 index 0000000..3eafda7 --- /dev/null +++ b/app/src/main/cpp/sox/synth.c @@ -0,0 +1,677 @@ +/* libSoX synth - Synthesizer Effect. + * + * Copyright (c) 2001-2009 SoX contributors + * Copyright (c) Jan 2001 Carsten Borchardt + * + * This source code is freely redistributable and may be used for any purpose. + * This copyright notice must be maintained. The authors are not responsible + * for the consequences of using this software. + * + * Except for synth types: pluck, tpdf, pinknoise, & brownnoise, and + * sweep types: linear, square & exp, which are: + * + * Copyright (c) 2006-2013 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include +#include + +typedef enum { + synth_sine, + synth_square, + synth_sawtooth, + synth_triangle, + synth_trapezium, + synth_trapetz = synth_trapezium, /* Deprecated name for trapezium */ + synth_exp, + /* Tones above, noises below */ + synth_whitenoise, + synth_noise = synth_whitenoise, /* Just a handy alias */ + synth_tpdfnoise, + synth_pinknoise, + synth_brownnoise, + synth_pluck +} type_t; + +static lsx_enum_item const synth_type[] = { + LSX_ENUM_ITEM(synth_, sine) + LSX_ENUM_ITEM(synth_, square) + LSX_ENUM_ITEM(synth_, sawtooth) + LSX_ENUM_ITEM(synth_, triangle) + LSX_ENUM_ITEM(synth_, trapezium) + LSX_ENUM_ITEM(synth_, trapetz) + LSX_ENUM_ITEM(synth_, exp) + LSX_ENUM_ITEM(synth_, whitenoise) + LSX_ENUM_ITEM(synth_, noise) + LSX_ENUM_ITEM(synth_, tpdfnoise) + LSX_ENUM_ITEM(synth_, pinknoise) + LSX_ENUM_ITEM(synth_, brownnoise) + LSX_ENUM_ITEM(synth_, pluck) + {0, 0} +}; + +typedef enum {synth_create, synth_mix, synth_amod, synth_fmod} combine_t; + +static lsx_enum_item const combine_type[] = { + LSX_ENUM_ITEM(synth_, create) + LSX_ENUM_ITEM(synth_, mix) + LSX_ENUM_ITEM(synth_, amod) + LSX_ENUM_ITEM(synth_, fmod) + {0, 0} +}; + + + +typedef enum {Linear, Square, Exp, Exp_cycle} sweep_t; + +typedef struct { + /* options */ + type_t type; + combine_t combine; + double freq, freq2, mult; + sweep_t sweep; + double offset, phase; + double p1, p2, p3; /* Use depends on synth type */ + + /* internal stuff */ + double lp_last_out, hp_last_out, hp_last_in, ap_last_out, ap_last_in; + double cycle_start_time_s, c0, c1, c2, c3, c4, c5, c6; + + double * buffer; + size_t buffer_len, pos; +} channel_t; + + + +/* Private data for the synthesizer */ +typedef struct { + char * length_str; + channel_t * getopts_channels; + size_t getopts_nchannels; + uint64_t samples_done; + uint64_t samples_to_do; + channel_t * channels; + size_t number_of_channels; + sox_bool no_headroom; + double gain; +} priv_t; + + + +static void create_channel(channel_t * chan) +{ + memset(chan, 0, sizeof(*chan)); + chan->freq2 = chan->freq = 440; + chan->p3 = chan->p2 = chan->p1 = -1; +} + + + +static void set_default_parameters(channel_t * chan) +{ + switch (chan->type) { + case synth_square: /* p1 is pulse width */ + if (chan->p1 < 0) + chan->p1 = 0.5; /* default to 50% duty cycle */ + break; + + case synth_triangle: /* p1 is position of maximum */ + if (chan->p1 < 0) + chan->p1 = 0.5; + break; + + case synth_trapezium: + /* p1 is length of rising slope, + * p2 position where falling slope begins + * p3 position of end of falling slope + */ + if (chan->p1 < 0) { + chan->p1 = 0.1; + chan->p2 = 0.5; + chan->p3 = 0.6; + } else if (chan->p2 < 0) { /* try a symmetric waveform */ + if (chan->p1 <= 0.5) { + chan->p2 = (1 - 2 * chan->p1) / 2; + chan->p3 = chan->p2 + chan->p1; + } else { + /* symetric is not possible, fall back to asymmetrical triangle */ + chan->p2 = chan->p1; + chan->p3 = 1; + } + } else if (chan->p3 < 0) + chan->p3 = 1; /* simple falling slope to the end */ + break; + + case synth_exp: + if (chan->p1 < 0) /* p1 is position of maximum */ + chan->p1 = 0.5; + if (chan->p2 < 0) /* p2 is amplitude */ + chan->p2 = .5; + break; + + case synth_pluck: + if (chan->p1 < 0) + chan->p1 = .4; + if (chan->p2 < 0) + chan->p2 = .2, chan->p3 = .9; + + default: break; + } +} + + + +#undef NUMERIC_PARAMETER +#define NUMERIC_PARAMETER(p, min, max) { \ +char * end_ptr_np; \ +double d_np = strtod(argv[argn], &end_ptr_np); \ +if (end_ptr_np == argv[argn]) \ + break; \ +if (d_np < min || d_np > max || *end_ptr_np != '\0') { \ + lsx_fail("parameter error"); \ + return SOX_EOF; \ +} \ +chan->p = d_np / 100; /* adjust so abs(parameter) <= 1 */\ +if (++argn == argc) \ + break; \ +} + + + +static int getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *) effp->priv; + channel_t master, * chan = &master; + int key = INT_MAX, argn = 0; + char dummy, * end_ptr; + const char *n; + --argc, ++argv; + + if (argc && !strcmp(*argv, "-n")) p->no_headroom = sox_true, ++argv, --argc; + + if (argc > 1 && !strcmp(*argv, "-j") && ( + sscanf(argv[1], "%i %c", &key, &dummy) == 1 || ( + (key = lsx_parse_note(argv[1], &end_ptr)) != INT_MAX && + !*end_ptr))) { + argc -= 2; + argv += 2; + } + + /* Get duration if given (if first arg starts with digit) */ + if (argc && (isdigit((int)argv[argn][0]) || argv[argn][0] == '.')) { + p->length_str = lsx_strdup(argv[argn]); + /* Do a dummy parse of to see if it will fail */ + n = lsx_parsesamples(0., p->length_str, &p->samples_to_do, 't'); + if (!n || *n) + return lsx_usage(effp); + argn++; + } + + create_channel(chan); + if (argn < argc) { /* [off [ph [p1 [p2 [p3]]]]]] */ + do { /* break-able block */ + NUMERIC_PARAMETER(offset,-100, 100) + NUMERIC_PARAMETER(phase , 0, 100) + NUMERIC_PARAMETER(p1, 0, 100) + NUMERIC_PARAMETER(p2, 0, 100) + NUMERIC_PARAMETER(p3, 0, 100) + } while (0); + } + + while (argn < argc) { /* type [combine] [f1[-f2] [off [ph [p1 [p2 [p3]]]]]] */ + lsx_enum_item const * enum_p = lsx_find_enum_text(argv[argn], synth_type, lsx_find_enum_item_case_sensitive); + + if (enum_p == NULL) { + lsx_fail("no type given"); + return SOX_EOF; + } + p->getopts_channels = lsx_realloc(p->getopts_channels, sizeof(*p->getopts_channels) * (p->getopts_nchannels + 1)); + chan = &p->getopts_channels[p->getopts_nchannels++]; + memcpy(chan, &master, sizeof(*chan)); + chan->type = enum_p->value; + if (++argn == argc) + break; + + /* maybe there is a combine-type in next arg */ + enum_p = lsx_find_enum_text(argv[argn], combine_type, lsx_find_enum_item_case_sensitive); + if (enum_p != NULL) { + chan->combine = enum_p->value; + if (++argn == argc) + break; + } + + /* read frequencies if given */ + if (!lsx_find_enum_text(argv[argn], synth_type, lsx_find_enum_item_case_sensitive) && + argv[argn][0] != '-') { + static const char sweeps[] = ":+/-"; + + chan->freq2 = chan->freq = lsx_parse_frequency_k(argv[argn], &end_ptr, key); + if (chan->freq < (chan->type == synth_pluck? 27.5 : 0) || + (chan->type == synth_pluck && chan->freq > 4220)) { + lsx_fail("invalid freq"); + return SOX_EOF; + } + if (*end_ptr && strchr(sweeps, *end_ptr)) { /* freq2 given? */ + if (chan->type >= synth_noise) { + lsx_fail("can't sweep this type"); + return SOX_EOF; + } + chan->sweep = strchr(sweeps, *end_ptr) - sweeps; + chan->freq2 = lsx_parse_frequency_k(end_ptr + 1, &end_ptr, key); + if (chan->freq2 < 0) { + lsx_fail("invalid freq2"); + return SOX_EOF; + } + if (p->length_str == NULL) { + lsx_fail("duration must be given when using freq2"); + return SOX_EOF; + } + } + if (*end_ptr) { + lsx_fail("frequency: invalid trailing character"); + return SOX_EOF; + } + if (chan->sweep >= Exp && chan->freq * chan->freq2 == 0) { + lsx_fail("invalid frequency for exponential sweep"); + return SOX_EOF; + } + + if (++argn == argc) + break; + } + + /* read rest of parameters */ + do { /* break-able block */ + NUMERIC_PARAMETER(offset,-100, 100) + NUMERIC_PARAMETER(phase , 0, 100) + NUMERIC_PARAMETER(p1, 0, 100) + NUMERIC_PARAMETER(p2, 0, 100) + NUMERIC_PARAMETER(p3, 0, 100) + } while (0); + } + + /* If no channel parameters were given, create one default channel: */ + if (!p->getopts_nchannels) { + p->getopts_channels = lsx_malloc(sizeof(*p->getopts_channels)); + memcpy(&p->getopts_channels[0], &master, sizeof(channel_t)); + ++p->getopts_nchannels; + } + + if (!effp->in_signal.channels) + effp->in_signal.channels = p->getopts_nchannels; + + return SOX_SUCCESS; +} + + + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i, j, k; + + p->samples_done = 0; + + if (p->length_str) { + if (lsx_parsesamples(effp->in_signal.rate, p->length_str, &p->samples_to_do, 't') == NULL) + return lsx_usage(effp); + } else + p->samples_to_do = effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : 0; + + p->number_of_channels = effp->in_signal.channels; + p->channels = lsx_calloc(p->number_of_channels, sizeof(*p->channels)); + for (i = 0; i < p->number_of_channels; ++i) { + channel_t * chan = &p->channels[i]; + *chan = p->getopts_channels[i % p->getopts_nchannels]; + set_default_parameters(chan); + if (chan->type == synth_pluck) { + double min, max, frac, p2; + + /* Low pass: */ + double const decay_rate = -2; /* dB / s */ + double const decay_f = min(912, 266 + 106 * log(chan->freq)); + double d = sqr(dB_to_linear(decay_rate / chan->freq)); + d = (d * cos(2 * M_PI * decay_f / effp->in_signal.rate) - 1) / (d - 1); + chan->c0 = d - sqrt(d * d - 1); + chan->c1 = 1 - chan->c0; + + /* Single-pole low pass is very rate-dependent: */ + if (effp->in_signal.rate < 44100 || effp->in_signal.rate > 48000) { + lsx_fail( + "sample rate for pluck must be 44100-48000; use `rate' to resample"); + return SOX_EOF; + } + /* Decay: */ + chan->c1 *= exp(-2e4/ (.05+chan->p1)/ chan->freq/ effp->in_signal.rate); + + /* High pass (DC-block): */ + chan->c2 = exp(-2 * M_PI * 10 / effp->in_signal.rate); + chan->c3 = (1 + chan->c2) * .5; + + /* All pass (for fractional delay): */ + d = chan->c0 / (chan->c0 + chan->c1); + chan->buffer_len = effp->in_signal.rate / chan->freq - d; + frac = effp->in_signal.rate / chan->freq - d - chan->buffer_len; + chan->c4 = (1 - frac) / (1 + frac); + chan->pos = 0; + + /* Exitation: */ + chan->buffer = lsx_calloc(chan->buffer_len, sizeof(*chan->buffer)); + for (k = 0, p2 = chan->p2; k < 2 && p2 >= 0; ++k, p2 = chan->p3) { + double d1 = 0, d2, colour = pow(2., 4 * (p2 - 1)); + int32_t r = p2 * 100 + .5; + for (j = 0; j < chan->buffer_len; ++j) { + do d2 = d1 + (chan->phase? DRANQD1:dranqd1(r)) * colour; + while (fabs(d2) > 1); + chan->buffer[j] += d2 * (1 - .3 * k); + d1 = d2 * (colour != 1); +#ifdef TEST_PLUCK + chan->buffer[j] = sin(2 * M_PI * j / chan->buffer_len); +#endif + } + } + + /* In-delay filter graduation: */ + for (j = 0, min = max = 0; j < chan->buffer_len; ++j) { + double d2, t = (double)j / chan->buffer_len; + chan->lp_last_out = d2 = + chan->buffer[j] * chan->c1 + chan->lp_last_out * chan->c0; + + chan->ap_last_out = + d2 * chan->c4 + chan->ap_last_in - chan->ap_last_out * chan->c4; + chan->ap_last_in = d2; + + chan->buffer[j] = chan->buffer[j] * (1 - t) + chan->ap_last_out * t; + min = min(min, chan->buffer[j]); + max = max(max, chan->buffer[j]); + } + + /* Normalise: */ + for (j = 0, d = 0; j < chan->buffer_len; ++j) { + chan->buffer[j] = (2 * chan->buffer[j] - max - min) / (max - min); + d += sqr(chan->buffer[j]); + } + lsx_debug("rms=%f c0=%f c1=%f df=%f d3f=%f c2=%f c3=%f c4=%f frac=%f", + 10 * log(d / chan->buffer_len), chan->c0, chan->c1, decay_f, + log(chan->c0)/ -2 / M_PI * effp->in_signal.rate, + chan->c2, chan->c3, chan->c4, frac); + } + switch (chan->sweep) { + case Linear: chan->mult = p->samples_to_do? + (chan->freq2 - chan->freq) / p->samples_to_do / 2 : 0; + break; + case Square: chan->mult = p->samples_to_do? + sqrt(fabs(chan->freq2 - chan->freq)) / p->samples_to_do / sqrt(3.) : 0; + if (chan->freq > chan->freq2) + chan->mult = -chan->mult; + break; + case Exp: chan->mult = p->samples_to_do? + log(chan->freq2 / chan->freq) / p->samples_to_do * effp->in_signal.rate : 1; + chan->freq /= chan->mult; + break; + case Exp_cycle: chan->mult = p->samples_to_do? + (log(chan->freq2) - log(chan->freq)) / p->samples_to_do : 1; + break; + } + lsx_debug("type=%s, combine=%s, samples_to_do=%" PRIu64 ", f1=%g, f2=%g, " + "offset=%g, phase=%g, p1=%g, p2=%g, p3=%g mult=%g", + lsx_find_enum_value(chan->type, synth_type)->text, + lsx_find_enum_value(chan->combine, combine_type)->text, + p->samples_to_do, chan->freq, chan->freq2, + chan->offset, chan->phase, chan->p1, chan->p2, chan->p3, chan->mult); + } + p->gain = 1; + effp->out_signal.mult = p->no_headroom? NULL : &p->gain; + effp->out_signal.length = p->samples_to_do ? + p->samples_to_do * effp->out_signal.channels : SOX_UNKNOWN_LEN; + return SOX_SUCCESS; +} + +#define elapsed_time_s p->samples_done / effp->in_signal.rate + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, sox_sample_t * obuf, + size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *) effp->priv; + unsigned len = min(*isamp, *osamp) / effp->in_signal.channels; + unsigned c, done; + int result = SOX_SUCCESS; + + for (done = 0; done < len && result == SOX_SUCCESS; ++done) { + for (c = 0; c < effp->in_signal.channels; c++) { + sox_sample_t synth_input = *ibuf++; + channel_t * chan = &p->channels[c]; + double synth_out; /* [-1, 1] */ + + if (chan->type < synth_noise) { /* Need to calculate phase: */ + double phase; /* [0, 1) */ + switch (chan->sweep) { + case Linear: + phase = (chan->freq + p->samples_done * chan->mult) * + elapsed_time_s; + break; + case Square: + phase = (chan->freq + sign(chan->mult) * + sqr(p->samples_done * chan->mult)) * elapsed_time_s; + break; + case Exp: + phase = chan->freq * exp(chan->mult * elapsed_time_s); + break; + case Exp_cycle: default: { + double f = chan->freq * exp(p->samples_done * chan->mult); + double cycle_elapsed_time_s = elapsed_time_s - chan->cycle_start_time_s; + if (f * cycle_elapsed_time_s >= 1) { /* move to next cycle */ + chan->cycle_start_time_s += 1 / f; + cycle_elapsed_time_s = elapsed_time_s - chan->cycle_start_time_s; + } + phase = f * cycle_elapsed_time_s; + break; + } + } + phase = fmod(phase + chan->phase, 1.0); + + switch (chan->type) { + case synth_sine: + synth_out = sin(2 * M_PI * phase); + break; + + case synth_square: + /* |_______ | +1 + * | | | + * |_______|__________| 0 + * | | | + * | |__________| -1 + * | | + * 0 p1 1 + */ + synth_out = -1 + 2 * (phase < chan->p1); + break; + + case synth_sawtooth: + /* | __| +1 + * | __/ | + * |_______/_____| 0 + * | __/ | + * |_/ | -1 + * | | + * 0 1 + */ + synth_out = -1 + 2 * phase; + break; + + case synth_triangle: + /* | . | +1 + * | / \ | + * |__/___\__| 0 + * | / \ | + * |/ \| -1 + * | | + * 0 p1 1 + */ + + if (phase < chan->p1) + synth_out = -1 + 2 * phase / chan->p1; /* In rising part of period */ + else + synth_out = 1 - 2 * (phase - chan->p1) / (1 - chan->p1); /* In falling part */ + break; + + case synth_trapezium: + /* | ______ |+1 + * | / \ | + * |__/________\___________| 0 + * | / \ | + * |/ \_________|-1 + * | | + * 0 p1 p2 p3 1 + */ + if (phase < chan->p1) /* In rising part of period */ + synth_out = -1 + 2 * phase / chan->p1; + else if (phase < chan->p2) /* In high part of period */ + synth_out = 1; + else if (phase < chan->p3) /* In falling part */ + synth_out = 1 - 2 * (phase - chan->p2) / (chan->p3 - chan->p2); + else /* In low part of period */ + synth_out = -1; + break; + + case synth_exp: + /* | | | +1 + * | | | | + * | _| |_ | 0 + * | __- -__ | + * |____--- ---____ | f(p2) + * | | + * 0 p1 1 + */ + synth_out = dB_to_linear(chan->p2 * -200); /* 0 .. 1 */ + if (phase < chan->p1) + synth_out = synth_out * exp(phase * log(1 / synth_out) / chan->p1); + else + synth_out = synth_out * exp((1 - phase) * log(1 / synth_out) / (1 - chan->p1)); + synth_out = synth_out * 2 - 1; /* map 0 .. 1 to -1 .. +1 */ + break; + + default: synth_out = 0; + } + } else switch (chan->type) { + case synth_whitenoise: + synth_out = DRANQD1; + break; + + case synth_tpdfnoise: + synth_out = .5 * (DRANQD1 + DRANQD1); + break; + + case synth_pinknoise: { /* "Paul Kellet's refined method" */ +#define _ .125 / (65536. * 32768.) + double d = RANQD1; + chan->c0 = .99886 * chan->c0 + d * (.0555179*_); + chan->c1 = .99332 * chan->c1 + d * (.0750759*_); + chan->c2 = .96900 * chan->c2 + d * (.1538520*_); + chan->c3 = .86650 * chan->c3 + d * (.3104856*_); + chan->c4 = .55000 * chan->c4 + d * (.5329522*_); + chan->c5 = -.7616 * chan->c5 - d * (.0168980*_); + synth_out = chan->c0 + chan->c1 + chan->c2 + chan->c3 + + chan->c4 + chan->c5 + chan->c6 + d * (.5362*_); + chan->c6 = d * (.115926*_); + break; +#undef _ + } + + case synth_brownnoise: + do synth_out = chan->lp_last_out + DRANQD1 * (1. / 16); + while (fabs(synth_out) > 1); + chan->lp_last_out = synth_out; + break; + + case synth_pluck: { + double d = chan->buffer[chan->pos]; + + chan->hp_last_out = + (d - chan->hp_last_in) * chan->c3 + chan->hp_last_out * chan->c2; + chan->hp_last_in = d; + + synth_out = range_limit(chan->hp_last_out, -1, 1); + + chan->lp_last_out = d = d * chan->c1 + chan->lp_last_out * chan->c0; + + chan->ap_last_out = chan->buffer[chan->pos] = + (d - chan->ap_last_out) * chan->c4 + chan->ap_last_in; + chan->ap_last_in = d; + + chan->pos = chan->pos + 1 == chan->buffer_len? 0 : chan->pos + 1; + break; + } + + default: synth_out = 0; + } + + /* Add offset, but prevent clipping: */ + synth_out = synth_out * (1 - fabs(chan->offset)) + chan->offset; + + switch (chan->combine) { + case synth_create: synth_out *= SOX_SAMPLE_MAX; break; + case synth_mix : synth_out = (synth_out * SOX_SAMPLE_MAX + synth_input) * .5; break; + case synth_amod : synth_out = (synth_out + 1) * synth_input * .5; break; + case synth_fmod : synth_out *= synth_input; break; + } + *obuf++ = synth_out < 0? synth_out * p->gain - .5 : synth_out * p->gain + .5; + } + if (++p->samples_done == p->samples_to_do) + result = SOX_EOF; + } + *isamp = *osamp = done * effp->in_signal.channels; + return result; +} + + + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + size_t i; + + for (i = 0; i < p->number_of_channels; ++i) + free(p->channels[i].buffer); + free(p->channels); + return SOX_SUCCESS; +} + + + +static int lsx_kill(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + free(p->getopts_channels); + free(p->length_str); + return SOX_SUCCESS; +} + + + +const sox_effect_handler_t *lsx_synth_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "synth", "[-j KEY] [-n] [length [offset [phase [p1 [p2 [p3]]]]]]] {type [combine] [[%]freq[k][:|+|/|-[%]freq2[k]] [offset [phase [p1 [p2 [p3]]]]]]}", + SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_GAIN, + getopts, start, flow, 0, stop, lsx_kill, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/tempo.c b/app/src/main/cpp/sox/tempo.c new file mode 100644 index 0000000..29f1c14 --- /dev/null +++ b/app/src/main/cpp/sox/tempo.c @@ -0,0 +1,360 @@ +/* libSoX effect: change tempo (and duration) or pitch (maintain duration) + * Copyright (c) 2007,8 robs@users.sourceforge.net + * Based on ideas from Olli Parviainen's SoundTouch Library. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "fifo.h" +#include + +typedef struct { + /* Configuration parameters: */ + size_t channels; + sox_bool quick_search; /* Whether to quick search or linear search */ + double factor; /* 1 for no change, < 1 for slower, > 1 for faster. */ + size_t search; /* Wide samples to search for best overlap position */ + size_t segment; /* Processing segment length in wide samples */ + size_t overlap; /* In wide samples */ + + size_t process_size; /* # input wide samples needed to process 1 segment */ + + /* Buffers: */ + fifo_t input_fifo; + float * overlap_buf; + fifo_t output_fifo; + + /* Counters: */ + uint64_t samples_in; + uint64_t samples_out; + uint64_t segments_total; + uint64_t skip_total; +} tempo_t; + +/* Waveform Similarity by least squares; works across multi-channels */ +static float difference(const float * a, const float * b, size_t length) +{ + float diff = 0; + size_t i = 0; + + #define _ diff += sqr(a[i] - b[i]), ++i; /* Loop optimisation */ + do {_ _ _ _ _ _ _ _} while (i < length); /* N.B. length ≡ 0 (mod 8) */ + #undef _ + return diff; +} + +/* Find where the two segments are most alike over the overlap period. */ +static size_t tempo_best_overlap_position(tempo_t * t, float const * new_win) +{ + float * f = t->overlap_buf; + size_t j, best_pos, prev_best_pos = (t->search + 1) >> 1, step = 64; + size_t i = best_pos = t->quick_search? prev_best_pos : 0; + float diff, least_diff = difference(new_win + t->channels * i, f, t->channels * t->overlap); + int k = 0; + + if (t->quick_search) do { /* hierarchical search */ + for (k = -1; k <= 1; k += 2) for (j = 1; j < 4 || step == 64; ++j) { + i = prev_best_pos + k * j * step; + if ((int)i < 0 || i >= t->search) + break; + diff = difference(new_win + t->channels * i, f, t->channels * t->overlap); + if (diff < least_diff) + least_diff = diff, best_pos = i; + } + prev_best_pos = best_pos; + } while (step >>= 2); + else for (i = 1; i < t->search; i++) { /* linear search */ + diff = difference(new_win + t->channels * i, f, t->channels * t->overlap); + if (diff < least_diff) + least_diff = diff, best_pos = i; + } + return best_pos; +} + +static void tempo_overlap( + tempo_t * t, const float * in1, const float * in2, float * output) +{ + size_t i, j, k = 0; + float fade_step = 1.0f / (float) t->overlap; + + for (i = 0; i < t->overlap; ++i) { + float fade_in = fade_step * (float) i; + float fade_out = 1.0f - fade_in; + for (j = 0; j < t->channels; ++j, ++k) + output[k] = in1[k] * fade_out + in2[k] * fade_in; + } +} + +static void tempo_process(tempo_t * t) +{ + while (fifo_occupancy(&t->input_fifo) >= t->process_size) { + size_t skip, offset; + + /* Copy or overlap the first bit to the output */ + if (!t->segments_total) { + offset = t->search / 2; + fifo_write(&t->output_fifo, t->overlap, (float *) fifo_read_ptr(&t->input_fifo) + t->channels * offset); + } else { + offset = tempo_best_overlap_position(t, fifo_read_ptr(&t->input_fifo)); + tempo_overlap(t, t->overlap_buf, + (float *) fifo_read_ptr(&t->input_fifo) + t->channels * offset, + fifo_write(&t->output_fifo, t->overlap, NULL)); + } + /* Copy the middle bit to the output */ + fifo_write(&t->output_fifo, t->segment - 2 * t->overlap, + (float *) fifo_read_ptr(&t->input_fifo) + + t->channels * (offset + t->overlap)); + + /* Copy the end bit to overlap_buf ready to be mixed with + * the beginning of the next segment. */ + memcpy(t->overlap_buf, + (float *) fifo_read_ptr(&t->input_fifo) + + t->channels * (offset + t->segment - t->overlap), + t->channels * t->overlap * sizeof(*(t->overlap_buf))); + + /* Advance through the input stream */ + skip = t->factor * (++t->segments_total * (t->segment - t->overlap)) + 0.5; + t->skip_total += skip -= t->skip_total; + fifo_read(&t->input_fifo, skip, NULL); + } +} + +static float * tempo_input(tempo_t * t, float const * samples, size_t n) +{ + t->samples_in += n; + return fifo_write(&t->input_fifo, n, samples); +} + +static float const * tempo_output(tempo_t * t, float * samples, size_t * n) +{ + t->samples_out += *n = min(*n, fifo_occupancy(&t->output_fifo)); + return fifo_read(&t->output_fifo, *n, samples); +} + +/* Flush samples remaining in overlap_buf & input_fifo to the output. */ +static void tempo_flush(tempo_t * t) +{ + uint64_t samples_out = t->samples_in / t->factor + .5; + size_t remaining = samples_out > t->samples_out ? + (size_t)(samples_out - t->samples_out) : 0; + float * buff = lsx_calloc(128 * t->channels, sizeof(*buff)); + + if (remaining > 0) { + while (fifo_occupancy(&t->output_fifo) < remaining) { + tempo_input(t, buff, (size_t) 128); + tempo_process(t); + } + fifo_trim_to(&t->output_fifo, remaining); + t->samples_in = 0; + } + free(buff); +} + +static void tempo_setup(tempo_t * t, + double sample_rate, sox_bool quick_search, double factor, + double segment_ms, double search_ms, double overlap_ms) +{ + size_t max_skip; + t->quick_search = quick_search; + t->factor = factor; + t->segment = sample_rate * segment_ms / 1000 + .5; + t->search = sample_rate * search_ms / 1000 + .5; + t->overlap = max(sample_rate * overlap_ms / 1000 + 4.5, 16); + t->overlap &= ~7; /* Make divisible by 8 for loop optimisation */ + if (t->overlap * 2 > t->segment) + t->overlap -= 8; + t->overlap_buf = lsx_malloc(t->overlap * t->channels * sizeof(*t->overlap_buf)); + max_skip = ceil(factor * (t->segment - t->overlap)); + t->process_size = max(max_skip + t->overlap, t->segment) + t->search; + memset(fifo_reserve(&t->input_fifo, t->search / 2), 0, (t->search / 2) * t->channels * sizeof(float)); +} + +static void tempo_delete(tempo_t * t) +{ + free(t->overlap_buf); + fifo_delete(&t->output_fifo); + fifo_delete(&t->input_fifo); + free(t); +} + +static tempo_t * tempo_create(size_t channels) +{ + tempo_t * t = lsx_calloc(1, sizeof(*t)); + t->channels = channels; + fifo_create(&t->input_fifo, t->channels * sizeof(float)); + fifo_create(&t->output_fifo, t->channels * sizeof(float)); + return t; +} + +/*------------------------------- SoX Wrapper --------------------------------*/ + +typedef struct { + tempo_t * tempo; + sox_bool quick_search; + double factor, segment_ms, search_ms, overlap_ms; +} priv_t; + +static int getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * p = (priv_t *)effp->priv; + enum {Default, Music, Speech, Linear} profile = Default; + static const double segments_ms [] = { 82,82, 35 , 20}; + static const double segments_pow[] = { 0, 1, .33 , 1}; + static const double overlaps_div[] = {6.833, 7, 2.5 , 2}; + static const double searches_div[] = {5.587, 6, 2.14, 2}; + int c; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, "+qmls", NULL, lsx_getopt_flag_none, 1, &optstate); + + p->segment_ms = p->search_ms = p->overlap_ms = HUGE_VAL; + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + case 'q': p->quick_search = sox_true; break; + case 'm': profile = Music; break; + case 's': profile = Speech; break; + case 'l': profile = Linear; p->search_ms = 0; break; + default: lsx_fail("unknown option `-%c'", optstate.opt); return lsx_usage(effp); + } + argc -= optstate.ind, argv += optstate.ind; + do { /* break-able block */ + NUMERIC_PARAMETER(factor ,0.1 , 100 ) + NUMERIC_PARAMETER(segment_ms , 10 , 120) + NUMERIC_PARAMETER(search_ms , 0 , 30 ) + NUMERIC_PARAMETER(overlap_ms , 0 , 30 ) + } while (0); + + if (p->segment_ms == HUGE_VAL) + p->segment_ms = max(10, segments_ms[profile] / max(pow(p->factor, segments_pow[profile]), 1)); + if (p->overlap_ms == HUGE_VAL) + p->overlap_ms = p->segment_ms / overlaps_div[profile]; + if (p->search_ms == HUGE_VAL) + p->search_ms = p->segment_ms / searches_div[profile]; + + p->overlap_ms = min(p->overlap_ms, p->segment_ms / 2); + lsx_report("quick_search=%u factor=%g segment=%g search=%g overlap=%g", + p->quick_search, p->factor, p->segment_ms, p->search_ms, p->overlap_ms); + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + + if (p->factor == 1) + return SOX_EFF_NULL; + + p->tempo = tempo_create((size_t)effp->in_signal.channels); + tempo_setup(p->tempo, effp->in_signal.rate, p->quick_search, p->factor, + p->segment_ms, p->search_ms, p->overlap_ms); + + effp->out_signal.length = SOX_UNKNOWN_LEN; + if (effp->in_signal.length != SOX_UNKNOWN_LEN) { + uint64_t in_length = effp->in_signal.length / effp->in_signal.channels; + uint64_t out_length = in_length / p->factor + .5; + effp->out_signal.length = out_length * effp->in_signal.channels; + } + + return SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t i, odone = *osamp /= effp->in_signal.channels; + float const * s = tempo_output(p->tempo, NULL, &odone); + SOX_SAMPLE_LOCALS; + + for (i = 0; i < odone * effp->in_signal.channels; ++i) + *obuf++ = SOX_FLOAT_32BIT_TO_SAMPLE(*s++, effp->clips); + + if (*isamp && odone < *osamp) { + float * t = tempo_input(p->tempo, NULL, *isamp / effp->in_signal.channels); + for (i = *isamp; i; --i) + *t++ = SOX_SAMPLE_TO_FLOAT_32BIT(*ibuf++, effp->clips); + tempo_process(p->tempo); + } + else *isamp = 0; + + *osamp = odone * effp->in_signal.channels; + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + static size_t isamp = 0; + tempo_flush(p->tempo); + return flow(effp, 0, obuf, &isamp, osamp); +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + tempo_delete(p->tempo); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_tempo_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "tempo", "[-q] [-m | -s | -l] factor [segment-ms [search-ms [overlap-ms]]]", + SOX_EFF_MCHAN | SOX_EFF_LENGTH, + getopts, start, flow, drain, stop, NULL, sizeof(priv_t) + }; + return &handler; +} + +/*---------------------------------- pitch -----------------------------------*/ + +static int pitch_getopts(sox_effect_t * effp, int argc, char **argv) +{ + double d; + char dummy, arg[100], **argv2 = lsx_malloc(argc * sizeof(*argv2)); + int result, pos = (argc > 1 && !strcmp(argv[1], "-q"))? 2 : 1; + + if (argc <= pos || sscanf(argv[pos], "%lf %c", &d, &dummy) != 1) + return lsx_usage(effp); + + d = pow(2., d / 1200); /* cents --> factor */ + sprintf(arg, "%g", 1 / d); + memcpy(argv2, argv, argc * sizeof(*argv2)); + argv2[pos] = arg; + result = getopts(effp, argc, argv2); + free(argv2); + return result; +} + +static int pitch_start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + int result = start(effp); + + effp->out_signal.rate = effp->in_signal.rate / p->factor; + return result; +} + +sox_effect_handler_t const * lsx_pitch_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_tempo_effect_fn(); + handler.name = "pitch"; + handler.usage = "[-q] shift-in-cents [segment-ms [search-ms [overlap-ms]]]", + handler.getopts = pitch_getopts; + handler.start = pitch_start; + handler.flags &= ~SOX_EFF_LENGTH; + handler.flags |= SOX_EFF_RATE; + return &handler; +} diff --git a/app/src/main/cpp/sox/tremolo.c b/app/src/main/cpp/sox/tremolo.c new file mode 100644 index 0000000..ed827ad --- /dev/null +++ b/app/src/main/cpp/sox/tremolo.c @@ -0,0 +1,47 @@ +/* libSoX effect: tremolo (c) 2007 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +static int getopts(sox_effect_t * effp, int argc, char * * argv) +{ + double speed, depth = 40; + char dummy; /* To check for extraneous chars. */ + char offset[100]; + char * args[] = {0, "sine", "fmod", 0, 0, "25"}; + + if (argc < 2 || argc > 3 || + sscanf(argv[1], "%lf %c", &speed, &dummy) != 1 || speed < 0 || + (argc > 2 && sscanf(argv[2], "%lf %c", &depth, &dummy) != 1) || + depth <= 0 || depth > 100) + return lsx_usage(effp); + args[0] = argv[0]; + args[3] = argv[1]; + sprintf(offset, "%g", 100 - depth / 2); + args[4] = offset; + return lsx_synth_effect_fn()->getopts(effp, (int)array_length(args), args); +} + +sox_effect_handler_t const * lsx_tremolo_effect_fn(void) +{ + static sox_effect_handler_t handler; + handler = *lsx_synth_effect_fn(); + handler.name = "tremolo"; + handler.usage = "speed_Hz [depth_percent]"; + handler.getopts = getopts; + return &handler; +} diff --git a/app/src/main/cpp/sox/trim.c b/app/src/main/cpp/sox/trim.c new file mode 100644 index 0000000..5c28a36 --- /dev/null +++ b/app/src/main/cpp/sox/trim.c @@ -0,0 +1,216 @@ +/* libSoX effect: trim - cut portions out of the audio + * + * First version written 01/2012 by Ulrich Klauer. + * Replaces an older trim effect originally written by Curt Zirzow in 2000. + * + * Copyright 2012 Chris Bagwell and SoX Contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct { + /* parameters */ + unsigned int num_pos; + struct { + uint64_t sample; /* NB: wide samples */ + char *argstr; + } *pos; + /* state */ + unsigned int current_pos; + uint64_t samples_read; /* NB: wide samples */ + sox_bool copying; +} priv_t; + +static int parse(sox_effect_t *effp, int argc, char **argv) +{ + priv_t *p = (priv_t*) effp->priv; + unsigned int i; + --argc, ++argv; + p->num_pos = argc; + lsx_Calloc(p->pos, p->num_pos); + for (i = 0; i < p->num_pos; i++) { + const char *arg = argv[i]; + p->pos[i].argstr = lsx_strdup(arg); + /* dummy parse to check for syntax errors */ + arg = lsx_parseposition(0., arg, NULL, (uint64_t)0, (uint64_t)0, '+'); + if (!arg || *arg) { + lsx_fail("Error parsing position %u", i+1); + return lsx_usage(effp); + } + } + return SOX_SUCCESS; +} + +static int start(sox_effect_t *effp) +{ + priv_t *p = (priv_t*) effp->priv; + uint64_t in_length = effp->in_signal.length != SOX_UNKNOWN_LEN ? + effp->in_signal.length / effp->in_signal.channels : SOX_UNKNOWN_LEN; + uint64_t last_seen = 0; + sox_bool open_end; + unsigned int i; + + p->copying = sox_false; + + /* calculate absolute positions */ + for (i = 0; i < p->num_pos; i++) { + if (!lsx_parseposition(effp->in_signal.rate, p->pos[i].argstr, &p->pos[i].sample, last_seen, in_length, '+')) { + lsx_fail("Position %u is relative to end of audio, but audio length is unknown", i+1); + return SOX_EOF; + } + last_seen = p->pos[i].sample; + lsx_debug_more("position %u at %" PRIu64, i+1, last_seen); + } + + /* sanity checks */ + last_seen = 0; + for (i = 0; i < p->num_pos; i++) { + if (p->pos[i].sample < last_seen) { + lsx_fail("Position %u is behind the following position.", i); + return SOX_EOF; + } + last_seen = p->pos[i].sample; + } + if (p->num_pos && in_length != SOX_UNKNOWN_LEN) + if (p->pos[0].sample > in_length || + p->pos[p->num_pos-1].sample > in_length) + lsx_warn("%s position is after expected end of audio.", + p->pos[0].sample > in_length ? "Start" : "End"); + + /* avoid unnecessary work */ + if (in_length == SOX_UNKNOWN_LEN) + while (p->num_pos && p->pos[p->num_pos-1].sample == SOX_UNKNOWN_LEN) { + lsx_debug_more("removing `-0' position"); + p->num_pos--; + free(p->pos[p->num_pos].argstr); + } + if (p->num_pos == 1 && !p->pos[0].sample) + return SOX_EFF_NULL; + + /* calculate output length */ + open_end = p->num_pos % 2; + if (open_end && in_length == SOX_UNKNOWN_LEN) + effp->out_signal.length = SOX_UNKNOWN_LEN; + else { + effp->out_signal.length = 0; + for (i = 0; i+1 < p->num_pos ; i += 2) + effp->out_signal.length += + min(p->pos[i+1].sample, in_length) - min(p->pos[i].sample, in_length); + if (open_end) + effp->out_signal.length += + in_length - min(p->pos[p->num_pos-1].sample, in_length); + effp->out_signal.length *= effp->in_signal.channels; + } + + return SOX_SUCCESS; +} + +static int flow(sox_effect_t *effp, const sox_sample_t *ibuf, + sox_sample_t *obuf, size_t *isamp, size_t *osamp) +{ + priv_t *p = (priv_t*) effp->priv; + size_t len = min(*isamp, *osamp); + size_t channels = effp->in_signal.channels; + len /= channels; + *isamp = *osamp = 0; + + while (len) { + size_t chunk; + + if (p->current_pos < p->num_pos && + p->samples_read == p->pos[p->current_pos].sample) { + p->copying = !p->copying; + p->current_pos++; + } + + if (p->current_pos >= p->num_pos && !p->copying) + return SOX_EOF; + + chunk = p->current_pos < p->num_pos ? + min(len, p->pos[p->current_pos].sample - p->samples_read) : len; + if (p->copying) { + memcpy(obuf, ibuf, chunk * channels * sizeof(*obuf)); + obuf += chunk * channels, *osamp += chunk * channels; + } + ibuf += chunk * channels; *isamp += chunk * channels; + p->samples_read += chunk, len -= chunk; + } + + return SOX_SUCCESS; +} + +static int drain(sox_effect_t *effp, sox_sample_t *obuf UNUSED, size_t *osamp) +{ + priv_t *p = (priv_t*) effp->priv; + *osamp = 0; /* only checking for errors */ + + if (p->current_pos + 1 == p->num_pos && + p->pos[p->current_pos].sample == p->samples_read && + p->copying) /* would stop here anyway */ + p->current_pos++; + if (p->current_pos < p->num_pos) + lsx_warn("Last %u position(s) not reached%s.", + p->num_pos - p->current_pos, + (effp->in_signal.length == SOX_UNKNOWN_LEN || + effp->in_signal.length/effp->in_signal.channels == p->samples_read) ? + "" /* unknown length, or did already warn during start() */ : + " (audio shorter than expected)" + ); + return SOX_EOF; +} + +static int lsx_kill(sox_effect_t *effp) +{ + unsigned int i; + priv_t *p = (priv_t*) effp->priv; + for (i = 0; i < p->num_pos; i++) + free(p->pos[i].argstr); + free(p->pos); + return SOX_SUCCESS; +} + +sox_effect_handler_t const *lsx_trim_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "trim", "{position}", + SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY, + parse, start, flow, drain, NULL, lsx_kill, + sizeof(priv_t) + }; + return &handler; +} + +/* The following functions allow a libSoX client to do a speed + * optimization, by asking for the number of samples to be skipped + * at the beginning of the audio with sox_trim_get_start(), skipping + * that many samples in an efficient way such as seeking within the + * input file, then telling us it has been done by calling + * sox_trim_clear_start() (the name is historical). + * Note that sox_trim_get_start() returns the number of non-wide + * samples. */ + +sox_uint64_t sox_trim_get_start(sox_effect_t *effp) +{ + priv_t *p = (priv_t*) effp->priv; + return p->num_pos ? p->pos[0].sample * effp->in_signal.channels : 0; +} + +void sox_trim_clear_start(sox_effect_t *effp) +{ + priv_t *p = (priv_t*) effp->priv; + p->samples_read = p->num_pos ? p->pos[0].sample : 0; +} diff --git a/app/src/main/cpp/sox/tx16w.c b/app/src/main/cpp/sox/tx16w.c new file mode 100644 index 0000000..42c644d --- /dev/null +++ b/app/src/main/cpp/sox/tx16w.c @@ -0,0 +1,382 @@ +/* libSoX Yamaha TX-16W sampler file support + * + * May 20, 1993 + * Copyright 1993 Rob Talley (rob@aii.com) + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice and the following copyright + * notice must be maintained intact. No warranty whatsoever is + * provided. This code is furnished AS-IS as a component of the + * larger work Copyright 1991 Lance Norskog and Sundry Contributors. + * Much appreciation to ross-c for his sampConv utility for SGI/IRIX + * from where these methods were derived. + * + * Jan 24, 1994 + * Pat McElhatton, HP Media Technology Lab + * Handles reading of files which do not have the sample rate field + * set to one of the expected by looking at some other bytes in the + * attack/loop length fields, and defaulting to 33kHz if the sample + * rate is still unknown. + * + * January 12, 1995 + * Copyright 1995 Mark Lakata (lakata@physics.berkeley.edu) + * Additions to tx16w.c SOX handler. This version writes as well as + * reads TX16W format. + * + * July 31, 1998 + * Cleaned up by Leigh Smith (leigh@psychokiller.dialix.oz.au) + * for incorporation into the main sox distribution. + * + * September 24, 1998 + * Forced output to mono signed words to match input. It was basically + * doing this anyways but now the user will see a display that it's been + * overridden. cbagwell@sprynet.com + * + */ + +#include "sox_i.h" +#include +#include + +#define TXMAXLEN 0x3FF80 + +/* Private data for TX16 file */ +typedef struct { + size_t samples_out; + size_t bytes_out; + size_t rest; /* bytes remaining in sample file */ + sox_sample_t odd; + sox_bool odd_flag; +} priv_t; + +struct WaveHeader_ { + char filetype[6]; /* = "LM8953", */ + unsigned char + nulls[10], + dummy_aeg[6], /* space for the AEG (never mind this) */ + format, /* 0x49 = looped, 0xC9 = non-looped */ + sample_rate, /* 1 = 33 kHz, 2 = 50 kHz, 3 = 16 kHz */ + atc_length[3], /* I'll get to this... */ + rpt_length[3], + unused[2]; /* set these to null, to be on the safe side */ +}; + +static const unsigned char magic1[4] = {0, 0x06, 0x10, 0xF6}; +static const unsigned char magic2[4] = {0, 0x52, 0x00, 0x52}; + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int startread(sox_format_t * ft) +{ + int c; + char filetype[7]; + int8_t format; + unsigned char sample_rate; + size_t num_samp_bytes = 0; + unsigned char gunk[8]; + int blewIt; + uint8_t trash; + + priv_t * sk = (priv_t *) ft->priv; + /* If you need to seek around the input file. */ + if (! ft->seekable) + { + lsx_fail_errno(ft,SOX_EOF,"txw input file must be a file, not a pipe"); + return(SOX_EOF); + } + + /* This is dumb but portable, just count the bytes til EOF */ + while (lsx_read_b_buf(ft, &trash, (size_t) 1) == 1) + num_samp_bytes++; + num_samp_bytes -= 32; /* calculate num samples by sub header size */ + lsx_seeki(ft, (off_t)0, 0); /* rewind file */ + sk->rest = num_samp_bytes; /* set how many sample bytes to read */ + + /* first 6 bytes are file type ID LM8953 */ + lsx_readchars(ft, filetype, sizeof(filetype) - 1); + filetype[6] = '\0'; + for( c = 16; c > 0 ; c-- ) /* Discard next 16 bytes */ + lsx_readb(ft, &trash); + lsx_readsb(ft, &format); + lsx_readb(ft, &sample_rate); + /* + * save next 8 bytes - if sample rate is 0, then we need + * to look at gunk[2] and gunk[5] to get real rate + */ + for( c = 0; c < 8; c++ ) + lsx_readb(ft, &(gunk[c])); + /* + * We should now be pointing at start of raw sample data in file + */ + + /* Check to make sure we got a good filetype ID from file */ + lsx_debug("Found header filetype %s",filetype); + if(strcmp(filetype,"LM8953")) + { + lsx_fail_errno(ft,SOX_EHDR,"Invalid filetype ID in input file header, != LM8953"); + return(SOX_EOF); + } + /* + * Set up the sample rate as indicated by the header + */ + + switch( sample_rate ) { + case 1: + ft->signal.rate = 1e5 / 3; + break; + case 2: + ft->signal.rate = 1e5 / 2; + break; + case 3: + ft->signal.rate = 1e5 / 6; + break; + default: + blewIt = 1; + switch( gunk[2] & 0xFE ) { + case 0x06: + if ( (gunk[5] & 0xFE) == 0x52 ) { + blewIt = 0; + ft->signal.rate = 1e5 / 3; + } + break; + case 0x10: + if ( (gunk[5] & 0xFE) == 0x00 ) { + blewIt = 0; + ft->signal.rate = 1e5 / 2; + } + break; + case 0xF6: + if ( (gunk[5] & 0xFE) == 0x52 ) { + blewIt = 0; + ft->signal.rate = 1e5 / 6; + } + break; + } + if ( blewIt ) { + lsx_debug("Invalid sample rate identifier found %d", sample_rate); + ft->signal.rate = 1e5 / 3; + } + } + lsx_debug("Sample rate = %g", ft->signal.rate); + + ft->signal.channels = 1 ; /* not sure about stereo sample data yet ??? */ + ft->encoding.bits_per_sample = 12; + ft->encoding.encoding = SOX_ENCODING_SIGN2; + + return(SOX_SUCCESS); +} + +/* + * Read up to len samples from file. + * Convert to sox_sample_t. + * Place in buf[]. + * Return number of samples read. + */ + +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t * sk = (priv_t *) ft->priv; + size_t done = 0; + unsigned char uc1,uc2,uc3; + unsigned short s1,s2; + + /* + * This gets called by the top level 'process' routine. + * We will essentially get called with a buffer pointer + * and a max length to read. Graciously, it is always + * an even amount so we don't have to worry about + * hanging onto the left over odd samples since there + * won't be any. Something to look out for though :-( + * We return the number of samples we read. + * We will get called over and over again until we return + * 0 bytes read. + */ + + /* + * This is ugly but it's readable! + * Read three bytes from stream, then decompose these into + * two unsigned short samples. + * TCC 3.0 appeared to do unwanted things, so we really specify + * exactly what we want to happen. + * Convert unsigned short to sox_sample_t then shift up the result + * so that the 12-bit sample lives in the most significant + * 12-bits of the sox_sample_t. + * This gets our two samples into the internal format which we + * deposit into the given buffer and adjust our counts respectivly. + */ + for(done = 0; done < len; ) { + if(sk->rest < 3) break; /* Finished reading from file? */ + lsx_readb(ft, &uc1); + lsx_readb(ft, &uc2); + lsx_readb(ft, &uc3); + sk->rest -= 3; /* adjust remaining for bytes we just read */ + s1 = (unsigned short) (uc1 << 4) | (((uc2 >> 4) & 017)); + s2 = (unsigned short) (uc3 << 4) | (( uc2 & 017 )); + *buf = (sox_sample_t) s1; + *buf = (*buf << 20); + buf++; /* sample one is done */ + *buf = (sox_sample_t) s2; + *buf = (*buf << 20); + buf++; /* sample two is done */ + done += 2; /* adjust converted & stored sample count */ + } + return done; +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * sk = (priv_t *) ft->priv; + struct WaveHeader_ WH; + + lsx_debug("tx16w selected output"); + + memset(&WH, 0, sizeof(struct WaveHeader_)); + + /* If you have to seek around the output file */ + if (! ft->seekable) + { + lsx_fail_errno(ft,SOX_EOF,"Output .txw file must be a file, not a pipe"); + return(SOX_EOF); + } + + /* dummy numbers, just for place holder, real header is written + at end of processing, since byte count is needed */ + + lsx_writebuf(ft, &WH, (size_t) 32); + sk->bytes_out = 32; + return(SOX_SUCCESS); +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len0) +{ + priv_t * sk = (priv_t *) ft->priv; + size_t last_i, i = 0, len = min(len0, TXMAXLEN - sk->samples_out); + sox_sample_t w1, w2; + + while (i < len) { + last_i = i; + if (sk->odd_flag) { + w1 = sk->odd; + sk->odd_flag = sox_false; + } + else w1 = *buf++ >> 20, ++i; + + if (i < len) { + w2 = *buf++ >> 20, ++i; + if (lsx_writesb(ft, (w1 >> 4) & 0xFF) || + lsx_writesb(ft, (((w1 & 0x0F) << 4) | (w2 & 0x0F)) & 0xFF) || + lsx_writesb(ft, (w2 >> 4) & 0xFF)) { + i = last_i; + break; + } + sk->samples_out += 2; + sk->bytes_out += 3; + } + else { + sk->odd = w1; + sk->odd_flag = sox_true; + } + } + return i; +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * sk = (priv_t *) ft->priv; + struct WaveHeader_ WH; + int AttackLength, LoopLength, i; + + if (sk->odd_flag) { + sox_sample_t pad = 0; + write_samples(ft, &pad, (size_t) 1); + } + + /* All samples are already written out. */ + /* If file header needs fixing up, for example it needs the */ + /* the number of samples in a field, seek back and write them here. */ + + lsx_debug("tx16w:output finished"); + + memset(&WH, 0, sizeof(struct WaveHeader_)); + memcpy(WH.filetype, "LM8953", 6); + for (i=0;i<10;i++) WH.nulls[i]=0; + for (i=0;i<6;i++) WH.dummy_aeg[i]=0; + for (i=0;i<2;i++) WH.unused[i]=0; + for (i=0;i<2;i++) WH.dummy_aeg[i] = 0; + for (i=2;i<6;i++) WH.dummy_aeg[i] = 0x7F; + + WH.format = 0xC9; /* loop off */ + + /* the actual sample rate is not that important ! */ + if (ft->signal.rate < 24000) WH.sample_rate = 3; + else if (ft->signal.rate < 41000) WH.sample_rate = 1; + else WH.sample_rate = 2; + + if (sk->samples_out >= TXMAXLEN) { + lsx_warn("Sound too large for TX16W. Truncating, Loop Off"); + AttackLength = TXMAXLEN/2; + LoopLength = TXMAXLEN/2; + } + else if (sk->samples_out >=TXMAXLEN/2) { + AttackLength = TXMAXLEN/2; + LoopLength = sk->samples_out - TXMAXLEN/2; + if (LoopLength < 0x40) { + LoopLength +=0x40; + AttackLength -= 0x40; + } + } + else if (sk->samples_out >= 0x80) { + AttackLength = sk->samples_out -0x40; + LoopLength = 0x40; + } + else { + AttackLength = 0x40; + LoopLength = 0x40; + for(i=sk->samples_out;i<0x80;i++) { + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + lsx_writeb(ft, 0); + sk->bytes_out += 3; + } + } + + /* Fill up to 256 byte blocks; the TX16W seems to like that */ + + while ((sk->bytes_out % 0x100) != 0) { + lsx_writeb(ft, 0); + sk->bytes_out++; + } + + WH.atc_length[0] = 0xFF & AttackLength; + WH.atc_length[1] = 0xFF & (AttackLength >> 8); + WH.atc_length[2] = (0x01 & (AttackLength >> 16)) + + magic1[WH.sample_rate]; + + WH.rpt_length[0] = 0xFF & LoopLength; + WH.rpt_length[1] = 0xFF & (LoopLength >> 8); + WH.rpt_length[2] = (0x01 & (LoopLength >> 16)) + + magic2[WH.sample_rate]; + + lsx_rewind(ft); + lsx_writebuf(ft, &WH, (size_t) 32); + + return(SOX_SUCCESS); +} + +LSX_FORMAT_HANDLER(txw) +{ + static char const * const names[] = {"txw", NULL}; + static sox_rate_t const write_rates[] = {1e5/6, 1e5/3, 1e5/2, 0}; + static unsigned const write_encodings[] = {SOX_ENCODING_SIGN2, 12, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Yamaha TX-16W sampler", names, SOX_FILE_MONO, + startread, read_samples, NULL, + startwrite, write_samples, stopwrite, + NULL, write_encodings, write_rates, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/u1-fmt.c b/app/src/main/cpp/sox/u1-fmt.c new file mode 100644 index 0000000..f25f39d --- /dev/null +++ b/app/src/main/cpp/sox/u1-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT4(u1, "u8", "ub", "sou", "fssd", 8, 0, UNSIGNED) diff --git a/app/src/main/cpp/sox/u2-fmt.c b/app/src/main/cpp/sox/u2-fmt.c new file mode 100644 index 0000000..27019d6 --- /dev/null +++ b/app/src/main/cpp/sox/u2-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT2(u2, "u16", "uw", 16, 0, UNSIGNED) diff --git a/app/src/main/cpp/sox/u3-fmt.c b/app/src/main/cpp/sox/u3-fmt.c new file mode 100644 index 0000000..66b7587 --- /dev/null +++ b/app/src/main/cpp/sox/u3-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT1(u3, "u24", 24, 0, UNSIGNED) diff --git a/app/src/main/cpp/sox/u4-fmt.c b/app/src/main/cpp/sox/u4-fmt.c new file mode 100644 index 0000000..28f99fa --- /dev/null +++ b/app/src/main/cpp/sox/u4-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT1(u4, "u32", 32, 0, UNSIGNED) diff --git a/app/src/main/cpp/sox/ul-fmt.c b/app/src/main/cpp/sox/ul-fmt.c new file mode 100644 index 0000000..b876f3e --- /dev/null +++ b/app/src/main/cpp/sox/ul-fmt.c @@ -0,0 +1,21 @@ +/* libSoX file formats: raw (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "raw.h" + +RAW_FORMAT(ul, 8, 0, ULAW) diff --git a/app/src/main/cpp/sox/upsample.c b/app/src/main/cpp/sox/upsample.c new file mode 100644 index 0000000..c0afea1 --- /dev/null +++ b/app/src/main/cpp/sox/upsample.c @@ -0,0 +1,64 @@ +/* libSoX effect: Upsample (zero stuff) (c) 2011 robs@users.sourceforge.net + * + * Sometimes filters perform better at higher sampling rates, so e.g. + * sox -r 48k input output upsample 4 filter rate 48k vol 4 + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +typedef struct {unsigned factor, pos;} priv_t; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + p->factor = 2; + --argc, ++argv; + do {NUMERIC_PARAMETER(factor, 1, 256)} while (0); + return argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *) effp->priv; + effp->out_signal.rate = effp->in_signal.rate * p->factor; + return p->factor == 1? SOX_EFF_NULL : SOX_SUCCESS; +} + +static int flow(sox_effect_t * effp, const sox_sample_t * ibuf, + sox_sample_t * obuf, size_t * isamp, size_t * osamp) +{ + priv_t * p = (priv_t *)effp->priv; + size_t ilen = *isamp, olen = *osamp; + while (sox_true) { + for (; p->pos && olen; p->pos = (p->pos + 1) % p->factor, --olen) + *obuf++ = 0; + if (!ilen || !olen) + break; + *obuf++ = *ibuf++; + --olen, --ilen; + ++p->pos; + } + *isamp -= ilen, *osamp -= olen; + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_upsample_effect_fn(void) +{ + static sox_effect_handler_t handler = {"upsample", "[factor (2)]", + SOX_EFF_RATE | SOX_EFF_MODIFY, create, start, flow, NULL, NULL, NULL, sizeof(priv_t)}; + return &handler; +} diff --git a/app/src/main/cpp/sox/util.c b/app/src/main/cpp/sox/util.c new file mode 100644 index 0000000..2d41dfd --- /dev/null +++ b/app/src/main/cpp/sox/util.c @@ -0,0 +1,304 @@ +/* General purpose, i.e. non SoX specific, utility functions. + * Copyright (c) 2007-8 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include +#include + +int lsx_strcasecmp(const char * s1, const char * s2) +{ +#if defined(HAVE_STRCASECMP) + return strcasecmp(s1, s2); +#elif defined(_MSC_VER) + return _stricmp(s1, s2); +#else + while (*s1 && (toupper(*s1) == toupper(*s2))) + s1++, s2++; + return toupper(*s1) - toupper(*s2); +#endif +} + +int lsx_strncasecmp(char const * s1, char const * s2, size_t n) +{ +#if defined(HAVE_STRCASECMP) + return strncasecmp(s1, s2, n); +#elif defined(_MSC_VER) + return _strnicmp(s1, s2, n); +#else + while (--n && *s1 && (toupper(*s1) == toupper(*s2))) + s1++, s2++; + return toupper(*s1) - toupper(*s2); +#endif +} + +sox_bool lsx_strends(char const * str, char const * end) +{ + size_t str_len = strlen(str), end_len = strlen(end); + return str_len >= end_len && !strcmp(str + str_len - end_len, end); +} + +char const * lsx_find_file_extension(char const * pathname) +{ + /* First, chop off any path portions of filename. This + * prevents the next search from considering that part. */ + char const * result = LAST_SLASH(pathname); + if (!result) + result = pathname; + + /* Now look for an filename extension */ + result = strrchr(result, '.'); + if (result) + ++result; + return result; +} + +lsx_enum_item const * lsx_find_enum_text(char const * text, lsx_enum_item const * enum_items, int flags) +{ + lsx_enum_item const * result = NULL; /* Assume not found */ + sox_bool sensitive = !!(flags & lsx_find_enum_item_case_sensitive); + + while (enum_items->text) { + if ((!sensitive && !strcasecmp(text, enum_items->text)) || + ( sensitive && ! strcmp(text, enum_items->text))) + return enum_items; /* Found exact match */ + if ((!sensitive && !strncasecmp(text, enum_items->text, strlen(text))) || + ( sensitive && ! strncmp(text, enum_items->text, strlen(text)))) { + if (result != NULL && result->value != enum_items->value) + return NULL; /* Found ambiguity */ + result = enum_items; /* Found sub-string match */ + } + ++enum_items; + } + return result; +} + +lsx_enum_item const * lsx_find_enum_value(unsigned value, lsx_enum_item const * enum_items) +{ + for (;enum_items->text; ++enum_items) + if (value == enum_items->value) + return enum_items; + return NULL; +} + +int lsx_enum_option(int c, char const * arg, lsx_enum_item const * items) +{ + lsx_enum_item const * p = lsx_find_enum_text(arg, items, sox_false); + if (p == NULL) { + size_t len = 1; + char * set = lsx_malloc(len); + *set = 0; + for (p = items; p->text; ++p) { + set = lsx_realloc(set, len += 2 + strlen(p->text)); + strcat(set, ", "); strcat(set, p->text); + } + lsx_fail("-%c: `%s' is not one of: %s.", c, arg, set + 2); + free(set); + return INT_MAX; + } + return p->value; +} + +char const * lsx_sigfigs3(double number) +{ + static char const symbols[] = "\0kMGTPEZY"; + static char string[16][10]; /* FIXME: not thread-safe */ + static unsigned n; /* ditto */ + unsigned a, b, c; + sprintf(string[n = (n+1) & 15], "%#.3g", number); + switch (sscanf(string[n], "%u.%ue%u", &a, &b, &c)) { + case 2: if (b) return string[n]; /* Can fall through */ + case 1: c = 2; break; + case 3: a = 100*a + b; break; + } + if (c < array_length(symbols) * 3 - 3) switch (c%3) { + case 0: sprintf(string[n], "%u.%02u%c", a/100,a%100, symbols[c/3]); break; + case 1: sprintf(string[n], "%u.%u%c" , a/10 ,a%10 , symbols[c/3]); break; + case 2: sprintf(string[n], "%u%c" , a , symbols[c/3]); break; + } + return string[n]; +} + +char const * lsx_sigfigs3p(double percentage) +{ + static char string[16][10]; + static unsigned n; + sprintf(string[n = (n+1) & 15], "%.1f%%", percentage); + if (strlen(string[n]) < 5) + sprintf(string[n], "%.2f%%", percentage); + else if (strlen(string[n]) > 5) + sprintf(string[n], "%.0f%%", percentage); + return string[n]; +} + +int lsx_open_dllibrary( + int show_error_on_failure, + const char* library_description, + const char* const library_names[] UNUSED, + const lsx_dlfunction_info func_infos[], + lsx_dlptr selected_funcs[], + lsx_dlhandle* pdl) +{ + int failed = 0; + lsx_dlhandle dl = NULL; + + /* Track enough information to give a good error message about one failure. + * Let failed symbol load override failed library open, and let failed + * library open override missing static symbols. + */ + const char* failed_libname = NULL; + const char* failed_funcname = NULL; + +#ifdef HAVE_LIBLTDL + if (library_names && library_names[0]) + { + const char* const* libname; + if (lt_dlinit()) + { + lsx_fail( + "Unable to load %s - failed to initialize ltdl.", + library_description); + return 1; + } + + for (libname = library_names; *libname; libname++) + { + lsx_debug("Attempting to open %s (%s).", library_description, *libname); + dl = lt_dlopenext(*libname); + if (dl) + { + size_t i; + lsx_debug("Opened %s (%s).", library_description, *libname); + for (i = 0; func_infos[i].name; i++) + { + union {lsx_dlptr fn; lt_ptr ptr;} func; + func.ptr = lt_dlsym(dl, func_infos[i].name); + selected_funcs[i] = func.fn ? func.fn : func_infos[i].stub_func; + if (!selected_funcs[i]) + { + lt_dlclose(dl); + dl = NULL; + failed_libname = *libname; + failed_funcname = func_infos[i].name; + lsx_debug("Cannot use %s (%s) - missing function \"%s\".", library_description, failed_libname, failed_funcname); + break; + } + } + + if (dl) + break; + } + else if (!failed_libname) + { + failed_libname = *libname; + } + } + + if (!dl) + lt_dlexit(); + } +#endif /* HAVE_LIBLTDL */ + + if (!dl) + { + size_t i; + for (i = 0; func_infos[i].name; i++) + { + selected_funcs[i] = + func_infos[i].static_func + ? func_infos[i].static_func + : func_infos[i].stub_func; + if (!selected_funcs[i]) + { + if (!failed_libname) + { + failed_libname = "static"; + failed_funcname = func_infos[i].name; + } + + failed = 1; + break; + } + } + } + + if (failed) + { + size_t i; + for (i = 0; func_infos[i].name; i++) + selected_funcs[i] = NULL; +#ifdef HAVE_LIBLTDL +#define LTDL_MISSING "" +#else +#define LTDL_MISSING " (Dynamic library support not configured.)" +#endif /* HAVE_LIBLTDL */ + if (failed_funcname) + { + if (show_error_on_failure) + lsx_fail( + "Unable to load %s (%s) function \"%s\"." LTDL_MISSING, + library_description, + failed_libname, + failed_funcname); + else + lsx_report( + "Unable to load %s (%s) function \"%s\"." LTDL_MISSING, + library_description, + failed_libname, + failed_funcname); + } + else if (failed_libname) + { + if (show_error_on_failure) + lsx_fail( + "Unable to load %s (%s)." LTDL_MISSING, + library_description, + failed_libname); + else + lsx_report( + "Unable to load %s (%s)." LTDL_MISSING, + library_description, + failed_libname); + } + else + { + if (show_error_on_failure) + lsx_fail( + "Unable to load %s - no dynamic library names selected." LTDL_MISSING, + library_description); + else + lsx_report( + "Unable to load %s - no dynamic library names selected." LTDL_MISSING, + library_description); + } + } + + *pdl = dl; + return failed; +} + +void lsx_close_dllibrary( + lsx_dlhandle dl UNUSED) +{ +#ifdef HAVE_LIBLTDL + if (dl) + { + lt_dlclose(dl); + lt_dlexit(); + } +#endif /* HAVE_LIBLTDL */ +} diff --git a/app/src/main/cpp/sox/util.h b/app/src/main/cpp/sox/util.h new file mode 100644 index 0000000..fa34128 --- /dev/null +++ b/app/src/main/cpp/sox/util.h @@ -0,0 +1,184 @@ +/* General purpose, i.e. non SoX specific, utility functions and macros. + * + * (c) 2006-8 Chris Bagwell and SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include "soxconfig.h" + +#ifdef HAVE_SYS_TYPES_H +#include /* For off_t not found in stdio.h */ +#endif + +#ifdef HAVE_SYS_STAT_H +#include /* Needs to be included before we redefine off_t. */ +#endif + +#include "xmalloc.h" + +/*---------------------------- Portability stuff -----------------------------*/ + +#ifdef __GNUC__ +#define NORET __attribute__((noreturn)) +#define UNUSED __attribute__ ((unused)) +#else +#define NORET +#define UNUSED +#endif + +#ifdef _MSC_VER + +#define __STDC__ 1 +#define O_BINARY _O_BINARY +#define O_CREAT _O_CREAT +#define O_RDWR _O_RDWR +#define O_TRUNC _O_TRUNC +#define S_IFMT _S_IFMT +#define S_IFREG _S_IFREG +#define S_IREAD _S_IREAD +#define S_IWRITE _S_IWRITE +#define close _close +#define dup _dup +#define fdopen _fdopen +#define fileno _fileno + +#ifdef _fstati64 +#define fstat _fstati64 +#else +#define fstat _fstat +#endif + +#define ftime _ftime +#define inline __inline +#define isatty _isatty +#define kbhit _kbhit +#define mktemp _mktemp +#define off_t _off_t +#define open _open +#define pclose _pclose +#define popen _popen +#define setmode _setmode +#define snprintf _snprintf + +#ifdef _stati64 +#define stat _stati64 +#else +#define stat _stat +#endif + +#define strdup _strdup +#define timeb _timeb +#define unlink _unlink + +#if defined(HAVE__FSEEKI64) && !defined(HAVE_FSEEKO) +#undef off_t +#define fseeko _fseeki64 +#define ftello _ftelli64 +#define off_t __int64 +#define HAVE_FSEEKO 1 +#endif + +#elif defined(__MINGW32__) + +#if !defined(HAVE_FSEEKO) +#undef off_t +#define fseeko fseeko64 +#define fstat _fstati64 +#define ftello ftello64 +#define off_t off64_t +#define stat _stati64 +#define HAVE_FSEEKO 1 +#endif + +#endif + +#if defined(DOS) || defined(WIN32) || defined(__NT__) || defined(__DJGPP__) || defined(__OS2__) + #define LAST_SLASH(path) max(strrchr(path, '/'), strrchr(path, '\\')) + #define IS_ABSOLUTE(path) ((path)[0] == '/' || (path)[0] == '\\' || (path)[1] == ':') + #define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) + #define POPEN_MODE "rb" +#else + #define LAST_SLASH(path) strrchr(path, '/') + #define IS_ABSOLUTE(path) ((path)[0] == '/') + #define SET_BINARY_MODE(file) +#endif + +#ifdef WORDS_BIGENDIAN + #define MACHINE_IS_BIGENDIAN 1 + #define MACHINE_IS_LITTLEENDIAN 0 +#else + #define MACHINE_IS_BIGENDIAN 0 + #define MACHINE_IS_LITTLEENDIAN 1 +#endif + +/*--------------------------- Language extensions ----------------------------*/ + +/* Compile-time ("static") assertion */ +/* e.g. assert_static(sizeof(int) >= 4, int_type_too_small) */ +#define assert_static(e,f) enum {assert_static__##f = 1/(e)} +#define array_length(a) (sizeof(a)/sizeof(a[0])) +#define field_offset(type, field) ((size_t)&(((type *)0)->field)) +#define unless(x) if (!(x)) + +/*------------------------------- Maths stuff --------------------------------*/ + +#include + +#ifdef min +#undef min +#endif +#define min(a, b) ((a) <= (b) ? (a) : (b)) + +#ifdef max +#undef max +#endif +#define max(a, b) ((a) >= (b) ? (a) : (b)) + +#define range_limit(x, lower, upper) (min(max(x, lower), upper)) + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif +#ifndef M_PI_2 +#define M_PI_2 1.57079632679489661923 /* pi/2 */ +#endif +#ifndef M_LN10 +#define M_LN10 2.30258509299404568402 /* natural log of 10 */ +#endif +#ifndef M_SQRT2 +#define M_SQRT2 sqrt(2.) +#endif + +#define sqr(a) ((a) * (a)) +#define sign(x) ((x) < 0? -1 : 1) + +/* Numerical Recipes in C, p. 284 */ +#define ranqd1(x) ((x) = 1664525L * (x) + 1013904223L) /* int32_t x */ +#define dranqd1(x) (ranqd1(x) * (1. / (65536. * 32768.))) /* [-1,1) */ + +#define dB_to_linear(x) exp((x) * M_LN10 * 0.05) +#define linear_to_dB(x) (log10(x) * 20) + +extern int lsx_strcasecmp(const char *s1, const char *st); +extern int lsx_strncasecmp(char const *s1, char const *s2, size_t n); + +#ifndef HAVE_STRCASECMP +#define strcasecmp(s1, s2) lsx_strcasecmp((s1), (s2)) +#define strncasecmp(s1, s2, n) lsx_strncasecmp((s1), (s2), (n)) +#endif diff --git a/app/src/main/cpp/sox/vad.c b/app/src/main/cpp/sox/vad.c new file mode 100644 index 0000000..fc1f9e9 --- /dev/null +++ b/app/src/main/cpp/sox/vad.c @@ -0,0 +1,329 @@ +/* libSoX effect: Voice Activity Detector (c) 2009 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +typedef struct { + double * dftBuf, * noiseSpectrum, * spectrum, * measures, meanMeas; +} chan_t; + +typedef struct { /* Configuration parameters: */ + double bootTime, noiseTcUp, noiseTcDown, noiseReductionAmount; + double measureFreq, measureDuration, measureTc, preTriggerTime; + double hpFilterFreq, lpFilterFreq, hpLifterFreq, lpLifterFreq; + double triggerTc, triggerLevel, searchTime, gapTime; + /* Working variables: */ + sox_sample_t * samples; + unsigned dftLen_ws, samplesLen_ns, samplesIndex_ns, flushedLen_ns, gapLen; + unsigned measurePeriod_ns, measuresLen, measuresIndex; + unsigned measureTimer_ns, measureLen_ws, measureLen_ns; + unsigned spectrumStart, spectrumEnd, cepstrumStart, cepstrumEnd; /* bins */ + int bootCountMax, bootCount; + double noiseTcUpMult, noiseTcDownMult; + double measureTcMult, triggerMeasTcMult; + double * spectrumWindow, * cepstrumWindow; + chan_t * channels; +} priv_t; + +#define GETOPT_FREQ(optstate, c, name, min) \ + case c: p->name = lsx_parse_frequency(optstate.arg, &parseIndex); \ + if (p->name < min || *parseIndex) return lsx_usage(effp); \ + break; + +static int create(sox_effect_t * effp, int argc, char * * argv) +{ + priv_t * p = (priv_t *)effp->priv; + #define opt_str "+b:N:n:r:f:m:M:h:l:H:L:T:t:s:g:p:" + int c; + lsx_getopt_t optstate; + lsx_getopt_init(argc, argv, opt_str, NULL, lsx_getopt_flag_none, 1, &optstate); + + p->bootTime = .35; + p->noiseTcUp = .1; + p->noiseTcDown = .01; + p->noiseReductionAmount = 1.35; + + p->measureFreq = 20; + p->measureDuration = 2 / p->measureFreq; /* 50% overlap */ + p->measureTc = .4; + + p->hpFilterFreq = 50; + p->lpFilterFreq = 6000; + p->hpLifterFreq = 150; + p->lpLifterFreq = 2000; + + p->triggerTc = .25; + p->triggerLevel = 7; + + p->searchTime = 1; + p->gapTime = .25; + + while ((c = lsx_getopt(&optstate)) != -1) switch (c) { + char * parseIndex; + GETOPT_NUMERIC(optstate, 'b', bootTime , .1 , 10) + GETOPT_NUMERIC(optstate, 'N', noiseTcUp , .1 , 10) + GETOPT_NUMERIC(optstate, 'n', noiseTcDown ,.001 , .1) + GETOPT_NUMERIC(optstate, 'r', noiseReductionAmount,0 , 2) + GETOPT_NUMERIC(optstate, 'f', measureFreq , 5 , 50) + GETOPT_NUMERIC(optstate, 'm', measureDuration, .01 , 1) + GETOPT_NUMERIC(optstate, 'M', measureTc , .1 , 1) + GETOPT_FREQ( optstate, 'h', hpFilterFreq , 10) + GETOPT_FREQ( optstate, 'l', lpFilterFreq , 1000) + GETOPT_FREQ( optstate, 'H', hpLifterFreq , 10) + GETOPT_FREQ( optstate, 'L', lpLifterFreq , 1000) + GETOPT_NUMERIC(optstate, 'T', triggerTc , .01 , 1) + GETOPT_NUMERIC(optstate, 't', triggerLevel , 0 , 20) + GETOPT_NUMERIC(optstate, 's', searchTime , .1 , 4) + GETOPT_NUMERIC(optstate, 'g', gapTime , .1 , 1) + GETOPT_NUMERIC(optstate, 'p', preTriggerTime, 0 , 4) + default: lsx_fail("invalid option `-%c'", optstate.opt); return lsx_usage(effp); + } + return optstate.ind !=argc? lsx_usage(effp) : SOX_SUCCESS; +} + +static int start(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i, fixedPreTriggerLen_ns, searchPreTriggerLen_ns; + + fixedPreTriggerLen_ns = p->preTriggerTime * effp->in_signal.rate + .5; + fixedPreTriggerLen_ns *= effp->in_signal.channels; + + p->measureLen_ws = effp->in_signal.rate * p->measureDuration + .5; + p->measureLen_ns = p->measureLen_ws * effp->in_signal.channels; + for (p->dftLen_ws = 16; p->dftLen_ws < p->measureLen_ws; p->dftLen_ws <<= 1); + lsx_debug("dftLen_ws=%u measureLen_ws=%u", p->dftLen_ws, p->measureLen_ws); + + p->measurePeriod_ns = effp->in_signal.rate / p->measureFreq + .5; + p->measurePeriod_ns *= effp->in_signal.channels; + p->measuresLen = ceil(p->searchTime * p->measureFreq); + searchPreTriggerLen_ns = p->measuresLen * p->measurePeriod_ns; + p->gapLen = p->gapTime * p->measureFreq + .5; + + p->samplesLen_ns = + fixedPreTriggerLen_ns + searchPreTriggerLen_ns + p->measureLen_ns; + lsx_Calloc(p->samples, p->samplesLen_ns); + + lsx_Calloc(p->channels, effp->in_signal.channels); + for (i = 0; i < effp->in_signal.channels; ++i) { + chan_t * c = &p->channels[i]; + lsx_Calloc(c->dftBuf, p->dftLen_ws); + lsx_Calloc(c->spectrum, p->dftLen_ws); + lsx_Calloc(c->noiseSpectrum, p->dftLen_ws); + lsx_Calloc(c->measures, p->measuresLen); + } + + lsx_Calloc(p->spectrumWindow, p->measureLen_ws); + for (i = 0; i < p->measureLen_ws; ++i) + p->spectrumWindow[i] = -2./ SOX_SAMPLE_MIN / sqrt((double)p->measureLen_ws); + lsx_apply_hann(p->spectrumWindow, (int)p->measureLen_ws); + + p->spectrumStart = p->hpFilterFreq / effp->in_signal.rate * p->dftLen_ws + .5; + p->spectrumStart = max(p->spectrumStart, 1); + p->spectrumEnd = p->lpFilterFreq / effp->in_signal.rate * p->dftLen_ws + .5; + p->spectrumEnd = min(p->spectrumEnd, p->dftLen_ws / 2); + + lsx_Calloc(p->cepstrumWindow, p->spectrumEnd - p->spectrumStart); + for (i = 0; i < p->spectrumEnd - p->spectrumStart; ++i) + p->cepstrumWindow[i] = 2 / sqrt((double)p->spectrumEnd - p->spectrumStart); + lsx_apply_hann(p->cepstrumWindow,(int)(p->spectrumEnd - p->spectrumStart)); + + p->cepstrumStart = ceil(effp->in_signal.rate * .5 / p->lpLifterFreq); + p->cepstrumEnd = floor(effp->in_signal.rate * .5 / p->hpLifterFreq); + p->cepstrumEnd = min(p->cepstrumEnd, p->dftLen_ws / 4); + if (p->cepstrumEnd <= p->cepstrumStart) + return SOX_EOF; + + p->noiseTcUpMult = exp(-1 / (p->noiseTcUp * p->measureFreq)); + p->noiseTcDownMult = exp(-1 / (p->noiseTcDown * p->measureFreq)); + p->measureTcMult = exp(-1 / (p->measureTc * p->measureFreq)); + p->triggerMeasTcMult = exp(-1 / (p->triggerTc * p->measureFreq)); + + p->bootCountMax = p->bootTime * p->measureFreq - .5; + p->measureTimer_ns = p->measureLen_ns; + p->bootCount = p->measuresIndex = p->flushedLen_ns = p->samplesIndex_ns = 0; + + effp->out_signal.length = SOX_UNKNOWN_LEN; /* depends on input data */ + return SOX_SUCCESS; +} + +static int flowFlush(sox_effect_t * effp, sox_sample_t const * ibuf, + sox_sample_t * obuf, size_t * ilen, size_t * olen) +{ + priv_t * p = (priv_t *)effp->priv; + size_t odone = min(p->samplesLen_ns - p->flushedLen_ns, *olen); + size_t odone1 = min(odone, p->samplesLen_ns - p->samplesIndex_ns); + + memcpy(obuf, p->samples + p->samplesIndex_ns, odone1 * sizeof(*obuf)); + if ((p->samplesIndex_ns += odone1) == p->samplesLen_ns) { + memcpy(obuf + odone1, p->samples, (odone - odone1) * sizeof(*obuf)); + p->samplesIndex_ns = odone - odone1; + } + if ((p->flushedLen_ns += odone) == p->samplesLen_ns) { + size_t olen1 = *olen - odone; + (effp->handler.flow = lsx_flow_copy)(effp, ibuf, obuf +odone, ilen, &olen1); + odone += olen1; + } + else *ilen = 0; + *olen = odone; + return SOX_SUCCESS; +} + +static double measure( + priv_t * p, chan_t * c, size_t index_ns, unsigned step_ns, int bootCount) +{ + double mult, result = 0; + size_t i; + + for (i = 0; i < p->measureLen_ws; ++i, index_ns = (index_ns + step_ns) % p->samplesLen_ns) + c->dftBuf[i] = p->samples[index_ns] * p->spectrumWindow[i]; + memset(c->dftBuf + i, 0, (p->dftLen_ws - i) * sizeof(*c->dftBuf)); + lsx_safe_rdft((int)p->dftLen_ws, 1, c->dftBuf); + + memset(c->dftBuf, 0, p->spectrumStart * sizeof(*c->dftBuf)); + for (i = p->spectrumStart; i < p->spectrumEnd; ++i) { + double d = sqrt(sqr(c->dftBuf[2 * i]) + sqr(c->dftBuf[2 * i + 1])); + mult = bootCount >= 0? bootCount / (1. + bootCount) : p->measureTcMult; + c->spectrum[i] = c->spectrum[i] * mult + d * (1 - mult); + d = sqr(c->spectrum[i]); + mult = bootCount >= 0? 0 : + d > c->noiseSpectrum[i]? p->noiseTcUpMult : p->noiseTcDownMult; + c->noiseSpectrum[i] = c->noiseSpectrum[i] * mult + d * (1 - mult); + d = sqrt(max(0, d - p->noiseReductionAmount * c->noiseSpectrum[i])); + c->dftBuf[i] = d * p->cepstrumWindow[i - p->spectrumStart]; + } + memset(c->dftBuf + i, 0, ((p->dftLen_ws >> 1) - i) * sizeof(*c->dftBuf)); + lsx_safe_rdft((int)p->dftLen_ws >> 1, 1, c->dftBuf); + + for (i = p->cepstrumStart; i < p->cepstrumEnd; ++i) + result += sqr(c->dftBuf[2 * i]) + sqr(c->dftBuf[2 * i + 1]); + result = log(result / (p->cepstrumEnd - p->cepstrumStart)); + return max(0, 21 + result); +} + +static int flowTrigger(sox_effect_t * effp, sox_sample_t const * ibuf, + sox_sample_t * obuf, size_t * ilen, size_t * olen) +{ + priv_t * p = (priv_t *)effp->priv; + sox_bool hasTriggered = sox_false; + size_t i, idone = 0, numMeasuresToFlush = 0; + + while (idone < *ilen && !hasTriggered) { + p->measureTimer_ns -= effp->in_signal.channels; + for (i = 0; i < effp->in_signal.channels; ++i, ++idone) { + chan_t * c = &p->channels[i]; + p->samples[p->samplesIndex_ns++] = *ibuf++; + if (!p->measureTimer_ns) { + size_t x = (p->samplesIndex_ns + p->samplesLen_ns - p->measureLen_ns) % p->samplesLen_ns; + double meas = measure(p, c, x, effp->in_signal.channels, p->bootCount); + c->measures[p->measuresIndex] = meas; + c->meanMeas = c->meanMeas * p->triggerMeasTcMult + + meas *(1 - p->triggerMeasTcMult); + + if (hasTriggered |= c->meanMeas >= p->triggerLevel) { + unsigned n = p->measuresLen, k = p->measuresIndex; + unsigned j, jTrigger = n, jZero = n; + for (j = 0; j < n; ++j, k = (k + n - 1) % n) + if (c->measures[k] >= p->triggerLevel && j <= jTrigger + p->gapLen) + jZero = jTrigger = j; + else if (!c->measures[k] && jTrigger >= jZero) + jZero = j; + j = min(j, jZero); + numMeasuresToFlush = range_limit(j, numMeasuresToFlush, n); + } + lsx_debug_more("%12g %12g %u", + meas, c->meanMeas, (unsigned)numMeasuresToFlush); + } + } + if (p->samplesIndex_ns == p->samplesLen_ns) + p->samplesIndex_ns = 0; + if (!p->measureTimer_ns) { + p->measureTimer_ns = p->measurePeriod_ns; + ++p->measuresIndex; + p->measuresIndex %= p->measuresLen; + if (p->bootCount >= 0) + p->bootCount = p->bootCount == p->bootCountMax? -1 : p->bootCount + 1; + } + } + if (hasTriggered) { + size_t ilen1 = *ilen - idone; + p->flushedLen_ns = (p->measuresLen - numMeasuresToFlush) * p->measurePeriod_ns; + p->samplesIndex_ns = (p->samplesIndex_ns + p->flushedLen_ns) % p->samplesLen_ns; + (effp->handler.flow = flowFlush)(effp, ibuf, obuf, &ilen1, olen); + idone += ilen1; + } + else *olen = 0; + *ilen = idone; + return SOX_SUCCESS; +} + +static int drain(sox_effect_t * effp, sox_sample_t * obuf, size_t * olen) +{ + size_t ilen = 0; + return effp->handler.flow(effp, NULL, obuf, &ilen, olen); +} + +static int stop(sox_effect_t * effp) +{ + priv_t * p = (priv_t *)effp->priv; + unsigned i; + + for (i = 0; i < effp->in_signal.channels; ++i) { + chan_t * c = &p->channels[i]; + free(c->measures); + free(c->noiseSpectrum); + free(c->spectrum); + free(c->dftBuf); + } + free(p->channels); + free(p->cepstrumWindow); + free(p->spectrumWindow); + free(p->samples); + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_vad_effect_fn(void) +{ + static sox_effect_handler_t handler = {"vad", NULL, + SOX_EFF_MCHAN | SOX_EFF_LENGTH | SOX_EFF_MODIFY, + create, start, flowTrigger, drain, stop, NULL, sizeof(priv_t) + }; + static char const * lines[] = { + "[options]", + "\t-t trigger-level (7)", + "\t-T trigger-time-constant (0.25 s)", + "\t-s search-time (1 s)", + "\t-g allowed-gap (0.25 s)", + "\t-p pre-trigger-time (0 s)", + "Advanced options:", + "\t-b noise-est-boot-time (0.35 s)", + "\t-N noise-est-time-constant-up (0.1 s)", + "\t-n noise-est-time-constant-down (0.01 s)", + "\t-r noise-reduction-amount (1.35)", + "\t-f measurement-frequency (20 Hz)", + "\t-m measurement-duration (0.1 s)", + "\t-M measurement-time-constant (0.4 s)", + "\t-h high-pass-filter (50 Hz)", + "\t-l low-pass-filter (6000 Hz)", + "\t-H high-pass-lifter (150 Hz)", + "\t-L low-pass-lifter (2000 Hz)", + }; + static char * usage; + handler.usage = lsx_usage_lines(&usage, lines, array_length(lines)); + return &handler; +} diff --git a/app/src/main/cpp/sox/voc.c b/app/src/main/cpp/sox/voc.c new file mode 100644 index 0000000..a75639e --- /dev/null +++ b/app/src/main/cpp/sox/voc.c @@ -0,0 +1,815 @@ +/* libSoX Sound Blaster VOC handler sources. + * Copyright 1991 Lance Norskog And Sundry Contributors + * + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + * + * September 8, 1993 + * Copyright 1993 T. Allen Grider - for changes to support block type 9 + * and word sized samples. Same caveats and disclaimer as above. + * + * February 22, 1996 + * by Chris Bagwell (cbagwell@sprynet.com) + * Added support for block type 8 (extended) which allows for 8-bit stereo + * files. Added support for saving stereo files and 16-bit files. + * Added VOC format info from audio format FAQ so I don't have to keep + * looking around for it. + * + * February 5, 2001 + * For sox-12-17 by Annonymous (see notes ANN) + * Added comments and notes for each procedure. + * Fixed so this now works with pipes, input does not have to + * be seekable anymore (in startread() ) + * Added support for uLAW and aLaw (aLaw not tested). + * Fixed support of multi-part VOC files, and files with + * block 9 but no audio in the block.... + * The following need to be tested: 16-bit, 2 channel, and aLaw. + * + * December 10, 2001 + * For sox-12-17-3 by Annonymous (see notes ANN) + * Patch for sox-12-17 merged with sox-12-17-3-pre3 code. + * + */ + +/*------------------------------------------------------------------------ +The following is taken from the Audio File Formats FAQ dated 2-Jan-1995 +and submitted by Guido van Rossum . +-------------------------------------------------------------------------- +Creative Voice (VOC) file format +-------------------------------- + +From: galt@dsd.es.com + +(byte numbers are hex!) + + HEADER (bytes 00-19) + Series of DATA BLOCKS (bytes 1A+) [Must end w/ Terminator Block] + +- --------------------------------------------------------------- + +HEADER: +------- + byte # Description + ------ ------------------------------------------ + 00-12 "Creative Voice File" + 13 1A (eof to abort printing of file) + 14-15 Offset of first datablock in .voc file (std 1A 00 + in Intel Notation) + 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) + 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) + +- --------------------------------------------------------------- + +DATA BLOCK: +----------- + + Data Block: TYPE(1-byte), SIZE(3-bytes), INFO(0+ bytes) + NOTE: Terminator Block is an exception -- it has only the TYPE byte. + + TYPE Description Size (3-byte int) Info + ---- ----------- ----------------- ----------------------- + 00 Terminator (NONE) (NONE) + 01 Sound data 2+length of data * + 02 Sound continue length of data Voice Data + 03 Silence 3 ** + 04 Marker 2 Marker# (2 bytes) + 05 ASCII length of string null terminated string + 06 Repeat 2 Count# (2 bytes) + 07 End repeat 0 (NONE) + 08 Extended 4 *** + 09 New Header 16 see below + + + *Sound Info Format: **Silence Info Format: + --------------------- ---------------------------- + 00 Sample Rate 00-01 Length of silence - 1 + 01 Compression Type 02 Sample Rate + 02+ Voice Data + + ***Extended Info Format: + --------------------- + 00-01 Time Constant: Mono: 65536 - (256000000/sample_rate) + Stereo: 65536 - (25600000/(2*sample_rate)) + 02 Pack + 03 Mode: 0 = mono + 1 = stereo + + + Marker# -- Driver keeps the most recent marker in a status byte + Count# -- Number of repetitions + 1 + Count# may be 1 to FFFE for 0 - FFFD repetitions + or FFFF for endless repetitions + Sample Rate -- SR byte = 256-(1000000/sample_rate) + Length of silence -- in units of sampling cycle + Compression Type -- of voice data + 8-bits = 0 + 4-bits = 1 + 2.6-bits = 2 + 2-bits = 3 + Multi DAC = 3+(# of channels) [interesting-- + this isn't in the developer's manual] + +Detailed description of new data blocks (VOC files version 1.20 and above): + + (Source is fax from Barry Boone at Creative Labs, 405/742-6622) + +BLOCK 8 - digitized sound attribute extension, must preceed block 1. + Used to define stereo, 8 bit audio + BYTE bBlockID; // = 8 + BYTE nBlockLen[3]; // 3 byte length + WORD wTimeConstant; // time constant = same as block 1 + BYTE bPackMethod; // same as in block 1 + BYTE bVoiceMode; // 0-mono, 1-stereo + + Data is stored left, right + +BLOCK 9 - data block that supersedes blocks 1 and 8. + Used for stereo, 16 bit (and uLaw, aLaw). + + BYTE bBlockID; // = 9 + BYTE nBlockLen[3]; // length 12 plus length of sound + DWORD dwSamplesPerSec; // samples per second, not time const. + BYTE bBitsPerSample; // e.g., 8 or 16 + BYTE bChannels; // 1 for mono, 2 for stereo + WORD wFormat; // see below + BYTE reserved[4]; // pad to make block w/o data + // have a size of 16 bytes + + Valid values of wFormat are: + + 0x0000 8-bit unsigned PCM + 0x0001 Creative 8-bit to 4-bit ADPCM + 0x0002 Creative 8-bit to 3-bit ADPCM + 0x0003 Creative 8-bit to 2-bit ADPCM + 0x0004 16-bit signed PCM + 0x0006 CCITT a-Law + 0x0007 CCITT u-Law + 0x02000 Creative 16-bit to 4-bit ADPCM + + Data is stored left, right + + ANN: Multi-byte quantities are in Intel byte order (Little Endian). + +------------------------------------------------------------------------*/ + +#include "sox_i.h" +#include "g711.h" +#include "adpcms.h" +#include +#include + +/* Private data for VOC file */ +typedef struct { + long block_remaining; /* bytes remaining in current block */ + long rate; /* rate code (byte) of this chunk */ + int silent; /* sound or silence? */ + long srate; /* rate code (byte) of silence */ + size_t blockseek; /* start of current output block */ + long samples; /* number of samples output */ + int format; /* VOC audio format */ + int size; /* word length of data */ + int channels; /* number of sound channels */ + long total_size; /* total size of all audio in file */ + int extended; /* Has an extended block been read? */ + adpcm_t adpcm; +} priv_t; + +#define VOC_TERM 0 +#define VOC_DATA 1 +#define VOC_CONT 2 +#define VOC_SILENCE 3 +#define VOC_MARKER 4 +#define VOC_TEXT 5 +#define VOC_LOOP 6 +#define VOC_LOOPEND 7 +#define VOC_EXTENDED 8 +#define VOC_DATA_16 9 + +/* ANN: Format encoding types */ +#define VOC_FMT_LIN8U 0 /* 8 bit unsigned linear PCM */ +#define VOC_FMT_CRLADPCM4 1 /* Creative 8-bit to 4-bit ADPCM */ +#define VOC_FMT_CRLADPCM3 2 /* Creative 8-bit to 3-bit ADPCM */ +#define VOC_FMT_CRLADPCM2 3 /* Creative 8-bit to 2-bit ADPCM */ +#define VOC_FMT_LIN16 4 /* 16-bit signed PCM */ +#define VOC_FMT_ALAW 6 /* CCITT a-Law 8-bit PCM */ +#define VOC_FMT_MU255 7 /* CCITT u-Law 8-bit PCM */ +#define VOC_FMT_CRLADPCM4A 0x200 /* Creative 16-bit to 4-bit ADPCM */ + +/* Prototypes for internal functions */ +static int getblock(sox_format_t *); +static void blockstart(sox_format_t *); + +/* Conversion macros (from raw.c) */ +#define SOX_ALAW_BYTE_TO_SAMPLE(d) ((sox_sample_t)(sox_alaw2linear16(d)) << 16) +#define SOX_ULAW_BYTE_TO_SAMPLE(d) ((sox_sample_t)(sox_ulaw2linear16(d)) << 16) + +/* public VOC functions for SOX */ + +/*----------------------------------------------------------------- + * startread() -- start reading a VOC file + *-----------------------------------------------------------------*/ +static int startread(sox_format_t * ft) +{ + char header[20]; + priv_t * v = (priv_t *) ft->priv; + unsigned short sbseek; + int rc; + int ii; /* for getting rid of lseek */ + unsigned char uc; + + if (lsx_readbuf(ft, header, (size_t)20) != 20) { + lsx_fail_errno(ft, SOX_EHDR, "unexpected EOF in VOC header"); + return (SOX_EOF); + } + if (strncmp(header, "Creative Voice File\032", (size_t)19)) { + lsx_fail_errno(ft, SOX_EHDR, "VOC file header incorrect"); + return (SOX_EOF); + } + + /* read the offset to data, from start of file */ + /* after this read we have read 20 bytes of header + 2 */ + lsx_readw(ft, &sbseek); + + /* ANN: read to skip the header, instead of lseek */ + /* this should allow use with pipes.... */ + for (ii = 22; ii < sbseek; ii++) + lsx_readb(ft, &uc); + + v->rate = -1; + v->format = -1; + v->channels = -1; + v->block_remaining = 0; + v->total_size = 0; /* ANN added */ + v->extended = 0; + + /* read until we get the format information.... */ + rc = getblock(ft); + if (rc) + return rc; + + /* get rate of data */ + if (v->rate == -1) { + lsx_fail_errno(ft, SOX_EOF, "Input .voc file had no sound!"); + return (SOX_EOF); + } + + /* setup word length of data */ + + /* ANN: Check VOC format and map to the proper libSoX format value */ + switch (v->format) { + case VOC_FMT_LIN8U: /* 0 8 bit unsigned linear PCM */ + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + v->size = 8; + break; + case VOC_FMT_CRLADPCM4: /* 1 Creative 8-bit to 4-bit ADPCM */ + ft->encoding.encoding = SOX_ENCODING_CL_ADPCM; + v->size = 4; + break; + case VOC_FMT_CRLADPCM3: /* 2 Creative 8-bit to 3-bit ADPCM */ + ft->encoding.encoding = SOX_ENCODING_CL_ADPCM; + v->size = 3; + break; + case VOC_FMT_CRLADPCM2: /* 3 Creative 8-bit to 2-bit ADPCM */ + ft->encoding.encoding = SOX_ENCODING_CL_ADPCM; + v->size = 2; + break; + case VOC_FMT_LIN16: /* 4 16-bit signed PCM */ + ft->encoding.encoding = SOX_ENCODING_SIGN2; + v->size = 16; + break; + case VOC_FMT_ALAW: /* 6 CCITT a-Law 8-bit PCM */ + ft->encoding.encoding = SOX_ENCODING_ALAW; + v->size = 8; + break; + case VOC_FMT_MU255: /* 7 CCITT u-Law 8-bit PCM */ + ft->encoding.encoding = SOX_ENCODING_ULAW; + v->size = 8; + break; + case VOC_FMT_CRLADPCM4A: /*0x200 Creative 16-bit to 4-bit ADPCM */ + ft->encoding.encoding = SOX_ENCODING_CL_ADPCM16; + v->size = 4; + break; + default: + lsx_fail("Unknown VOC format %d", v->format); + break; + } + ft->encoding.bits_per_sample = v->size; + + /* setup number of channels */ + if (ft->signal.channels == 0) + ft->signal.channels = v->channels; + + return (SOX_SUCCESS); +} + +/*----------------------------------------------------------------- + * read() -- read data from a VOC file + * ANN: Major changes here to support multi-part files and files + * that do not have audio in block 9's. + *-----------------------------------------------------------------*/ +static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, + size_t len) +{ + priv_t * v = (priv_t *) ft->priv; + size_t done = 0; + int rc = 0; + int16_t sw; + unsigned char uc; + + if (v->block_remaining == 0) { /* handle getting another cont. buffer */ + rc = getblock(ft); + if (rc) + return 0; + } + + if (v->block_remaining == 0) /* if no more data, return 0, i.e., done */ + return 0; + + if (v->silent) { + for (; v->block_remaining && (done < len); v->block_remaining--, done++) + *buf++ = 0; /* Fill in silence */ + } else { /* not silence; read len samples of audio from the file */ + size_t per = max(1, 9 / v->size); + + for (; (done + per <= len); done += per) { + if (v->block_remaining == 0) { /* IF no more in this block, get another */ + while (v->block_remaining == 0) { /* until have either EOF or a block with data */ + rc = getblock(ft); + if (rc) + break; + } + if (rc) /* IF EOF, break out, no more data, next will return 0 */ + break; + } + + /* Read the data in the file */ + if (v->size <= 4) { + if (!v->adpcm.setup.sign) { + SOX_SAMPLE_LOCALS; + if (lsx_readb(ft, &uc) == SOX_EOF) { + lsx_warn("VOC input: short file"); + v->block_remaining = 0; + return done; + } + *buf = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc,); + lsx_adpcm_init(&v->adpcm, 6 - v->size, SOX_SAMPLE_TO_SIGNED_16BIT(*buf, ft->clips)); + ++buf; + --v->block_remaining; + ++done; + } + if (lsx_readb(ft, &uc) == SOX_EOF) { + lsx_warn("VOC input: short file"); + v->block_remaining = 0; + return done; + } + switch (v->size) { + case 2: + if (v->format == VOC_FMT_CRLADPCM2) { + int u = uc; + + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u >> 6, &v->adpcm),); + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u >> 4, &v->adpcm),); + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u >> 2, &v->adpcm),); + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u , &v->adpcm),); + } + break; + case 3: + if (v->format == VOC_FMT_CRLADPCM3) { + int u = uc; + + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u >> 5, &v->adpcm),); + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u >> 2, &v->adpcm),); + *buf++ = /* A bit from nowhere! */ + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u << 1, &v->adpcm),); + } + break; + case 4: + if (v->format == VOC_FMT_CRLADPCM4) { + int u = uc; + + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u >> 4, &v->adpcm),); + *buf++ = + SOX_SIGNED_16BIT_TO_SAMPLE(lsx_adpcm_decode (u , &v->adpcm),); + } + break; + } + } else + switch (v->size) { + case 8: + if (lsx_readb(ft, &uc) == SOX_EOF) { + lsx_warn("VOC input: short file"); + v->block_remaining = 0; + return done; + } + if (v->format == VOC_FMT_MU255) { + *buf++ = SOX_ULAW_BYTE_TO_SAMPLE(uc); + } else if (v->format == VOC_FMT_ALAW) { + *buf++ = SOX_ALAW_BYTE_TO_SAMPLE(uc); + } else { + *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc,); + } + break; + case 16: + lsx_readsw(ft, &sw); + if (lsx_eof(ft)) { + lsx_warn("VOC input: short file"); + v->block_remaining = 0; + return done; + } + *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(sw,); + v->block_remaining--; /* Processed 2 bytes so update */ + break; + } + /* decrement count of processed bytes */ + v->block_remaining--; + } + } + v->total_size += done; + return done; +} + + +/* When saving samples in VOC format the following outline is followed: + * If an 8-bit mono sample then use a VOC_DATA header. + * If an 8-bit stereo sample then use a VOC_EXTENDED header followed + * by a VOC_DATA header. + * If a 16-bit sample (either stereo or mono) then save with a + * VOC_DATA_16 header. + * + * ANN: Not supported: uLaw and aLaw output VOC files.... + * + * This approach will cause the output to be an its most basic format + * which will work with the oldest software (eg. an 8-bit mono sample + * will be able to be played with a really old SB VOC player.) + */ +static int startwrite(sox_format_t * ft) +{ + priv_t * v = (priv_t *) ft->priv; + + if (!ft->seekable) { + lsx_fail_errno(ft, SOX_EOF, + "Output .voc file must be a file, not a pipe"); + return (SOX_EOF); + } + + v->samples = 0; + + /* File format name and a ^Z (aborts printing under DOS) */ + lsx_writes(ft, "Creative Voice File\032"); + lsx_writew(ft, 26); /* size of header */ + lsx_writew(ft, 0x10a); /* major/minor version number */ + lsx_writew(ft, 0x1129); /* checksum of version number */ + + return (SOX_SUCCESS); +} + +/*----------------------------------------------------------------- + * write() -- write a VOC file + *-----------------------------------------------------------------*/ +static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, + size_t len) +{ + priv_t * v = (priv_t *) ft->priv; + unsigned char uc; + int16_t sw; + size_t done = 0; + + if (len && v->samples == 0) { + /* No silence packing yet. */ + v->silent = 0; + blockstart(ft); + } + v->samples += len; + while (done < len) { + SOX_SAMPLE_LOCALS; + if (ft->encoding.bits_per_sample == 8) { + uc = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips); + lsx_writeb(ft, uc); + } else { + sw = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips); + lsx_writesw(ft, sw); + } + done++; + } + return done; +} + +/*----------------------------------------------------------------- + * blockstop() -- stop an output block + * End the current data or silence block. + *-----------------------------------------------------------------*/ +static void blockstop(sox_format_t * ft) +{ + priv_t * v = (priv_t *) ft->priv; + sox_sample_t datum; + + lsx_writeb(ft, 0); /* End of file block code */ + lsx_seeki(ft, (off_t) v->blockseek, 0); /* seek back to block length */ + lsx_seeki(ft, (off_t)1, 1); /* seek forward one */ + if (v->silent) { + lsx_writesw(ft, (signed)v->samples); + } else { + if (ft->encoding.bits_per_sample == 8) { + if (ft->signal.channels > 1) { + lsx_seeki(ft, (off_t)8, 1); /* forward 7 + 1 for new block header */ + } + } + v->samples += 2; /* adjustment: SBDK pp. 3-5 */ + datum = (v->samples * (ft->encoding.bits_per_sample >> 3)) & 0xff; + lsx_writesb(ft, datum); /* low byte of length */ + datum = ((v->samples * (ft->encoding.bits_per_sample >> 3)) >> 8) & 0xff; + lsx_writesb(ft, datum); /* middle byte of length */ + datum = ((v->samples * (ft->encoding.bits_per_sample >> 3)) >> 16) & 0xff; + lsx_writesb(ft, datum); /* high byte of length */ + } +} + +/*----------------------------------------------------------------- + * stopwrite() -- stop writing a VOC file + *-----------------------------------------------------------------*/ +static int stopwrite(sox_format_t * ft) +{ + blockstop(ft); + return (SOX_SUCCESS); +} + +/*----------------------------------------------------------------- + * Voc-file handlers (static, private to this module) + *-----------------------------------------------------------------*/ + +/*----------------------------------------------------------------- + * getblock() -- Read next block header, save info, + * leave position at start of dat + *-----------------------------------------------------------------*/ +static int getblock(sox_format_t * ft) +{ + priv_t * v = (priv_t *) ft->priv; + unsigned char uc, block; + uint16_t u16; + sox_uint24_t sblen; + uint16_t new_rate_16; + uint32_t new_rate_32; + + v->silent = 0; + /* DO while we have no audio to read */ + while (v->block_remaining == 0) { + if (lsx_eof(ft)) + return SOX_EOF; + + if (lsx_readb(ft, &block) == SOX_EOF) + return SOX_EOF; + + if (block == VOC_TERM) + return SOX_EOF; + + if (lsx_eof(ft)) + return SOX_EOF; + + lsx_read3(ft, &sblen); + + /* Based on VOC block type, process the block */ + /* audio may be in one or multiple blocks */ + switch (block) { + case VOC_DATA: + lsx_readb(ft, &uc); + /* When DATA block preceeded by an EXTENDED */ + /* block, the DATA blocks rate value is invalid */ + if (!v->extended) { + if (uc == 0) { + lsx_fail_errno(ft, SOX_EFMT, "Sample rate is zero?"); + return (SOX_EOF); + } + if ((v->rate != -1) && (uc != v->rate)) { + lsx_fail_errno(ft, SOX_EFMT, + "sample rate codes differ: %ld != %d", v->rate, + uc); + return (SOX_EOF); + } + v->rate = uc; + ft->signal.rate = 1000000.0 / (256 - v->rate); + if (v->channels != -1 && v->channels != 1) { + lsx_fail_errno(ft, SOX_EFMT, "channel count changed"); + return SOX_EOF; + } + v->channels = 1; + } + lsx_readb(ft, &uc); + if (v->format != -1 && uc != v->format) { + lsx_fail_errno(ft, SOX_EFMT, "format changed"); + return SOX_EOF; + } + v->format = uc; + v->extended = 0; + v->block_remaining = sblen - 2; + return (SOX_SUCCESS); + case VOC_DATA_16: + lsx_readdw(ft, &new_rate_32); + if (new_rate_32 == 0) { + lsx_fail_errno(ft, SOX_EFMT, "Sample rate is zero?"); + return (SOX_EOF); + } + if ((v->rate != -1) && ((long) new_rate_32 != v->rate)) { + lsx_fail_errno(ft, SOX_EFMT, "sample rate codes differ: %ld != %d", + v->rate, new_rate_32); + return (SOX_EOF); + } + v->rate = new_rate_32; + ft->signal.rate = new_rate_32; + lsx_readb(ft, &uc); + v->size = uc; + lsx_readb(ft, &uc); + if (v->channels != -1 && uc != v->channels) { + lsx_fail_errno(ft, SOX_EFMT, "channel count changed"); + return SOX_EOF; + } + v->channels = uc; + lsx_readw(ft, &u16); /* ANN: added format */ + if (v->format != -1 && u16 != v->format) { + lsx_fail_errno(ft, SOX_EFMT, "format changed"); + return SOX_EOF; + } + v->format = u16; + lsx_skipbytes(ft, (size_t) 4); + v->block_remaining = sblen - 12; + return (SOX_SUCCESS); + case VOC_CONT: + v->block_remaining = sblen; + return (SOX_SUCCESS); + case VOC_SILENCE: + { + unsigned short period; + + lsx_readw(ft, &period); + lsx_readb(ft, &uc); + if (uc == 0) { + lsx_fail_errno(ft, SOX_EFMT, "Silence sample rate is zero"); + return (SOX_EOF); + } + /* + * Some silence-packed files have gratuitously + * different sample rate codes in silence. + * Adjust period. + */ + if ((v->rate != -1) && (uc != v->rate)) + period = (period * (256. - uc)) / (256 - v->rate) + .5; + else + v->rate = uc; + v->block_remaining = period; + v->silent = 1; + return (SOX_SUCCESS); + } + case VOC_MARKER: + lsx_readb(ft, &uc); + lsx_readb(ft, &uc); + /* Falling! Falling! */ + case VOC_TEXT: + { + uint32_t i = sblen; + int8_t c /*, line_buf[80]; + * int len = 0 */ ; + + lsx_warn("VOC TEXT"); + while (i--) { + lsx_readsb(ft, &c); + /* FIXME: this needs to be tested but I couldn't + * find a voc file with a VOC_TEXT chunk :( + if (c != '\0' && c != '\r') + line_buf[len++] = c; + if (len && (c == '\0' || c == '\r' || + i == 0 || len == sizeof(line_buf) - 1)) + { + lsx_report("%s", line_buf); + line_buf[len] = '\0'; + len = 0; + } + */ + } + } + continue; /* get next block */ + case VOC_LOOP: + case VOC_LOOPEND: + lsx_debug("skipping repeat loop"); + lsx_skipbytes(ft, (size_t) sblen); + break; + case VOC_EXTENDED: + /* An Extended block is followed by a data block */ + /* Set this byte so we know to use the rate */ + /* value from the extended block and not the */ + /* data block. */ + v->extended = 1; + lsx_readw(ft, &new_rate_16); + if (new_rate_16 == 0) { + lsx_fail_errno(ft, SOX_EFMT, "Sample rate is zero?"); + return (SOX_EOF); + } + if ((v->rate != -1) && (new_rate_16 != v->rate)) { + lsx_fail_errno(ft, SOX_EFMT, "sample rate codes differ: %ld != %d", + v->rate, new_rate_16); + return (SOX_EOF); + } + v->rate = new_rate_16; + lsx_readb(ft, &uc); /* bits_per_sample */ + lsx_readb(ft, &uc); + if (v->channels != -1 && uc != v->channels) { + lsx_fail_errno(ft, SOX_EFMT, "channel count changed"); + return SOX_EOF; + } + v->channels = uc; + ft->signal.channels = uc? 2 : 1; /* Stereo */ + /* Needed number of channels before finishing + * compute for rate */ + ft->signal.rate = (256e6 / (65536 - v->rate)) / ft->signal.channels; + /* An extended block must be followed by a data */ + /* block to be valid so loop back to top so it */ + /* can be grabed. */ + continue; + default: + lsx_debug("skipping unknown block code %d", block); + lsx_skipbytes(ft, (size_t) sblen); + } + } + return SOX_SUCCESS; +} + +/*----------------------------------------------------------------- + * vlockstart() -- start an output block + *-----------------------------------------------------------------*/ +static void blockstart(sox_format_t * ft) +{ + priv_t * v = (priv_t *) ft->priv; + + v->blockseek = lsx_tell(ft); + if (v->silent) { + lsx_writeb(ft, VOC_SILENCE); /* Silence block code */ + lsx_writeb(ft, 0); /* Period length */ + lsx_writeb(ft, 0); /* Period length */ + lsx_writesb(ft, (signed)v->rate); /* Rate code */ + } else { + if (ft->encoding.bits_per_sample == 8) { + /* 8-bit sample section. By always setting the correct */ + /* rate value in the DATA block (even when its preceeded */ + /* by an EXTENDED block) old software can still play stereo */ + /* files in mono by just skipping over the EXTENDED block. */ + /* Prehaps the rate should be doubled though to make up for */ + /* double amount of samples for a given time???? */ + if (ft->signal.channels > 1) { + lsx_writeb(ft, VOC_EXTENDED); /* Voice Extended block code */ + lsx_writeb(ft, 4); /* block length = 4 */ + lsx_writeb(ft, 0); /* block length = 4 */ + lsx_writeb(ft, 0); /* block length = 4 */ + v->rate = 65536 - (256000000.0 / (2 * ft->signal.rate)) + .5; + lsx_writesw(ft, (signed) v->rate); /* Rate code */ + lsx_writeb(ft, 0); /* File is not packed */ + lsx_writeb(ft, 1); /* samples are in stereo */ + } + lsx_writeb(ft, VOC_DATA); /* Voice Data block code */ + lsx_writeb(ft, 0); /* block length (for now) */ + lsx_writeb(ft, 0); /* block length (for now) */ + lsx_writeb(ft, 0); /* block length (for now) */ + v->rate = 256 - (1000000.0 / ft->signal.rate) + .5; + lsx_writesb(ft, (signed) v->rate); /* Rate code */ + lsx_writeb(ft, 0); /* 8-bit raw data */ + } else { + lsx_writeb(ft, VOC_DATA_16); /* Voice Data block code */ + lsx_writeb(ft, 0); /* block length (for now) */ + lsx_writeb(ft, 0); /* block length (for now) */ + lsx_writeb(ft, 0); /* block length (for now) */ + v->rate = ft->signal.rate + .5; + lsx_writedw(ft, (unsigned) v->rate); /* Rate code */ + lsx_writeb(ft, 16); /* Sample Size */ + lsx_writeb(ft, ft->signal.channels); /* Sample Size */ + lsx_writew(ft, 0x0004); /* Encoding */ + lsx_writeb(ft, 0); /* Unused */ + lsx_writeb(ft, 0); /* Unused */ + lsx_writeb(ft, 0); /* Unused */ + lsx_writeb(ft, 0); /* Unused */ + } + } +} + +LSX_FORMAT_HANDLER(voc) +{ + static char const *const names[] = { "voc", NULL }; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 0, + SOX_ENCODING_UNSIGNED, 8, 0, + 0 + }; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Creative Technology Sound Blaster format", + names, SOX_FILE_LIT_END | SOX_FILE_MONO | SOX_FILE_STEREO, + startread, read_samples, NULL, + startwrite, write_samples, stopwrite, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/vol.c b/app/src/main/cpp/sox/vol.c new file mode 100644 index 0000000..9eb3a2a --- /dev/null +++ b/app/src/main/cpp/sox/vol.c @@ -0,0 +1,184 @@ +/* Copyright (c) 20/03/2000 Fabien COELHO + * Copyright (c) 2000-2007 SoX contributors + * + * SoX vol effect; change volume with basic linear amplitude formula. + * Beware of saturations! Clipping is checked and reported. + * + * FIXME: deprecate or remove the limiter in favour of compand. + */ +#define vol_usage \ + "GAIN [TYPE [LIMITERGAIN]]\n" \ + "\t(default TYPE=amplitude: 1 is constant, < 0 change phase;\n" \ + "\tTYPE=power 1 is constant; TYPE=dB: 0 is constant, +6 doubles ampl.)\n" \ + "\tThe peak limiter has a gain much less than 1 (e.g. 0.05 or 0.02) and\n" \ + "\tis only used on peaks (to prevent clipping); default is no limiter." + +#include "sox_i.h" + +typedef struct { + double gain; /* amplitude gain. */ + sox_bool uselimiter; + double limiterthreshhold; + double limitergain; + uint64_t limited; /* number of limited values to report. */ + uint64_t totalprocessed; +} priv_t; + +enum {vol_amplitude, vol_dB, vol_power}; + +static lsx_enum_item const vol_types[] = { + LSX_ENUM_ITEM(vol_,amplitude) + LSX_ENUM_ITEM(vol_,dB) + LSX_ENUM_ITEM(vol_,power) + {0, 0}}; + +/* + * Process options: gain (float) type (amplitude, power, dB) + */ +static int getopts(sox_effect_t * effp, int argc, char **argv) +{ + priv_t * vol = (priv_t *) effp->priv; + char type_string[11]; + char * type_ptr = type_string; + char dummy; /* To check for extraneous chars. */ + sox_bool have_type; + --argc, ++argv; + + vol->gain = 1; /* Default is no change. */ + vol->uselimiter = sox_false; /* Default is no limiter. */ + + /* Get the vol, and the type if it's in the same arg. */ + if (!argc || (have_type = sscanf(argv[0], "%lf %10s %c", &vol->gain, type_string, &dummy) - 1) > 1) + return lsx_usage(effp); + ++argv, --argc; + + /* No type yet? Get it from the next arg: */ + if (!have_type && argc) { + have_type = sox_true; + type_ptr = *argv; + ++argv, --argc; + } + + if (have_type) { + lsx_enum_item const * p = lsx_find_enum_text(type_ptr, vol_types, 0); + if (!p) + return lsx_usage(effp); + switch (p->value) { + case vol_dB: vol->gain = dB_to_linear(vol->gain); break; + case vol_power: /* power to amplitude, keep phase change */ + vol->gain = vol->gain > 0 ? sqrt(vol->gain) : -sqrt(-vol->gain); + break; + } + } + + if (argc) { + if (fabs(vol->gain) < 1 || sscanf(*argv, "%lf %c", &vol->limitergain, &dummy) != 1 || vol->limitergain <= 0 || vol->limitergain >= 1) + return lsx_usage(effp); + + vol->uselimiter = sox_true; + /* The following equation is derived so that there is no + * discontinuity in output amplitudes */ + /* and a SOX_SAMPLE_MAX input always maps to a SOX_SAMPLE_MAX output + * when the limiter is activated. */ + /* (NOTE: There **WILL** be a discontinuity in the slope + * of the output amplitudes when using the limiter.) */ + vol->limiterthreshhold = SOX_SAMPLE_MAX * (1.0 - vol->limitergain) / (fabs(vol->gain) - vol->limitergain); + } + lsx_debug("mult=%g limit=%g", vol->gain, vol->limitergain); + return SOX_SUCCESS; +} + +/* + * Start processing + */ +static int start(sox_effect_t * effp) +{ + priv_t * vol = (priv_t *) effp->priv; + + if (vol->gain == 1) + return SOX_EFF_NULL; + + vol->limited = 0; + vol->totalprocessed = 0; + + return SOX_SUCCESS; +} + +/* + * Process data. + */ +static int flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf, + size_t *isamp, size_t *osamp) +{ + priv_t * vol = (priv_t *) effp->priv; + register double gain = vol->gain; + register double limiterthreshhold = vol->limiterthreshhold; + register double sample; + register size_t len; + + len = min(*osamp, *isamp); + + /* report back dealt with amount. */ + *isamp = len; *osamp = len; + + if (vol->uselimiter) + { + vol->totalprocessed += len; + + for (;len>0; len--) + { + sample = *ibuf++; + + if (sample > limiterthreshhold) + { + sample = (SOX_SAMPLE_MAX - vol->limitergain * (SOX_SAMPLE_MAX - sample)); + vol->limited++; + } + else if (sample < -limiterthreshhold) + { + sample = -(SOX_SAMPLE_MAX - vol->limitergain * (SOX_SAMPLE_MAX + sample)); + /* FIXME: MIN is (-MAX)-1 so need to make sure we + * don't go over that. Probably could do this + * check inside the above equation but I didn't + * think it thru. + */ + if (sample < SOX_SAMPLE_MIN) + sample = SOX_SAMPLE_MIN; + vol->limited++; + } else + sample = gain * sample; + + SOX_SAMPLE_CLIP_COUNT(sample, effp->clips); + *obuf++ = sample; + } + } + else + { + /* quite basic, with clipping */ + for (;len>0; len--) + { + sample = gain * *ibuf++; + SOX_SAMPLE_CLIP_COUNT(sample, effp->clips); + *obuf++ = sample; + } + } + return SOX_SUCCESS; +} + +static int stop(sox_effect_t * effp) +{ + priv_t * vol = (priv_t *) effp->priv; + if (vol->limited) { + lsx_warn("limited %" PRIu64 " values (%d percent).", + vol->limited, (int) (vol->limited * 100.0 / vol->totalprocessed)); + } + return SOX_SUCCESS; +} + +sox_effect_handler_t const * lsx_vol_effect_fn(void) +{ + static sox_effect_handler_t handler = { + "vol", vol_usage, SOX_EFF_MCHAN | SOX_EFF_GAIN, getopts, start, flow, 0, stop, 0, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/vorbis.c b/app/src/main/cpp/sox/vorbis.c new file mode 100644 index 0000000..9fa234c --- /dev/null +++ b/app/src/main/cpp/sox/vorbis.c @@ -0,0 +1,429 @@ +/* libSoX Ogg Vorbis sound format handler + * Copyright 2001, Stan Seibert + * + * Portions from oggenc, (c) Michael Smith , + * ogg123, (c) Kenneth Arnold , and + * libvorbisfile (c) Xiphophorus Company + * + * May 9, 2001 - Stan Seibert (indigo@aztec.asu.edu) + * Ogg Vorbis handler initially written. + * + * July 5, 1991 - Skeleton file + * Copyright 1991 Lance Norskog And Sundry Contributors + * This source code is freely redistributable and may be used for + * any purpose. This copyright notice must be maintained. + * Lance Norskog And Sundry Contributors are not responsible for + * the consequences of using this software. + */ + +#include "sox_i.h" + +#include +#include +#include + +#include +#include +#include +#include + +#define DEF_BUF_LEN 4096 + +#define BUF_ERROR -1 +#define BUF_EOF 0 +#define BUF_DATA 1 + +#define HEADER_ERROR 0 +#define HEADER_OK 1 + +/* Private data for Ogg Vorbis file */ +typedef struct { + ogg_stream_state os; + ogg_page og; + ogg_packet op; + + vorbis_dsp_state vd; + vorbis_block vb; + vorbis_info vi; +} vorbis_enc_t; + +typedef struct { + /* Decoding data */ + OggVorbis_File *vf; + char *buf; + size_t buf_len; + size_t start; + size_t end; /* Unsent data samples in buf[start] through buf[end-1] */ + int current_section; + int eof; + + vorbis_enc_t *vorbis_enc_data; +} priv_t; + +/******** Callback functions used in ov_open_callbacks ************/ + +static size_t callback_read(void* ptr, size_t size, size_t nmemb, void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + size_t ret = lsx_readbuf(ft, ptr, size * nmemb); + return ret / size; +} + +static int callback_seek(void* ft_data, ogg_int64_t off, int whence) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + int ret = ft->seekable ? lsx_seeki(ft, (off_t)off, whence) : -1; + + if (ret == EBADF) + ret = -1; + return ret; +} + +static int callback_close(void* ft_data UNUSED) +{ + /* Do nothing so sox can close the file for us */ + return 0; +} + +static long callback_tell(void* ft_data) +{ + sox_format_t* ft = (sox_format_t*)ft_data; + return lsx_tell(ft); +} + +/********************* End callbacks *****************************/ + + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int startread(sox_format_t * ft) +{ + priv_t * vb = (priv_t *) ft->priv; + vorbis_info *vi; + vorbis_comment *vc; + int i; + + ov_callbacks callbacks = { + callback_read, + callback_seek, + callback_close, + callback_tell + }; + + /* Allocate space for decoding structure */ + vb->vf = lsx_malloc(sizeof(OggVorbis_File)); + + /* Init the decoder */ + if (ov_open_callbacks(ft, vb->vf, NULL, (size_t) 0, callbacks) < 0) { + lsx_fail_errno(ft, SOX_EHDR, "Input not an Ogg Vorbis audio stream"); + return (SOX_EOF); + } + + /* Get info about the Ogg Vorbis stream */ + vi = ov_info(vb->vf, -1); + vc = ov_comment(vb->vf, -1); + + /* Record audio info */ + ft->signal.rate = vi->rate; + ft->encoding.encoding = SOX_ENCODING_VORBIS; + ft->signal.channels = vi->channels; + + /* ov_pcm_total doesn't work on non-seekable files so + * skip that step in that case. Also, it reports + * "frame"-ish results so we must * channels. + */ + if (ft->seekable) + ft->signal.length = ov_pcm_total(vb->vf, -1) * ft->signal.channels; + + /* Record comments */ + for (i = 0; i < vc->comments; i++) + sox_append_comment(&ft->oob.comments, vc->user_comments[i]); + + /* Setup buffer */ + vb->buf_len = DEF_BUF_LEN; + vb->buf_len -= vb->buf_len % (vi->channels*2); /* 2 bytes per sample */ + vb->buf = lsx_calloc(vb->buf_len, sizeof(char)); + vb->start = vb->end = 0; + + /* Fill in other info */ + vb->eof = 0; + vb->current_section = -1; + + return (SOX_SUCCESS); +} + + +/* Refill the buffer with samples. Returns BUF_EOF if the end of the + * vorbis data was reached while the buffer was being filled, + * BUF_ERROR is something bad happens, and BUF_DATA otherwise */ +static int refill_buffer(priv_t * vb) +{ + int num_read; + + if (vb->start == vb->end) /* Samples all played */ + vb->start = vb->end = 0; + + while (vb->end < vb->buf_len) { + num_read = ov_read(vb->vf, vb->buf + vb->end, + (int) (vb->buf_len - vb->end), 0, 2, 1, &vb->current_section); + if (num_read == 0) + return (BUF_EOF); + else if (num_read == OV_HOLE) + lsx_warn("Warning: hole in stream; probably harmless"); + else if (num_read < 0) + return (BUF_ERROR); + else + vb->end += num_read; + } + return (BUF_DATA); +} + + +/* + * Read up to len samples from file. + * Convert to signed longs. + * Place in buf[]. + * Return number of samples read. + */ + +static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + priv_t * vb = (priv_t *) ft->priv; + size_t i; + int ret; + sox_sample_t l; + + + for (i = 0; i < len; i++) { + if (vb->start == vb->end) { + if (vb->eof) + break; + ret = refill_buffer(vb); + if (ret == BUF_EOF || ret == BUF_ERROR) { + vb->eof = 1; + if (vb->end == 0) + break; + } + } + + l = (vb->buf[vb->start + 1] << 24) + | (0xffffff & (vb->buf[vb->start] << 16)); + *(buf + i) = l; + vb->start += 2; + } + return i; +} + +/* + * Do anything required when you stop reading samples. + * Don't close input file! + */ +static int stopread(sox_format_t * ft) +{ + priv_t * vb = (priv_t *) ft->priv; + + free(vb->buf); + ov_clear(vb->vf); + + return (SOX_SUCCESS); +} + +/* Write a page of ogg data to a file. Taken directly from encode.c in + * oggenc. Returns the number of bytes written. */ +static int oe_write_page(ogg_page * page, sox_format_t * ft) +{ + int written; + + written = lsx_writebuf(ft, page->header, (size_t) page->header_len); + written += lsx_writebuf(ft, page->body, (size_t) page->body_len); + + return written; +} + +/* Write out the header packets. Derived mostly from encode.c in oggenc. + * Returns HEADER_OK if the header can be written, HEADER_ERROR otherwise. */ +static int write_vorbis_header(sox_format_t * ft, vorbis_enc_t * ve) +{ + ogg_packet header_main; + ogg_packet header_comments; + ogg_packet header_codebooks; + vorbis_comment vc; + int i, ret = HEADER_OK; + + memset(&vc, 0, sizeof(vc)); + vc.comments = sox_num_comments(ft->oob.comments); + if (vc.comments) { /* Make the comment structure */ + vc.comment_lengths = lsx_calloc((size_t)vc.comments, sizeof(*vc.comment_lengths)); + vc.user_comments = lsx_calloc((size_t)vc.comments, sizeof(*vc.user_comments)); + for (i = 0; i < vc.comments; ++i) { + static const char prepend[] = "Comment="; + char * text = lsx_calloc(strlen(prepend) + strlen(ft->oob.comments[i]) + 1, sizeof(*text)); + /* Prepend `Comment=' if no field-name already in the comment */ + if (!strchr(ft->oob.comments[i], '=')) + strcpy(text, prepend); + vc.user_comments[i] = strcat(text, ft->oob.comments[i]); + vc.comment_lengths[i] = strlen(text); + } + } + if (vorbis_analysis_headerout( /* Build the packets */ + &ve->vd, &vc, &header_main, &header_comments, &header_codebooks) < 0) { + ret = HEADER_ERROR; + goto cleanup; + } + + ogg_stream_packetin(&ve->os, &header_main); /* And stream them out */ + ogg_stream_packetin(&ve->os, &header_comments); + ogg_stream_packetin(&ve->os, &header_codebooks); + + while (ogg_stream_flush(&ve->os, &ve->og) && ret == HEADER_OK) + if (!oe_write_page(&ve->og, ft)) + ret = HEADER_ERROR; +cleanup: + for (i = 0; i < vc.comments; ++i) + free(vc.user_comments[i]); + free(vc.user_comments); + free(vc.comment_lengths); + return ret; +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * vb = (priv_t *) ft->priv; + vorbis_enc_t *ve; + long rate; + double quality = 3; /* Default compression quality gives ~112kbps */ + + ft->encoding.encoding = SOX_ENCODING_VORBIS; + + /* Allocate memory for all of the structures */ + ve = vb->vorbis_enc_data = lsx_malloc(sizeof(vorbis_enc_t)); + + vorbis_info_init(&ve->vi); + + /* TODO */ + rate = ft->signal.rate; + if (rate) + lsx_fail_errno(ft, SOX_EHDR, + "Error setting-up Ogg Vorbis encoder; check sample-rate & # of channels"); + + /* Use encoding to average bit rate of VBR as specified by the -C option */ + if (ft->encoding.compression != HUGE_VAL) { + if (ft->encoding.compression < -1 || ft->encoding.compression > 10) { + lsx_fail_errno(ft, SOX_EINVAL, + "Vorbis compression quality nust be between -1 and 10"); + return SOX_EOF; + } + quality = ft->encoding.compression; + } + + if (vorbis_encode_init_vbr(&ve->vi, ft->signal.channels, ft->signal.rate + .5, quality / 10)) + { + lsx_fail_errno(ft, SOX_EFMT, "libVorbis cannot encode this sample-rate or # of channels"); + return SOX_EOF; + } + + vorbis_analysis_init(&ve->vd, &ve->vi); + vorbis_block_init(&ve->vd, &ve->vb); + + ogg_stream_init(&ve->os, INT_MAX & (int)RANQD1); /* Random serial number */ + + if (write_vorbis_header(ft, ve) == HEADER_ERROR) { + lsx_fail_errno(ft, SOX_EHDR, + "Error writing header for Ogg Vorbis audio stream"); + return (SOX_EOF); + } + + return (SOX_SUCCESS); +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, + size_t len) +{ + priv_t * vb = (priv_t *) ft->priv; + vorbis_enc_t *ve = vb->vorbis_enc_data; + size_t samples = len / ft->signal.channels; + float **buffer = vorbis_analysis_buffer(&ve->vd, (int) samples); + size_t i, j; + int ret; + int eos = 0; + + /* Copy samples into vorbis buffer */ + for (i = 0; i < samples; i++) + for (j = 0; j < ft->signal.channels; j++) + buffer[j][i] = buf[i * ft->signal.channels + j] + / ((float) SOX_SAMPLE_MAX); + + vorbis_analysis_wrote(&ve->vd, (int) samples); + + while (vorbis_analysis_blockout(&ve->vd, &ve->vb) == 1) { + /* Do the main analysis, creating a packet */ + vorbis_analysis(&ve->vb, &ve->op); + vorbis_bitrate_addblock(&ve->vb); + + /* Add packet to bitstream */ + while (vorbis_bitrate_flushpacket(&ve->vd, &ve->op)) { + ogg_stream_packetin(&ve->os, &ve->op); + + /* If we've gone over a page boundary, we can do actual + * output, so do so (for however many pages are available) + */ + + while (!eos) { + int result = ogg_stream_pageout(&ve->os, &ve->og); + + if (!result) + break; + + ret = oe_write_page(&ve->og, ft); + if (!ret) + return 0; + + if (ogg_page_eos(&ve->og)) + eos = 1; + } + } + } + + return (len); +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * vb = (priv_t *) ft->priv; + vorbis_enc_t *ve = vb->vorbis_enc_data; + + /* Close out the remaining data */ + write_samples(ft, NULL, (size_t) 0); + + ogg_stream_clear(&ve->os); + vorbis_block_clear(&ve->vb); + vorbis_dsp_clear(&ve->vd); + vorbis_info_clear(&ve->vi); + + return (SOX_SUCCESS); +} + +static int seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * vb = (priv_t *) ft->priv; + + return ov_pcm_seek(vb->vf, (ogg_int64_t)(offset / ft->signal.channels))? SOX_EOF:SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(vorbis) +{ + static const char *names[] = {"vorbis", "ogg", NULL}; + static const unsigned encodings[] = {SOX_ENCODING_VORBIS, 0, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Xiph.org's ogg-vorbis lossy compression", names, 0, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + seek, encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/vox-fmt.c b/app/src/main/cpp/sox/vox-fmt.c new file mode 100644 index 0000000..f51dd2c --- /dev/null +++ b/app/src/main/cpp/sox/vox-fmt.c @@ -0,0 +1,33 @@ +/* libSoX file format: raw Dialogic/OKI ADPCM (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include "adpcms.h" +#include "vox.h" + +LSX_FORMAT_HANDLER(vox) +{ + static char const * const names[] = {"vox", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_OKI_ADPCM, 4, 0, 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Raw OKI/Dialogic ADPCM", names, SOX_FILE_MONO, + lsx_vox_start, lsx_vox_read, lsx_vox_stopread, + lsx_vox_start, lsx_vox_write, lsx_vox_stopwrite, + lsx_rawseek, write_encodings, NULL, sizeof(adpcm_io_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/vox.c b/app/src/main/cpp/sox/vox.c new file mode 100644 index 0000000..4943acb --- /dev/null +++ b/app/src/main/cpp/sox/vox.c @@ -0,0 +1,47 @@ +/* libSoX file format handler for Dialogic/Oki ADPCM VOX files. + * + * Copyright 1991-2007 Tony Seebregts And Sundry Contributors + * + * This source code is freely redistributable and may be used for any + * purpose. This copyright notice must be maintained. + * + * Tony Seebregts And Sundry Contributors are not responsible for the + * consequences of using this software. + */ + +#include "sox_i.h" +#include "vox.h" +#include "adpcms.h" + +/* .vox doesn't need any private state over and above adpcm_io_t *, so + just have simple wrappers that pass it on directly. */ + +int lsx_vox_start(sox_format_t * ft) +{ + return lsx_adpcm_oki_start(ft, (adpcm_io_t *)ft->priv); +} + +int lsx_ima_start(sox_format_t * ft) +{ + return lsx_adpcm_ima_start(ft, (adpcm_io_t *)ft->priv); +} + +size_t lsx_vox_read(sox_format_t * ft, sox_sample_t *buffer, size_t len) +{ + return lsx_adpcm_read(ft, (adpcm_io_t *)ft->priv, buffer, len); +} + +int lsx_vox_stopread(sox_format_t * ft) +{ + return lsx_adpcm_stopread(ft, (adpcm_io_t *)ft->priv); +} + +size_t lsx_vox_write(sox_format_t * ft, const sox_sample_t *buffer, size_t length) +{ + return lsx_adpcm_write(ft, (adpcm_io_t *)ft->priv, buffer, length); +} + +int lsx_vox_stopwrite(sox_format_t * ft) +{ + return lsx_adpcm_stopwrite(ft, (adpcm_io_t *)ft->priv); +} diff --git a/app/src/main/cpp/sox/vox.h b/app/src/main/cpp/sox/vox.h new file mode 100644 index 0000000..b81d20b --- /dev/null +++ b/app/src/main/cpp/sox/vox.h @@ -0,0 +1,23 @@ +/* (c) 2007-8 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +int lsx_vox_start(sox_format_t * ft); +int lsx_ima_start(sox_format_t * ft); +size_t lsx_vox_read(sox_format_t * ft, sox_sample_t *buffer, size_t len); +int lsx_vox_stopread(sox_format_t * ft); +size_t lsx_vox_write(sox_format_t * ft, const sox_sample_t *buffer, size_t length); +int lsx_vox_stopwrite(sox_format_t * ft); diff --git a/app/src/main/cpp/sox/w64.c b/app/src/main/cpp/sox/w64.c new file mode 100644 index 0000000..9cf9a58 --- /dev/null +++ b/app/src/main/cpp/sox/w64.c @@ -0,0 +1,39 @@ +/* libSoX file format: W64 Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(w64) +{ + static char const * const names[] = {"w64", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 24, 32, 0, + SOX_ENCODING_UNSIGNED, 8, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + SOX_ENCODING_ALAW, 8, 0, + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_IMA_ADPCM, 4, 0, + SOX_ENCODING_MS_ADPCM, 4, 0, + SOX_ENCODING_GSM, 0, + 0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = "Sound Forge Audio Format"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/wav.c b/app/src/main/cpp/sox/wav.c new file mode 100644 index 0000000..3f6beb4 --- /dev/null +++ b/app/src/main/cpp/sox/wav.c @@ -0,0 +1,1650 @@ +/* libSoX microsoft's WAVE sound format handler + * + * Copyright 1998-2006 Chris Bagwell and SoX Contributors + * Copyright 1997 Graeme W. Gill, 93/5/17 + * Copyright 1992 Rick Richardson + * Copyright 1991 Lance Norskog And Sundry Contributors + * + * Info for format tags can be found at: + * http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html + * + */ + +#include "sox_i.h" + +#include +#include +#include + +#include "ima_rw.h" +#include "adpcm.h" + +#ifdef HAVE_LIBGSM +#ifdef HAVE_GSM_GSM_H +#include +#else +#include +#endif +#endif + +/* Magic length sometimes used to indicate unknown or too large size. + * When detected on inputs, disable any length logic. + */ +#define MS_UNSPEC 0x7ffff000 + +#define WAVE_FORMAT_UNKNOWN 0x0000 +#define WAVE_FORMAT_PCM 0x0001 +#define WAVE_FORMAT_ADPCM 0x0002 +#define WAVE_FORMAT_IEEE_FLOAT 0x0003 +#define WAVE_FORMAT_IBM_CVSD 0x0005 +#define WAVE_FORMAT_ALAW 0x0006 +#define WAVE_FORMAT_MULAW 0x0007 +#define WAVE_FORMAT_OKI_ADPCM 0x0010 +#define WAVE_FORMAT_IMA_ADPCM 0x0011 +#define WAVE_FORMAT_MEDIASPACE_ADPCM 0x0012 +#define WAVE_FORMAT_SIERRA_ADPCM 0x0013 +#define WAVE_FORMAT_G723_ADPCM 0x0014 +#define WAVE_FORMAT_DIGISTD 0x0015 +#define WAVE_FORMAT_DIGIFIX 0x0016 +#define WAVE_FORMAT_YAMAHA_ADPCM 0x0020 +#define WAVE_FORMAT_SONARC 0x0021 +#define WAVE_FORMAT_TRUESPEECH 0x0022 +#define WAVE_FORMAT_ECHOSC1 0x0023 +#define WAVE_FORMAT_AUDIOFILE_AF36 0x0024 +#define WAVE_FORMAT_APTX 0x0025 +#define WAVE_FORMAT_AUDIOFILE_AF10 0x0026 +#define WAVE_FORMAT_DOLBY_AC2 0x0030 +#define WAVE_FORMAT_GSM610 0x0031 +#define WAVE_FORMAT_ADPCME 0x0033 +#define WAVE_FORMAT_CONTROL_RES_VQLPC 0x0034 +#define WAVE_FORMAT_DIGIREAL 0x0035 +#define WAVE_FORMAT_DIGIADPCM 0x0036 +#define WAVE_FORMAT_CONTROL_RES_CR10 0x0037 +#define WAVE_FORMAT_ROCKWELL_ADPCM 0x003b +#define WAVE_FORMAT_ROCKWELL_DIGITALK 0x003c +#define WAVE_FORMAT_G721_ADPCM 0x0040 +#define WAVE_FORMAT_G728_CELP 0x0041 +#define WAVE_FORMAT_MPEG 0x0050 +#define WAVE_FORMAT_MPEGLAYER3 0x0055 +#define WAVE_FORMAT_G726_ADPCM 0x0064 +#define WAVE_FORMAT_G722_ADPCM 0x0065 +#define WAVE_FORMAT_CREATIVE_ADPCM 0x0200 +#define WAVE_FORMAT_CREATIVE_FSP8 0x0202 +#define WAVE_FORMAT_CREATIVE_FSP10 0x0203 +#define WAVE_FORMAT_FM_TOWNS_SND 0x0300 +#define WAVE_FORMAT_OLIGSM 0x1000 +#define WAVE_FORMAT_OLIADPCM 0x1001 +#define WAVE_FORMAT_OLISBC 0x1003 +#define WAVE_FORMAT_OLIOPR 0x1004 +#define WAVE_FORMAT_EXTENSIBLE 0xfffe + +/* To allow padding to samplesPerBlock. Works, but currently never true. */ +static const size_t pad_nsamps = sox_false; + +/* Private data for .wav file */ +typedef struct { + /* samples/channel reading: starts at total count and decremented */ + /* writing: starts at 0 and counts samples written */ + uint64_t numSamples; + size_t dataLength; /* needed for ADPCM writing */ + unsigned short formatTag; /* What type of encoding file is using */ + unsigned short samplesPerBlock; + unsigned short blockAlign; + uint16_t bitsPerSample; /* bits per sample */ + size_t dataStart; /* need to for seeking */ + int ignoreSize; /* ignoreSize allows us to process 32-bit WAV files that are + * greater then 2 Gb and can't be represented by the + * 32-bit size field. */ + /* FIXME: Have some front-end code which sets this flag. */ + + /* following used by *ADPCM wav files */ + unsigned short nCoefs; /* ADPCM: number of coef sets */ + short *lsx_ms_adpcm_i_coefs; /* ADPCM: coef sets */ + void *ms_adpcm_data; /* Private data of adpcm decoder */ + unsigned char *packet; /* Temporary buffer for packets */ + short *samples; /* interleaved samples buffer */ + short *samplePtr; /* Pointer to current sample */ + short *sampleTop; /* End of samples-buffer */ + unsigned short blockSamplesRemaining;/* Samples remaining per channel */ + int state[16]; /* step-size info for *ADPCM writes */ + +#ifdef HAVE_LIBGSM + /* following used by GSM 6.10 wav */ + gsm gsmhandle; + gsm_signal *gsmsample; + int gsmindex; + size_t gsmbytecount; /* counts bytes written to data block */ +#endif +} priv_t; + +struct wave_format { + uint16_t tag; + const char *name; + sox_encoding_t encoding; + int (*read_fmt)(sox_format_t *ft, uint32_t len); +}; + +static const char *wav_format_str(unsigned tag); + +static int wavwritehdr(sox_format_t *, int); + +/****************************************************************************/ +/* IMA ADPCM Support Functions Section */ +/****************************************************************************/ + +static int wav_ima_adpcm_fmt(sox_format_t *ft, uint32_t len) +{ + priv_t *wav = ft->priv; + size_t bytesPerBlock; + int err; + + if (wav->bitsPerSample != 4) { + lsx_fail_errno(ft, SOX_EOF, + "Can only handle 4-bit IMA ADPCM in wav files"); + return SOX_EOF; + } + + err = lsx_read_fields(ft, &len, "h", &wav->samplesPerBlock); + if (err) + return SOX_EOF; + + bytesPerBlock = lsx_ima_bytes_per_block(ft->signal.channels, + wav->samplesPerBlock); + + if (bytesPerBlock != wav->blockAlign || wav->samplesPerBlock % 8 != 1) { + lsx_fail_errno(ft, SOX_EOF, + "format[%s]: samplesPerBlock(%d) != blockAlign(%d)", + wav_format_str(wav->formatTag), + wav->samplesPerBlock, wav->blockAlign); + return SOX_EOF; + } + + wav->packet = lsx_malloc(wav->blockAlign); + wav->samples = + lsx_malloc(ft->signal.channels * wav->samplesPerBlock * sizeof(short)); + + return SOX_SUCCESS; +} + +/* + * + * ImaAdpcmReadBlock - Grab and decode complete block of samples + * + */ +static unsigned short ImaAdpcmReadBlock(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + size_t bytesRead; + int samplesThisBlock; + + /* Pull in the packet and check the header */ + bytesRead = lsx_readbuf(ft, wav->packet, (size_t)wav->blockAlign); + samplesThisBlock = wav->samplesPerBlock; + if (bytesRead < wav->blockAlign) + { + /* If it looks like a valid header is around then try and */ + /* work with partial blocks. Specs say it should be null */ + /* padded but I guess this is better than trailing quiet. */ + samplesThisBlock = lsx_ima_samples_in((size_t)0, (size_t)ft->signal.channels, bytesRead, (size_t) 0); + if (samplesThisBlock == 0 || samplesThisBlock > wav->samplesPerBlock) + { + lsx_warn("Premature EOF on .wav input file"); + return 0; + } + } + + wav->samplePtr = wav->samples; + + /* For a full block, the following should be true: */ + /* wav->samplesPerBlock = blockAlign - 8byte header + 1 sample in header */ + lsx_ima_block_expand_i(ft->signal.channels, wav->packet, wav->samples, samplesThisBlock); + return samplesThisBlock; + +} + +/****************************************************************************/ +/* MS ADPCM Support Functions Section */ +/****************************************************************************/ + +static int wav_ms_adpcm_fmt(sox_format_t *ft, uint32_t len) +{ + priv_t *wav = ft->priv; + size_t bytesPerBlock; + int i, errct = 0; + int err; + + if (wav->bitsPerSample != 4) { + lsx_fail_errno(ft, SOX_EOF, + "Can only handle 4-bit MS ADPCM in wav files"); + return SOX_EOF; + } + + err = lsx_read_fields(ft, &len, "hh", &wav->samplesPerBlock, &wav->nCoefs); + if (err) + return SOX_EOF; + + bytesPerBlock = lsx_ms_adpcm_bytes_per_block(ft->signal.channels, + wav->samplesPerBlock); + + if (bytesPerBlock != wav->blockAlign) { + lsx_fail_errno(ft, SOX_EOF, + "format[%s]: samplesPerBlock(%d) != blockAlign(%d)", + wav_format_str(wav->formatTag), + wav->samplesPerBlock, wav->blockAlign); + return SOX_EOF; + } + + if (wav->nCoefs < 7 || wav->nCoefs > 0x100) { + lsx_fail_errno(ft, SOX_EOF, + "ADPCM file nCoefs (%.4hx) makes no sense", + wav->nCoefs); + return SOX_EOF; + } + + if (len < 4 * wav->nCoefs) { + lsx_fail_errno(ft, SOX_EOF, "wave header error: cbSize too small"); + return SOX_EOF; + } + + wav->packet = lsx_malloc(wav->blockAlign); + wav->samples = + lsx_malloc(ft->signal.channels * wav->samplesPerBlock * sizeof(short)); + + /* nCoefs, lsx_ms_adpcm_i_coefs used by adpcm.c */ + wav->lsx_ms_adpcm_i_coefs = lsx_malloc(wav->nCoefs * 2 * sizeof(short)); + wav->ms_adpcm_data = lsx_ms_adpcm_alloc(ft->signal.channels); + + err = lsx_read_fields(ft, &len, "*h", + 2 * wav->nCoefs, wav->lsx_ms_adpcm_i_coefs); + if (err) + return SOX_EOF; + + for (i = 0; i < 14; i++) + errct += wav->lsx_ms_adpcm_i_coefs[i] != lsx_ms_adpcm_i_coef[i/2][i%2]; + + if (errct) + lsx_warn("base lsx_ms_adpcm_i_coefs differ in %d/14 positions", errct); + + return SOX_SUCCESS; +} + +/* + * + * AdpcmReadBlock - Grab and decode complete block of samples + * + */ +static unsigned short AdpcmReadBlock(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + size_t bytesRead; + int samplesThisBlock; + const char *errmsg; + + /* Pull in the packet and check the header */ + bytesRead = lsx_readbuf(ft, wav->packet, (size_t) wav->blockAlign); + samplesThisBlock = wav->samplesPerBlock; + if (bytesRead < wav->blockAlign) + { + /* If it looks like a valid header is around then try and */ + /* work with partial blocks. Specs say it should be null */ + /* padded but I guess this is better than trailing quiet. */ + samplesThisBlock = lsx_ms_adpcm_samples_in((size_t)0, (size_t)ft->signal.channels, bytesRead, (size_t)0); + if (samplesThisBlock == 0 || samplesThisBlock > wav->samplesPerBlock) + { + lsx_warn("Premature EOF on .wav input file"); + return 0; + } + } + + errmsg = lsx_ms_adpcm_block_expand_i(wav->ms_adpcm_data, ft->signal.channels, wav->nCoefs, wav->lsx_ms_adpcm_i_coefs, wav->packet, wav->samples, samplesThisBlock); + + if (errmsg) + lsx_warn("%s", errmsg); + + return samplesThisBlock; +} + +/****************************************************************************/ +/* Common ADPCM Write Function */ +/****************************************************************************/ + +static int xxxAdpcmWriteBlock(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + size_t chans, ct; + short *p; + + chans = ft->signal.channels; + p = wav->samplePtr; + ct = p - wav->samples; + if (ct>=chans) { + /* zero-fill samples if needed to complete block */ + for (p = wav->samplePtr; p < wav->sampleTop; p++) *p=0; + /* compress the samples to wav->packet */ + if (wav->formatTag == WAVE_FORMAT_ADPCM) { + lsx_ms_adpcm_block_mash_i((unsigned) chans, wav->samples, wav->samplesPerBlock, wav->state, wav->packet, wav->blockAlign); + }else{ /* WAVE_FORMAT_IMA_ADPCM */ + lsx_ima_block_mash_i((unsigned) chans, wav->samples, wav->samplesPerBlock, wav->state, wav->packet, 9); + } + /* write the compressed packet */ + if (lsx_writebuf(ft, wav->packet, (size_t) wav->blockAlign) != wav->blockAlign) + { + lsx_fail_errno(ft,SOX_EOF,"write error"); + return (SOX_EOF); + } + /* update lengths and samplePtr */ + wav->dataLength += wav->blockAlign; + if (pad_nsamps) + wav->numSamples += wav->samplesPerBlock; + else + wav->numSamples += ct/chans; + wav->samplePtr = wav->samples; + } + return (SOX_SUCCESS); +} + +#ifdef HAVE_LIBGSM +/****************************************************************************/ +/* WAV GSM6.10 support functions */ +/****************************************************************************/ + +static int wav_gsm_fmt(sox_format_t *ft, uint32_t len) +{ + priv_t *wav = ft->priv; + int err; + + err = lsx_read_fields(ft, &len, "h", &wav->samplesPerBlock); + if (err) + return SOX_EOF; + + if (wav->blockAlign != 65) { + lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects blockAlign(%d) = %d", + wav_format_str(wav->formatTag), wav->blockAlign, 65); + return SOX_EOF; + } + + if (wav->samplesPerBlock != 320) { + lsx_fail_errno(ft, SOX_EOF, + "format[%s]: expects samplesPerBlock(%d) = %d", + wav_format_str(wav->formatTag), + wav->samplesPerBlock, 320); + return SOX_EOF; + } + + return SOX_SUCCESS; +} + +/* create the gsm object, malloc buffer for 160*2 samples */ +static int wavgsminit(sox_format_t * ft) +{ + int valueP=1; + priv_t * wav = (priv_t *) ft->priv; + wav->gsmbytecount=0; + wav->gsmhandle=gsm_create(); + if (!wav->gsmhandle) + { + lsx_fail_errno(ft,SOX_EOF,"cannot create GSM object"); + return (SOX_EOF); + } + + if(gsm_option(wav->gsmhandle,GSM_OPT_WAV49,&valueP) == -1){ + lsx_fail_errno(ft,SOX_EOF,"error setting gsm_option for WAV49 format. Recompile gsm library with -DWAV49 option and relink sox"); + return (SOX_EOF); + } + + wav->gsmsample=lsx_malloc(sizeof(gsm_signal)*160*2); + wav->gsmindex=0; + return (SOX_SUCCESS); +} + +/*destroy the gsm object and free the buffer */ +static void wavgsmdestroy(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + gsm_destroy(wav->gsmhandle); + free(wav->gsmsample); +} + +static size_t wavgsmread(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t * wav = (priv_t *) ft->priv; + size_t done=0; + int bytes; + gsm_byte frame[65]; + + ft->sox_errno = SOX_SUCCESS; + + /* copy out any samples left from the last call */ + while(wav->gsmindex && (wav->gsmindex<160*2) && (done < len)) + buf[done++]=SOX_SIGNED_16BIT_TO_SAMPLE(wav->gsmsample[wav->gsmindex++],); + + /* read and decode loop, possibly leaving some samples in wav->gsmsample */ + while (done < len) { + wav->gsmindex=0; + bytes = lsx_readbuf(ft, frame, (size_t)65); + if (bytes <=0) + return done; + if (bytes<65) { + lsx_warn("invalid wav gsm frame size: %d bytes",bytes); + return done; + } + /* decode the long 33 byte half */ + if(gsm_decode(wav->gsmhandle,frame, wav->gsmsample)<0) + { + lsx_fail_errno(ft,SOX_EOF,"error during gsm decode"); + return 0; + } + /* decode the short 32 byte half */ + if(gsm_decode(wav->gsmhandle,frame+33, wav->gsmsample+160)<0) + { + lsx_fail_errno(ft,SOX_EOF,"error during gsm decode"); + return 0; + } + + while ((wav->gsmindex <160*2) && (done < len)){ + buf[done++]=SOX_SIGNED_16BIT_TO_SAMPLE(wav->gsmsample[(wav->gsmindex)++],); + } + } + + return done; +} + +static int wavgsmflush(sox_format_t * ft) +{ + gsm_byte frame[65]; + priv_t * wav = (priv_t *) ft->priv; + + /* zero fill as needed */ + while(wav->gsmindex<160*2) + wav->gsmsample[wav->gsmindex++]=0; + + /*encode the even half short (32 byte) frame */ + gsm_encode(wav->gsmhandle, wav->gsmsample, frame); + /*encode the odd half long (33 byte) frame */ + gsm_encode(wav->gsmhandle, wav->gsmsample+160, frame+32); + if (lsx_writebuf(ft, frame, (size_t) 65) != 65) + { + lsx_fail_errno(ft,SOX_EOF,"write error"); + return (SOX_EOF); + } + wav->gsmbytecount += 65; + + wav->gsmindex = 0; + return (SOX_SUCCESS); +} + +static size_t wavgsmwrite(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * wav = (priv_t *) ft->priv; + size_t done = 0; + int rc; + + ft->sox_errno = SOX_SUCCESS; + + while (done < len) { + SOX_SAMPLE_LOCALS; + while ((wav->gsmindex < 160*2) && (done < len)) + wav->gsmsample[(wav->gsmindex)++] = + SOX_SAMPLE_TO_SIGNED_16BIT(buf[done++], ft->clips); + + if (wav->gsmindex < 160*2) + break; + + rc = wavgsmflush(ft); + if (rc) + return 0; + } + return done; + +} + +static void wavgsmstopwrite(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + + ft->sox_errno = SOX_SUCCESS; + + if (wav->gsmindex) + wavgsmflush(ft); + + /* Add a pad byte if amount of written bytes is not even. */ + if (wav->gsmbytecount && wav->gsmbytecount % 2){ + if(lsx_writeb(ft, 0)) + lsx_fail_errno(ft,SOX_EOF,"write error"); + else + wav->gsmbytecount += 1; + } + + wavgsmdestroy(ft); +} + +#endif /* HAVE_LIBGSM */ + +/****************************************************************************/ +/* General Sox WAV file code */ +/****************************************************************************/ + +static int wav_pcm_fmt(sox_format_t *ft, uint32_t len) +{ + priv_t *wav = ft->priv; + int bps = (wav->bitsPerSample + 7) / 8; + + if (bps == 1) { + ft->encoding.encoding = SOX_ENCODING_UNSIGNED; + } else if (bps <= 4) { + ft->encoding.encoding = SOX_ENCODING_SIGN2; + } else { + lsx_fail_errno(ft, SOX_EFMT, "%d bytes per sample not suppored", bps); + return SOX_EOF; + } + + return SOX_SUCCESS; +} + +static const struct wave_format wave_formats[] = { + { WAVE_FORMAT_UNKNOWN, "Unknown Wave Type" }, + { WAVE_FORMAT_PCM, "PCM", + SOX_ENCODING_UNKNOWN, + wav_pcm_fmt, + }, + { WAVE_FORMAT_ADPCM, "Microsoft ADPCM", + SOX_ENCODING_MS_ADPCM, + wav_ms_adpcm_fmt, + }, + { WAVE_FORMAT_IEEE_FLOAT, "IEEE Float", + SOX_ENCODING_FLOAT }, + { WAVE_FORMAT_IBM_CVSD, "Digispeech CVSD" }, + { WAVE_FORMAT_ALAW, "CCITT A-law", + SOX_ENCODING_ALAW }, + { WAVE_FORMAT_MULAW, "CCITT u-law", + SOX_ENCODING_ULAW }, + { WAVE_FORMAT_OKI_ADPCM, "OKI ADPCM" }, + { WAVE_FORMAT_IMA_ADPCM, "IMA ADPCM", + SOX_ENCODING_IMA_ADPCM, + wav_ima_adpcm_fmt, + }, + { WAVE_FORMAT_MEDIASPACE_ADPCM, "MediaSpace ADPCM" }, + { WAVE_FORMAT_SIERRA_ADPCM, "Sierra ADPCM" }, + { WAVE_FORMAT_G723_ADPCM, "G.723 ADPCM" }, + { WAVE_FORMAT_DIGISTD, "DIGISTD" }, + { WAVE_FORMAT_DIGIFIX, "DigiFix" }, + { WAVE_FORMAT_YAMAHA_ADPCM, "Yamaha ADPCM" }, + { WAVE_FORMAT_SONARC, "Sonarc" }, + { WAVE_FORMAT_TRUESPEECH, "Truespeech" }, + { WAVE_FORMAT_ECHOSC1, "ECHO SC-1", }, + { WAVE_FORMAT_AUDIOFILE_AF36, "Audio File AF36" }, + { WAVE_FORMAT_APTX, "aptX" }, + { WAVE_FORMAT_AUDIOFILE_AF10, "Audio File AF10" }, + { WAVE_FORMAT_DOLBY_AC2, "Dolby AC-2" }, + { WAVE_FORMAT_GSM610, "GSM 6.10", +#ifdef HAVE_LIBGSM + SOX_ENCODING_GSM, + wav_gsm_fmt, +#endif + }, + { WAVE_FORMAT_ADPCME, "Antex ADPCME" }, + { WAVE_FORMAT_CONTROL_RES_VQLPC, "Control Resources VQLPC" }, + { WAVE_FORMAT_DIGIREAL, "DSP Solutions REAL" }, + { WAVE_FORMAT_DIGIADPCM, "DSP Solutions ADPCM" }, + { WAVE_FORMAT_CONTROL_RES_CR10, "Control Resources CR10" }, + { WAVE_FORMAT_ROCKWELL_ADPCM, "Rockwell ADPCM" }, + { WAVE_FORMAT_ROCKWELL_DIGITALK, "Rockwell DIGITALK" }, + { WAVE_FORMAT_G721_ADPCM, "G.721 ADPCM" }, + { WAVE_FORMAT_G728_CELP, "G.728 CELP" }, + { WAVE_FORMAT_MPEG, "MPEG-1 Audio" }, + { WAVE_FORMAT_MPEGLAYER3, "MPEG-1 Layer 3" }, + { WAVE_FORMAT_G726_ADPCM, "G.726 ADPCM" }, + { WAVE_FORMAT_G722_ADPCM, "G.722 ADPCM" }, + { WAVE_FORMAT_CREATIVE_ADPCM, "Creative Labs ADPCM" }, + { WAVE_FORMAT_CREATIVE_FSP8, "Creative Labs FastSpeech 8" }, + { WAVE_FORMAT_CREATIVE_FSP10, "Creative Labs FastSpeech 10" }, + { WAVE_FORMAT_FM_TOWNS_SND, "Fujitsu FM Towns SND" }, + { WAVE_FORMAT_OLIGSM, "Olivetti GSM" }, + { WAVE_FORMAT_OLIADPCM, "Olivetti ADPCM" }, + { WAVE_FORMAT_OLISBC, "Olivetti CELP" }, + { WAVE_FORMAT_OLIOPR, "Olivetti OPR" }, + { } +}; + +static const struct wave_format *wav_find_format(unsigned tag) +{ + const struct wave_format *f; + + for (f = wave_formats; f->name; f++) + if (f->tag == tag) + return f; + + return NULL; +} + +static int wavfail(sox_format_t *ft, int tag, const char *name) +{ + if (name) + lsx_fail_errno(ft, SOX_EHDR, "WAVE format '%s' (%04x) not supported", + name, tag); + else + lsx_fail_errno(ft, SOX_EHDR, "Unknown WAVE format %04x", tag); + + return SOX_EOF; +} + +static int wav_read_fmt(sox_format_t *ft, uint32_t len) +{ + priv_t *wav = ft->priv; + uint16_t wChannels; /* number of channels */ + uint32_t dwSamplesPerSecond; /* samples per second per channel */ + uint32_t dwAvgBytesPerSec; /* estimate of bytes per second needed */ + uint16_t wExtSize = 0; /* extended field for non-PCM */ + const struct wave_format *fmt; + sox_encoding_t user_enc = ft->encoding.encoding; + int err; + + if (len < 16) { + lsx_fail_errno(ft, SOX_EHDR, "WAVE file fmt chunk is too short"); + return SOX_EOF; + } + + err = lsx_read_fields(ft, &len, "hhiihh", + &wav->formatTag, + &wChannels, + &dwSamplesPerSecond, + &dwAvgBytesPerSec, + &wav->blockAlign, + &wav->bitsPerSample); + if (err) + return SOX_EOF; + + /* non-PCM formats except alaw and mulaw formats have extended fmt chunk. + * Check for those cases. + */ + if (wav->formatTag != WAVE_FORMAT_PCM && + wav->formatTag != WAVE_FORMAT_ALAW && + wav->formatTag != WAVE_FORMAT_MULAW && + len < 2) + lsx_warn("WAVE file missing extended part of fmt chunk"); + + if (len >= 2) { + err = lsx_read_fields(ft, &len, "h", &wExtSize); + if (err) + return SOX_EOF; + } + + if (wExtSize != len) { + lsx_fail_errno(ft, SOX_EOF, + "WAVE header error: cbSize inconsistent with fmt size"); + return SOX_EOF; + } + + if (wav->formatTag == WAVE_FORMAT_EXTENSIBLE) { + uint16_t numberOfValidBits; + uint32_t speakerPositionMask; + uint16_t subFormatTag; + + if (len < 22) { + lsx_fail_errno(ft, SOX_EHDR, "WAVE file fmt chunk is too short"); + return SOX_EOF; + } + + err = lsx_read_fields(ft, &len, "hih14x", + &numberOfValidBits, + &speakerPositionMask, + &subFormatTag); + if (err) + return SOX_EOF; + + if (numberOfValidBits > wav->bitsPerSample) { + lsx_fail_errno(ft, SOX_EHDR, + "wValidBitsPerSample > wBitsPerSample"); + return SOX_EOF; + } + + wav->formatTag = subFormatTag; + lsx_report("EXTENSIBLE"); + } + + /* User options take precedence */ + if (ft->signal.channels == 0 || ft->signal.channels == wChannels) + ft->signal.channels = wChannels; + else + lsx_report("User options overriding channels read in .wav header"); + + if (ft->signal.channels == 0) { + lsx_fail_errno(ft, SOX_EHDR, "Channel count is zero"); + return SOX_EOF; + } + + if (ft->signal.rate == 0 || ft->signal.rate == dwSamplesPerSecond) + ft->signal.rate = dwSamplesPerSecond; + else + lsx_report("User options overriding rate read in .wav header"); + + fmt = wav_find_format(wav->formatTag); + if (!fmt) + return wavfail(ft, wav->formatTag, NULL); + + /* format handler might override */ + ft->encoding.encoding = fmt->encoding; + + if (fmt->read_fmt) { + if (fmt->read_fmt(ft, len)) + return SOX_EOF; + } else if (!fmt->encoding) { + return wavfail(ft, wav->formatTag, fmt->name); + } + + /* User options take precedence */ + if (!ft->encoding.bits_per_sample || + ft->encoding.bits_per_sample == wav->bitsPerSample) + ft->encoding.bits_per_sample = wav->bitsPerSample; + else + lsx_warn("User options overriding size read in .wav header"); + + if (user_enc && user_enc != ft->encoding.encoding) { + lsx_report("User options overriding encoding read in .wav header"); + ft->encoding.encoding = user_enc; + } + + return 0; +} + +static sox_bool valid_chunk_id(const char p[4]) +{ + int i; + + for (i = 0; i < 4; i++) + if (p[i] < 0x20 || p[i] > 0x7f) + return sox_false; + + return sox_true; +} + +static int read_chunk_header(sox_format_t *ft, char tag[4], uint32_t *len) +{ + int r; + + r = lsx_readbuf(ft, tag, 4); + if (r < 4) + return SOX_EOF; + + return lsx_readdw(ft, len); +} + +/* + * Do anything required before you start reading samples. + * Read file header. + * Find out sampling rate, + * size and encoding of samples, + * mono/stereo/quad. + */ +static int startread(sox_format_t *ft) +{ + priv_t *wav = ft->priv; + char magic[5] = { 0 }; + uint32_t clen; + int err; + + sox_bool isRF64 = sox_false; + uint64_t ds64_riff_size; + uint64_t ds64_data_size; + uint64_t ds64_sample_count; + + /* wave file characteristics */ + uint64_t qwRiffLength; + uint64_t qwDataLength = 0; + sox_bool have_fmt = sox_false; + + ft->sox_errno = SOX_SUCCESS; + wav->ignoreSize = ft->signal.length == SOX_IGNORE_LENGTH; + ft->encoding.reverse_bytes = MACHINE_IS_BIGENDIAN; + + if (read_chunk_header(ft, magic, &clen)) + return SOX_EOF; + + if (!memcmp(magic, "RIFX", 4)) { + lsx_debug("Found RIFX header"); + ft->encoding.reverse_bytes = MACHINE_IS_LITTLEENDIAN; + } else if (!memcmp(magic, "RF64", 4)) { + lsx_debug("Found RF64 header"); + isRF64 = sox_true; + } else if (memcmp(magic, "RIFF", 4)) { + lsx_fail_errno(ft, SOX_EHDR, "WAVE: RIFF header not found"); + return SOX_EOF; + } + + qwRiffLength = clen; + + if (lsx_readbuf(ft, magic, 4) < 4 || memcmp(magic, "WAVE", 4)) { + lsx_fail_errno(ft, SOX_EHDR, "WAVE header not found"); + return SOX_EOF; + } + + while (!read_chunk_header(ft, magic, &clen)) { + uint32_t len = clen; + off_t cstart = lsx_tell(ft); + off_t pos; + + if (!valid_chunk_id(magic)) { + lsx_fail_errno(ft, SOX_EHDR, "invalid chunk ID found"); + return SOX_EOF; + } + + lsx_debug("Found chunk '%s', size %u", magic, clen); + + if (!memcmp(magic, "ds64", 4)) { + if (!isRF64) + lsx_warn("ds64 chunk in non-RF64 file"); + + if (clen < 28) { + lsx_fail_errno(ft, SOX_EHDR, "ds64 chunk too small"); + return SOX_EOF; + } + + if (clen == 32) { + lsx_warn("ds64 chunk size invalid, attempting workaround"); + clen = 28; + } + + err = lsx_read_fields(ft, &len, "qqq", + &ds64_riff_size, + &ds64_data_size, + &ds64_sample_count); + if (err) + return SOX_EOF; + + goto next; + } + + if (!memcmp(magic, "fmt ", 4)) { + err = wav_read_fmt(ft, clen); + if (err) + return err; + + have_fmt = sox_true; + + goto next; + } + + if (!memcmp(magic, "fact", 4)) { + uint32_t val; + + err = lsx_read_fields(ft, &len, "i", &val); + if (err) + return SOX_EOF; + + wav->numSamples = val; + + goto next; + } + + if (!memcmp(magic, "data", 4)) { + if (isRF64 && clen == UINT32_MAX) + clen = ds64_data_size; + + qwDataLength = clen; + wav->dataStart = lsx_tell(ft); + + if (qwDataLength == UINT32_MAX || qwDataLength == MS_UNSPEC) + break; + + if (!ft->seekable) + break; + + goto next; + } + + next: + pos = lsx_tell(ft); + clen += clen & 1; + + if (pos > cstart + clen) { + lsx_fail_errno(ft, SOX_EHDR, "malformed chunk %s", magic); + return SOX_EOF; + } + + err = lsx_seeki(ft, cstart + clen - pos, SEEK_CUR); + if (err) + return SOX_EOF; + } + + if (isRF64) { + if (wav->numSamples == UINT32_MAX) + wav->numSamples = ds64_sample_count; + + if (qwRiffLength == UINT32_MAX) + qwRiffLength = ds64_riff_size; + } + + if (!have_fmt) { + lsx_fail_errno(ft, SOX_EOF, "fmt chunk not found"); + return SOX_EOF; + } + + if (!wav->dataStart) { + lsx_fail_errno(ft, SOX_EOF, "data chunk not found"); + return SOX_EOF; + } + + if (ft->seekable) + lsx_seeki(ft, wav->dataStart, SEEK_SET); + + /* some files wrongly report total samples across all channels */ + if (wav->numSamples * wav->blockAlign == qwDataLength * ft->signal.channels) + wav->numSamples /= ft->signal.channels; + + if ((qwDataLength == UINT32_MAX && !wav->numSamples) || + qwDataLength == MS_UNSPEC) { + lsx_warn("WAV data length is magic value or UINT32_MAX, ignoring"); + wav->ignoreSize = 1; + } + + switch (wav->formatTag) { + case WAVE_FORMAT_ADPCM: + wav->numSamples = + lsx_ms_adpcm_samples_in(qwDataLength, ft->signal.channels, + wav->blockAlign, wav->samplesPerBlock); + wav->blockSamplesRemaining = 0; /* Samples left in buffer */ + break; + + case WAVE_FORMAT_IMA_ADPCM: + /* Compute easiest part of number of samples. For every block, there + are samplesPerBlock samples to read. */ + wav->numSamples = + lsx_ima_samples_in(qwDataLength, ft->signal.channels, + wav->blockAlign, wav->samplesPerBlock); + wav->blockSamplesRemaining = 0; /* Samples left in buffer */ + lsx_ima_init_table(); + break; + +#ifdef HAVE_LIBGSM + case WAVE_FORMAT_GSM610: + wav->numSamples = qwDataLength / wav->blockAlign * wav->samplesPerBlock; + wavgsminit(ft); + break; +#endif + } + + if (!wav->numSamples) + wav->numSamples = div_bits(qwDataLength, ft->encoding.bits_per_sample) + / ft->signal.channels; + + if (wav->ignoreSize) + ft->signal.length = SOX_UNSPEC; + else + ft->signal.length = wav->numSamples * ft->signal.channels; + + return lsx_rawstartread(ft); +} + + +/* + * Read up to len samples from file. + * Convert to signed longs. + * Place in buf[]. + * Return number of samples read. + */ + +static size_t read_samples(sox_format_t *ft, sox_sample_t *buf, size_t len) +{ + priv_t *wav = ft->priv; + size_t done; + + ft->sox_errno = SOX_SUCCESS; + + if (!wav->ignoreSize) + len = min(len, wav->numSamples * ft->signal.channels); + + /* If file is in ADPCM encoding then read in multiple blocks else */ + /* read as much as possible and return quickly. */ + switch (ft->encoding.encoding) { + case SOX_ENCODING_IMA_ADPCM: + case SOX_ENCODING_MS_ADPCM: + done = 0; + while (done < len) { /* Still want data? */ + short *p, *top; + size_t ct; + + /* See if need to read more from disk */ + if (wav->blockSamplesRemaining == 0) { + if (wav->formatTag == WAVE_FORMAT_IMA_ADPCM) + wav->blockSamplesRemaining = ImaAdpcmReadBlock(ft); + else + wav->blockSamplesRemaining = AdpcmReadBlock(ft); + + if (wav->blockSamplesRemaining == 0) { + /* Don't try to read any more samples */ + wav->numSamples = 0; + return done; + } + wav->samplePtr = wav->samples; + } + + /* Copy interleaved data into buf, converting to sox_sample_t */ + ct = len - done; + if (ct > wav->blockSamplesRemaining * ft->signal.channels) + ct = wav->blockSamplesRemaining * ft->signal.channels; + + done += ct; + wav->blockSamplesRemaining -= ct / ft->signal.channels; + p = wav->samplePtr; + top = p + ct; + + /* Output is already signed */ + while (p < top) + *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(*p++,); + + wav->samplePtr = p; + } + + /* "done" for ADPCM equals total data processed and not + * total samples procesed. The only way to take care of that + * is to return here and not fall thru. + */ + wav->numSamples -= done / ft->signal.channels; + + return done; + +#ifdef HAVE_LIBGSM + case SOX_ENCODING_GSM: + done = wavgsmread(ft, buf, len); + break; +#endif + + default: /* assume PCM or float encoding */ + done = lsx_rawread(ft, buf, len); + break; + } + + if (done == 0 && wav->numSamples && !wav->ignoreSize) + lsx_warn("Premature EOF on .wav input file"); + + /* Only return buffers that contain a totally playable + * amount of audio. + */ + done -= done % ft->signal.channels; + + if (done / ft->signal.channels > wav->numSamples) + wav->numSamples = 0; + else + wav->numSamples -= done / ft->signal.channels; + + return done; +} + +/* + * Do anything required when you stop reading samples. + * Don't close input file! + */ +static int stopread(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + + ft->sox_errno = SOX_SUCCESS; + + free(wav->packet); + free(wav->samples); + free(wav->lsx_ms_adpcm_i_coefs); + free(wav->ms_adpcm_data); + + switch (ft->encoding.encoding) + { +#ifdef HAVE_LIBGSM + case SOX_ENCODING_GSM: + wavgsmdestroy(ft); + break; +#endif + case SOX_ENCODING_IMA_ADPCM: + case SOX_ENCODING_MS_ADPCM: + break; + default: + break; + } + return SOX_SUCCESS; +} + +static int startwrite(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + int rc; + + ft->sox_errno = SOX_SUCCESS; + + if (ft->encoding.encoding != SOX_ENCODING_MS_ADPCM && + ft->encoding.encoding != SOX_ENCODING_IMA_ADPCM && + ft->encoding.encoding != SOX_ENCODING_GSM) + { + rc = lsx_rawstartwrite(ft); + if (rc) + return rc; + } + + wav->numSamples = 0; + wav->dataLength = 0; + if (!ft->signal.length && !ft->seekable) + lsx_warn("Length in output .wav header will be wrong since can't seek to fix it"); + + rc = wavwritehdr(ft, 0); /* also calculates various wav->* info */ + if (rc != 0) + return rc; + + wav->packet = NULL; + wav->samples = NULL; + wav->lsx_ms_adpcm_i_coefs = NULL; + switch (wav->formatTag) + { + size_t ch, sbsize; + + case WAVE_FORMAT_IMA_ADPCM: + lsx_ima_init_table(); + /* intentional case fallthru! */ + case WAVE_FORMAT_ADPCM: + /* #channels already range-checked for overflow in wavwritehdr() */ + for (ch=0; chsignal.channels; ch++) + wav->state[ch] = 0; + sbsize = ft->signal.channels * wav->samplesPerBlock; + wav->packet = lsx_malloc((size_t)wav->blockAlign); + wav->samples = lsx_malloc(sbsize*sizeof(short)); + wav->sampleTop = wav->samples + sbsize; + wav->samplePtr = wav->samples; + break; + +#ifdef HAVE_LIBGSM + case WAVE_FORMAT_GSM610: + return wavgsminit(ft); +#endif + + default: + break; + } + return SOX_SUCCESS; +} + +/* wavwritehdr: write .wav headers as follows: + +bytes variable description +0 - 3 'RIFF'/'RIFX' Little/Big-endian +4 - 7 wRiffLength length of file minus the 8 byte riff header +8 - 11 'WAVE' +12 - 15 'fmt ' +16 - 19 wFmtSize length of format chunk minus 8 byte header +20 - 21 wFormatTag identifies PCM, ULAW etc +22 - 23 wChannels +24 - 27 dwSamplesPerSecond samples per second per channel +28 - 31 dwAvgBytesPerSec non-trivial for compressed formats +32 - 33 wBlockAlign basic block size +34 - 35 wBitsPerSample non-trivial for compressed formats + +PCM formats then go straight to the data chunk: +36 - 39 'data' +40 - 43 dwDataLength length of data chunk minus 8 byte header +44 - (dwDataLength + 43) the data +(+ a padding byte if dwDataLength is odd) + +non-PCM formats must write an extended format chunk and a fact chunk: + +ULAW, ALAW formats: +36 - 37 wExtSize = 0 the length of the format extension +38 - 41 'fact' +42 - 45 dwFactSize = 4 length of the fact chunk minus 8 byte header +46 - 49 dwSamplesWritten actual number of samples written out +50 - 53 'data' +54 - 57 dwDataLength length of data chunk minus 8 byte header +58 - (dwDataLength + 57) the data +(+ a padding byte if dwDataLength is odd) + + +GSM6.10 format: +36 - 37 wExtSize = 2 the length in bytes of the format-dependent extension +38 - 39 320 number of samples per block +40 - 43 'fact' +44 - 47 dwFactSize = 4 length of the fact chunk minus 8 byte header +48 - 51 dwSamplesWritten actual number of samples written out +52 - 55 'data' +56 - 59 dwDataLength length of data chunk minus 8 byte header +60 - (dwDataLength + 59) the data (including a padding byte, if necessary, + so dwDataLength is always even) + + +note that header contains (up to) 3 separate ways of describing the +length of the file, all derived here from the number of (input) +samples wav->numSamples in a way that is non-trivial for the blocked +and padded compressed formats: + +wRiffLength - (riff header) the length of the file, minus 8 +dwSamplesWritten - (fact header) the number of samples written (after padding + to a complete block eg for GSM) +dwDataLength - (data chunk header) the number of (valid) data bytes written + +*/ + +static int wavwritehdr(sox_format_t * ft, int second_header) +{ + priv_t * wav = (priv_t *) ft->priv; + + /* variables written to wav file header */ + /* RIFF header */ + uint64_t wRiffLength ; /* length of file after 8 byte riff header */ + /* fmt chunk */ + uint16_t wFmtSize = 16; /* size field of the fmt chunk */ + uint16_t wFormatTag = 0; /* data format */ + uint16_t wChannels; /* number of channels */ + uint32_t dwSamplesPerSecond; /* samples per second per channel*/ + uint32_t dwAvgBytesPerSec=0; /* estimate of bytes per second needed */ + uint32_t wBlockAlign=0; /* byte alignment of a basic sample block */ + uint16_t wBitsPerSample=0; /* bits per sample */ + /* fmt chunk extension (not PCM) */ + uint16_t wExtSize=0; /* extra bytes in the format extension */ + uint16_t wSamplesPerBlock; /* samples per channel per block */ + /* wSamplesPerBlock and other things may go into format extension */ + + /* fact chunk (not PCM) */ + uint32_t dwFactSize=4; /* length of the fact chunk */ + uint64_t dwSamplesWritten=0; /* windows doesnt seem to use this*/ + + /* data chunk */ + uint64_t dwDataLength; /* length of sound data in bytes */ + /* end of variables written to header */ + + /* internal variables, intermediate values etc */ + int bytespersample; /* (uncompressed) bytes per sample (per channel) */ + uint64_t blocksWritten = 0; + sox_bool isExtensible = sox_false; /* WAVE_FORMAT_EXTENSIBLE? */ + + if (ft->signal.channels > UINT16_MAX) { + lsx_fail_errno(ft, SOX_EOF, "Too many channels (%u)", + ft->signal.channels); + return SOX_EOF; + } + + dwSamplesPerSecond = ft->signal.rate; + wChannels = ft->signal.channels; + wBitsPerSample = ft->encoding.bits_per_sample; + wSamplesPerBlock = 1; /* common default for PCM data */ + + switch (ft->encoding.encoding) + { + case SOX_ENCODING_UNSIGNED: + case SOX_ENCODING_SIGN2: + wFormatTag = WAVE_FORMAT_PCM; + bytespersample = (wBitsPerSample + 7)/8; + wBlockAlign = wChannels * bytespersample; + break; + case SOX_ENCODING_FLOAT: + wFormatTag = WAVE_FORMAT_IEEE_FLOAT; + bytespersample = (wBitsPerSample + 7)/8; + wBlockAlign = wChannels * bytespersample; + break; + case SOX_ENCODING_ALAW: + wFormatTag = WAVE_FORMAT_ALAW; + wBlockAlign = wChannels; + break; + case SOX_ENCODING_ULAW: + wFormatTag = WAVE_FORMAT_MULAW; + wBlockAlign = wChannels; + break; + case SOX_ENCODING_IMA_ADPCM: + if (wChannels>16) + { + lsx_fail_errno(ft,SOX_EOF,"Channels(%d) must be <= 16",wChannels); + return SOX_EOF; + } + wFormatTag = WAVE_FORMAT_IMA_ADPCM; + wBlockAlign = wChannels * 256; /* reasonable default */ + wBitsPerSample = 4; + wExtSize = 2; + wSamplesPerBlock = lsx_ima_samples_in((size_t) 0, (size_t) wChannels, (size_t) wBlockAlign, (size_t) 0); + break; + case SOX_ENCODING_MS_ADPCM: + if (wChannels>16) + { + lsx_fail_errno(ft,SOX_EOF,"Channels(%d) must be <= 16",wChannels); + return SOX_EOF; + } + wFormatTag = WAVE_FORMAT_ADPCM; + wBlockAlign = ft->signal.rate / 11008; + wBlockAlign = max(wBlockAlign, 1) * wChannels * 256; + wBitsPerSample = 4; + wExtSize = 4+4*7; /* Ext fmt data length */ + wSamplesPerBlock = lsx_ms_adpcm_samples_in((size_t) 0, (size_t) wChannels, (size_t) wBlockAlign, (size_t) 0); + break; +#ifdef HAVE_LIBGSM + case SOX_ENCODING_GSM: + if (wChannels!=1) + { + lsx_report("Overriding GSM audio from %d channel to 1",wChannels); + if (!second_header) + ft->signal.length /= max(1, ft->signal.channels); + wChannels = ft->signal.channels = 1; + } + wFormatTag = WAVE_FORMAT_GSM610; + /* dwAvgBytesPerSec = 1625*(dwSamplesPerSecond/8000.)+0.5; */ + wBlockAlign=65; + wBitsPerSample=0; /* not representable as int */ + wExtSize=2; /* length of format extension */ + wSamplesPerBlock = 320; + break; +#endif + default: + break; + } + + if (wBlockAlign > UINT16_MAX) { + lsx_fail_errno(ft, SOX_EOF, "Too many channels (%u)", + ft->signal.channels); + return SOX_EOF; + } + + wav->formatTag = wFormatTag; + wav->blockAlign = wBlockAlign; + wav->samplesPerBlock = wSamplesPerBlock; + + /* When creating header, use length hint given by input file. If no + * hint then write default value. Also, use default value even + * on header update if more then 32-bit length needs to be written. + */ + + dwSamplesWritten = + second_header ? wav->numSamples : ft->signal.length / wChannels; + blocksWritten = + (dwSamplesWritten + wSamplesPerBlock - 1) / wSamplesPerBlock; + dwDataLength = blocksWritten * wBlockAlign; + + if (wFormatTag == WAVE_FORMAT_GSM610) + dwDataLength = (dwDataLength+1) & ~1u; /* round up to even */ + + if (wFormatTag == WAVE_FORMAT_PCM && (wBitsPerSample > 16 || wChannels > 2) + && strcmp(ft->filetype, "wavpcm")) { + isExtensible = sox_true; + wFmtSize += 2 + 22; + } + else if (wFormatTag != WAVE_FORMAT_PCM) + wFmtSize += 2+wExtSize; /* plus ExtData */ + + wRiffLength = 4 + (8+wFmtSize) + (8+dwDataLength+dwDataLength%2); + if (isExtensible || wFormatTag != WAVE_FORMAT_PCM) /* PCM omits the "fact" chunk */ + wRiffLength += (8+dwFactSize); + + if (dwSamplesWritten > UINT32_MAX) + dwSamplesWritten = UINT32_MAX; + + if (dwDataLength > UINT32_MAX) + dwDataLength = UINT32_MAX; + + if (!second_header && !ft->signal.length) + dwDataLength = UINT32_MAX; + + if (wRiffLength > UINT32_MAX) + wRiffLength = UINT32_MAX; + + /* dwAvgBytesPerSec <-- this is BEFORE compression, isn't it? guess not. */ + dwAvgBytesPerSec = (double)wBlockAlign*ft->signal.rate / (double)wSamplesPerBlock + 0.5; + + /* figured out header info, so write it */ + + /* If user specified opposite swap than we think, assume they are + * asking to write a RIFX file. + */ + if (ft->encoding.reverse_bytes == MACHINE_IS_LITTLEENDIAN) + { + if (!second_header) + lsx_report("Requested to swap bytes so writing RIFX header"); + lsx_writes(ft, "RIFX"); + } + else + lsx_writes(ft, "RIFF"); + lsx_writedw(ft, wRiffLength); + lsx_writes(ft, "WAVE"); + lsx_writes(ft, "fmt "); + lsx_writedw(ft, wFmtSize); + lsx_writew(ft, isExtensible ? WAVE_FORMAT_EXTENSIBLE : wFormatTag); + lsx_writew(ft, wChannels); + lsx_writedw(ft, dwSamplesPerSecond); + lsx_writedw(ft, dwAvgBytesPerSec); + lsx_writew(ft, wBlockAlign); + lsx_writew(ft, wBitsPerSample); /* end info common to all fmts */ + + if (isExtensible) { + uint32_t dwChannelMask=0; /* unassigned speaker mapping by default */ + static unsigned char const guids[][14] = { + "\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71", /* wav */ + "\x00\x00\x21\x07\xd3\x11\x86\x44\xc8\xc1\xca\x00\x00\x00"}; /* amb */ + + /* if not amb, assume most likely channel masks from number of channels; not + * ideal solution, but will make files playable in many/most situations + */ + if (strcmp(ft->filetype, "amb")) { + if (wChannels == 1) dwChannelMask = 0x4; /* 1 channel (mono) = FC */ + else if (wChannels == 2) dwChannelMask = 0x3; /* 2 channels (stereo) = FL, FR */ + else if (wChannels == 4) dwChannelMask = 0x33; /* 4 channels (quad) = FL, FR, BL, BR */ + else if (wChannels == 6) dwChannelMask = 0x3F; /* 6 channels (5.1) = FL, FR, FC, LF, BL, BR */ + else if (wChannels == 8) dwChannelMask = 0x63F; /* 8 channels (7.1) = FL, FR, FC, LF, BL, BR, SL, SR */ + } + + lsx_writew(ft, 22); + lsx_writew(ft, wBitsPerSample); /* No padding in container */ + lsx_writedw(ft, dwChannelMask); /* Speaker mapping is something reasonable */ + lsx_writew(ft, wFormatTag); + lsx_writebuf(ft, guids[!strcmp(ft->filetype, "amb")], (size_t)14); + } + else + /* if not PCM, we need to write out wExtSize even if wExtSize=0 */ + if (wFormatTag != WAVE_FORMAT_PCM) + lsx_writew(ft,wExtSize); + + switch (wFormatTag) + { + int i; + case WAVE_FORMAT_IMA_ADPCM: + lsx_writew(ft, wSamplesPerBlock); + break; + case WAVE_FORMAT_ADPCM: + lsx_writew(ft, wSamplesPerBlock); + lsx_writew(ft, 7); /* nCoefs */ + for (i=0; i<7; i++) { + lsx_writew(ft, (uint16_t)(lsx_ms_adpcm_i_coef[i][0])); + lsx_writew(ft, (uint16_t)(lsx_ms_adpcm_i_coef[i][1])); + } + break; + case WAVE_FORMAT_GSM610: + lsx_writew(ft, wSamplesPerBlock); + break; + default: + break; + } + + /* if not PCM, write the 'fact' chunk */ + if (isExtensible || wFormatTag != WAVE_FORMAT_PCM){ + lsx_writes(ft, "fact"); + lsx_writedw(ft,dwFactSize); + lsx_writedw(ft,dwSamplesWritten); + } + + lsx_writes(ft, "data"); + lsx_writedw(ft, dwDataLength); /* data chunk size */ + + if (!second_header) { + lsx_debug("Writing Wave file: %s format, %d channel%s, %d samp/sec", + wav_format_str(wFormatTag), wChannels, + wChannels == 1 ? "" : "s", dwSamplesPerSecond); + lsx_debug(" %d byte/sec, %d block align, %d bits/samp", + dwAvgBytesPerSec, wBlockAlign, wBitsPerSample); + } else { + if (wRiffLength == UINT32_MAX || dwDataLength == UINT32_MAX || + dwSamplesWritten == UINT32_MAX) + lsx_warn("File too large, writing truncated values in header"); + + lsx_debug("Finished writing Wave file, %"PRIu64" data bytes %"PRIu64" samples", + dwDataLength, wav->numSamples); +#ifdef HAVE_LIBGSM + if (wFormatTag == WAVE_FORMAT_GSM610){ + lsx_debug("GSM6.10 format: %"PRIu64" blocks %"PRIu64" padded samples %"PRIu64" padded data bytes", + blocksWritten, dwSamplesWritten, dwDataLength); + if (wav->gsmbytecount != dwDataLength) + lsx_warn("help ! internal inconsistency - data_written %"PRIu64" gsmbytecount %zu", + dwDataLength, wav->gsmbytecount); + + } +#endif + } + return SOX_SUCCESS; +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t *buf, size_t len) +{ + priv_t * wav = (priv_t *) ft->priv; + ptrdiff_t total_len = len; + + ft->sox_errno = SOX_SUCCESS; + + switch (wav->formatTag) + { + case WAVE_FORMAT_IMA_ADPCM: + case WAVE_FORMAT_ADPCM: + while (len>0) { + short *p = wav->samplePtr; + short *top = wav->sampleTop; + + if (top>p+len) top = p+len; + len -= top-p; /* update residual len */ + while (p < top) + *p++ = (*buf++) >> 16; + + wav->samplePtr = p; + if (p == wav->sampleTop) + xxxAdpcmWriteBlock(ft); + + } + return total_len - len; + break; + +#ifdef HAVE_LIBGSM + case WAVE_FORMAT_GSM610: + len = wavgsmwrite(ft, buf, len); + wav->numSamples += (len/ft->signal.channels); + return len; + break; +#endif + + default: + len = lsx_rawwrite(ft, buf, len); + wav->numSamples += (len/ft->signal.channels); + return len; + } +} + +static int stopwrite(sox_format_t * ft) +{ + priv_t * wav = (priv_t *) ft->priv; + + ft->sox_errno = SOX_SUCCESS; + + + /* Call this to flush out any remaining data. */ + switch (wav->formatTag) + { + case WAVE_FORMAT_IMA_ADPCM: + case WAVE_FORMAT_ADPCM: + xxxAdpcmWriteBlock(ft); + break; +#ifdef HAVE_LIBGSM + case WAVE_FORMAT_GSM610: + wavgsmstopwrite(ft); + break; +#endif + } + + /* Add a pad byte if the number of data bytes is odd. + See wavwritehdr() above for the calculation. */ + if (wav->formatTag != WAVE_FORMAT_GSM610) + lsx_padbytes(ft, (size_t)((wav->numSamples + wav->samplesPerBlock - 1)/wav->samplesPerBlock*wav->blockAlign) % 2); + + free(wav->packet); + free(wav->samples); + free(wav->lsx_ms_adpcm_i_coefs); + + /* All samples are already written out. */ + /* If file header needs fixing up, for example it needs the */ + /* the number of samples in a field, seek back and write them here. */ + if (ft->signal.length && wav->numSamples <= 0xffffffff && + wav->numSamples == ft->signal.length) + return SOX_SUCCESS; + if (!ft->seekable) + return SOX_EOF; + + if (lsx_seeki(ft, (off_t)0, SEEK_SET) != 0) + { + lsx_fail_errno(ft,SOX_EOF,"Can't rewind output file to rewrite .wav header."); + return SOX_EOF; + } + + return (wavwritehdr(ft, 1)); +} + +/* + * Return a string corresponding to the wave format type. + */ +static const char *wav_format_str(unsigned tag) +{ + const struct wave_format *f = wav_find_format(tag); + return f ? f->name : "unknown"; +} + +static int seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * wav = (priv_t *) ft->priv; + + if (ft->encoding.bits_per_sample & 7) + lsx_fail_errno(ft, SOX_ENOTSUP, "seeking not supported with this encoding"); + else if (wav->formatTag == WAVE_FORMAT_GSM610) { + int alignment; + size_t gsmoff; + + /* rounding bytes to blockAlign so that we + * don't have to decode partial block. */ + gsmoff = offset * wav->blockAlign / wav->samplesPerBlock + + wav->blockAlign * ft->signal.channels / 2; + gsmoff -= gsmoff % (wav->blockAlign * ft->signal.channels); + + ft->sox_errno = lsx_seeki(ft, (off_t)(gsmoff + wav->dataStart), SEEK_SET); + if (ft->sox_errno == SOX_SUCCESS) { + /* offset is in samples */ + uint64_t new_offset = offset; + alignment = offset % wav->samplesPerBlock; + if (alignment != 0) + new_offset += (wav->samplesPerBlock - alignment); + wav->numSamples = ft->signal.length - (new_offset / ft->signal.channels); + } + } else { + double wide_sample = offset - (offset % ft->signal.channels); + double to_d = wide_sample * ft->encoding.bits_per_sample / 8; + off_t to = to_d; + ft->sox_errno = (to != to_d)? SOX_EOF : lsx_seeki(ft, (off_t)wav->dataStart + (off_t)to, SEEK_SET); + if (ft->sox_errno == SOX_SUCCESS) + wav->numSamples -= (size_t)wide_sample / ft->signal.channels; + } + + return ft->sox_errno; +} + +LSX_FORMAT_HANDLER(wav) +{ + static char const * const names[] = {"wav", "wavpcm", "amb", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 16, 24, 32, 0, + SOX_ENCODING_UNSIGNED, 8, 0, + SOX_ENCODING_ULAW, 8, 0, + SOX_ENCODING_ALAW, 8, 0, +#ifdef HAVE_LIBGSM + SOX_ENCODING_GSM, 0, +#endif + SOX_ENCODING_MS_ADPCM, 4, 0, + SOX_ENCODING_IMA_ADPCM, 4, 0, + SOX_ENCODING_FLOAT, 32, 64, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Microsoft audio format", names, SOX_FILE_LIT_END, + startread, read_samples, stopread, + startwrite, write_samples, stopwrite, + seek, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/waveaudio.c b/app/src/main/cpp/sox/waveaudio.c new file mode 100644 index 0000000..875ce1d --- /dev/null +++ b/app/src/main/cpp/sox/waveaudio.c @@ -0,0 +1,534 @@ +/* libSoX device driver: MS-Windows audio (c) 2009 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#include +#include +#include + +/* Larger means more latency (difference between the status line and the audio you hear), + * but it means lower chance of stuttering/glitching. 2 buffers is usually enough. Use + * 4 if you want to be extra-safe. + */ +#define num_buffers 4 + +typedef struct waveaudio_priv_t +{ + /* Handle to the input device (microphone, line in, etc.). NULL if playing. */ + HWAVEIN hin; + + /* Handle to the output device (speakers, line out, etc.). NULL if recording. */ + HWAVEOUT hout; + + /* Event that becomes signaled when a the system has finished processing a buffer. */ + HANDLE block_finished_event; + + /* Data transfer buffers. The lpData member of the first buffer points at + * data[buf_len*sample_size*0], the second buffer's lpData points at + * data[buf_len*sample_size*1], etc. The dwUser field contains the number + * of samples of this buffer that have already been processed. + */ + WAVEHDR headers[num_buffers]; + + /* The combined data area shared by all transfer buffers. + * size = (bufsiz rounded up to a multiple of 32 samples) * num_buffers. + */ + char * data; + + /* The number of samples that can fit into one transfer buffer. */ + size_t buf_len; + + /* Index of the buffer that we're currently processing. For playback, this is the buffer + * that will receive the next samples. For recording, this is the buffer from which we'll + * be getting the next samples. If no buffers are ready for processing, this is the buffer + * that will be the next to become ready. + */ + unsigned current; + + /* Shift sample count by this many to get byte count: + * 0 for 8-bit samples, 1 for 16-bit samples, or 2 for 32-bit samples. + */ + unsigned char sample_shift; +} priv_t; + +static void fail(sox_format_t* ft, unsigned code, const char* context) +{ + char message[256]; + unsigned formatMessageOk = FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + code, + 0, + message, + sizeof(message) / sizeof(message[0]), + NULL); + if (formatMessageOk) + lsx_fail_errno(ft, SOX_EOF, "WaveAudio %s failed with code %d: %s", context, (int)code, message); + else + lsx_fail_errno(ft, SOX_EOF, "WaveAudio %s failed with unrecognized MMSYSERR code: %d", context, (int)code); +} + +static int stop(sox_format_t* ft) +{ + priv_t *priv = (priv_t*)ft->priv; + if (priv == NULL) return SOX_EOF; + + if (priv->hin) + { + waveInReset(priv->hin); + waveInClose(priv->hin); + } + + if (priv->hout) + { + waveOutReset(priv->hout); + waveOutClose(priv->hout); + } + + if (priv->block_finished_event) + CloseHandle(priv->block_finished_event); + + if (priv->data) + free(priv->data); + + return SOX_SUCCESS; +} + +static unsigned check_format( + WAVEFORMATEXTENSIBLE* pfmt, + int recording, + unsigned dev, + unsigned channels, + unsigned width, + unsigned hertz) +{ + /* GUID: KSDATAFORMAT_SUBTYPE_PCM */ + static unsigned char const SubformatPcm[] = + "\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71"; + + const unsigned bytewidth = width > 16 ? 4 : width > 8 ? 2 : 1; + const int extend = channels > 2 || width > 16; + unsigned error; + + pfmt->Format.wFormatTag = extend ? WAVE_FORMAT_EXTENSIBLE : WAVE_FORMAT_PCM; + pfmt->Format.nChannels = channels; + pfmt->Format.nSamplesPerSec = hertz; + pfmt->Format.nAvgBytesPerSec = channels * bytewidth * hertz; + pfmt->Format.nBlockAlign = channels * bytewidth; + pfmt->Format.wBitsPerSample = bytewidth * 8; + pfmt->Format.cbSize = extend ? 22 : 0; + pfmt->Samples.wValidBitsPerSample = width; + pfmt->dwChannelMask = 0; + memcpy(&pfmt->SubFormat, SubformatPcm, 16); + + if (recording) + error = waveInOpen(0, dev, &pfmt->Format, 0, 0, WAVE_FORMAT_QUERY); + else + error = waveOutOpen(0, dev, &pfmt->Format, 0, 0, WAVE_FORMAT_QUERY); + + lsx_debug( + "%s(QUERY: Dev %d %uHz %uCh %uPrec %uWide) returned %u", + recording ? "waveInOpen" : "waveOutOpen", + dev, + hertz, + channels, + bytewidth * 8, + width, + error); + return error; +} + +static unsigned negotiate_format(sox_format_t* ft, WAVEFORMATEXTENSIBLE* pfmt, unsigned dev) +{ + int recording = ft->mode == 'r'; + unsigned error = 0; + + unsigned precision = ft->encoding.bits_per_sample; + if (precision > 32) + precision = 32; + else if (precision < 8) + precision = 8; + + while (precision > 0) + { + error = check_format(pfmt, recording, dev, ft->signal.channels, precision, (unsigned)ft->signal.rate); + if (error == MMSYSERR_NOERROR) + return MMSYSERR_NOERROR; + precision = (precision - 1) & ~(7u); + } + + return error; +} + +static int start(sox_format_t* ft) +{ + size_t i; + unsigned dev; + WAVEFORMATEXTENSIBLE fmt; + int recording = ft->mode == 'r'; + unsigned error; + priv_t *priv = (priv_t*)ft->priv; + if (priv == NULL) return SOX_EOF; + memset(&fmt, 0, sizeof(fmt)); + + /* Handle AUDIODEV device selection: + * NULL, blank, or "default" gets you the default device (WAVE_MAPPER = -1). + * An integer value gets you the device with that device number, if it exists (counting starts at 0). + * A string gets you the device with that name, if it exists. + */ + if (ft->filename == 0 || ft->filename[0] == 0 || !strcasecmp("default", ft->filename)) + { + dev = WAVE_MAPPER; + } + else + { + WAVEINCAPSA incaps; + WAVEOUTCAPSA outcaps; + const char *dev_name; + char* dev_num_end; + dev = strtoul(ft->filename, &dev_num_end, 0); + if (dev_num_end[0] == 0) + { + if (recording) + error = waveInGetDevCapsA(dev, &incaps, sizeof(incaps)); + else + error = waveOutGetDevCapsA(dev, &outcaps, sizeof(outcaps)); + + if (error) + { + lsx_fail_errno(ft, ENODEV, "WaveAudio device not found."); + return SOX_EOF; + } + } + else + { + unsigned dev_count = recording ? waveInGetNumDevs() : waveOutGetNumDevs(); + size_t name_len = strlen(ft->filename); + if (name_len > 31) + name_len = 31; + for (dev = WAVE_MAPPER; dev != dev_count; dev++) + { + if (recording) + { + error = waveInGetDevCapsA(dev, &incaps, sizeof(incaps)); + dev_name = incaps.szPname; + lsx_debug("Enumerating input device %2d: \"%s\"", dev, dev_name); + } + else + { + error = waveOutGetDevCapsA(dev, &outcaps, sizeof(outcaps)); + dev_name = outcaps.szPname; + lsx_debug("Enumerating output device %2d: \"%s\"", dev, dev_name); + } + + if (error) + { + fail(ft, error, recording ? "waveInGetDevCapsA" : "waveOutGetDevCapsA"); + return SOX_EOF; + } + + if (!strncasecmp(ft->filename, dev_name, name_len)) + { + lsx_report("Requested name \"%s\" matched device %d: \"%s\"", ft->filename, dev, dev_name); + break; + } + } + + if (dev == dev_count) + { + lsx_fail_errno(ft, ENODEV, "The requested WaveAudio device was not found."); + return SOX_EOF; + } + } + } + + error = negotiate_format(ft, &fmt, dev); + if (error != MMSYSERR_NOERROR) + { + fail(ft, error, "sample format negotiation"); + return SOX_EOF; + } + + switch (fmt.Format.wBitsPerSample) + { + case 8: + priv->sample_shift = 0; + break; + case 16: + priv->sample_shift = 1; + break; + case 32: + priv->sample_shift = 2; + break; + default: + lsx_fail_errno(ft, E2BIG, "Unexpected value for WaveAudio wBitsPerSample: %u", fmt.Format.wBitsPerSample); + return SOX_EOF; + } + + ft->signal.precision = fmt.Samples.wValidBitsPerSample; + ft->signal.channels = fmt.Format.nChannels; + if (dev == WAVE_MAPPER) + { + lsx_report( + "Using default %s device at %uHz %uCh %uPrec %uWide.", + recording ? "input" : "output", + (unsigned)fmt.Format.nSamplesPerSec, + (unsigned)fmt.Format.nChannels, + (unsigned)fmt.Samples.wValidBitsPerSample, + (unsigned)fmt.Format.wBitsPerSample); + } + else + { + lsx_report( + "Using %s device #%d at %uHz %uCh %uPrec %uWide.", + recording ? "input" : "output", + (int)dev, + (unsigned)fmt.Format.nSamplesPerSec, + (unsigned)fmt.Format.nChannels, + (unsigned)fmt.Samples.wValidBitsPerSample, + (unsigned)fmt.Format.wBitsPerSample); + } + + priv->buf_len = ((sox_globals.bufsiz >> priv->sample_shift) + 31) & ~31u; + priv->data = lsx_malloc((priv->buf_len * num_buffers) << priv->sample_shift); + if (!priv->data) + { + lsx_fail_errno(ft, SOX_ENOMEM, "Out of memory."); + return SOX_EOF; + } + + priv->block_finished_event = CreateEventA(NULL, FALSE, FALSE, NULL); + if (!priv->block_finished_event) + { + error = GetLastError(); + fail(ft, error, "CreateEventA"); + stop(ft); + return SOX_EOF; + } + + if (recording) + { + error = waveInOpen( + &priv->hin, + dev, + &fmt.Format, + (DWORD_PTR)priv->block_finished_event, + 0, + CALLBACK_EVENT); + } + else + { + error = waveOutOpen( + &priv->hout, + dev, + &fmt.Format, + (DWORD_PTR)priv->block_finished_event, + 0, + CALLBACK_EVENT); + } + + if (error != MMSYSERR_NOERROR) + { + fail(ft, error, recording ? "waveInOpen" : "waveOutOpen"); + stop(ft); + return SOX_EOF; + } + + for (i = 0; i != num_buffers; i++) + { + priv->headers[i].lpData = priv->data + ((priv->buf_len * i) << priv->sample_shift); + priv->headers[i].dwBufferLength = priv->buf_len << priv->sample_shift; + + if (recording) + error = waveInPrepareHeader(priv->hin, &priv->headers[i], sizeof(priv->headers[i])); + else + error = waveOutPrepareHeader(priv->hout, &priv->headers[i], sizeof(priv->headers[i])); + + if (error != MMSYSERR_NOERROR) + { + fail(ft, error, recording ? "waveInPrepareHeader" : "waveOutPrepareHeader"); + stop(ft); + return SOX_EOF; + } + + if (recording) + { + error = waveInAddBuffer(priv->hin, &priv->headers[i], sizeof(priv->headers[i])); + if (error != MMSYSERR_NOERROR) + { + fail(ft, error, "waveInAddBuffer"); + stop(ft); + return SOX_EOF; + } + } + } + + if (recording) + { + error = waveInStart(priv->hin); + if (error != MMSYSERR_NOERROR) + { + fail(ft, error, "waveInStart"); + stop(ft); + return SOX_EOF; + } + } + + return SOX_SUCCESS; +} + +static size_t waveread(sox_format_t * ft, sox_sample_t* buf, size_t len) +{ + size_t copied = 0; + priv_t *priv = (priv_t*)ft->priv; + unsigned error = 0; + + if (priv == NULL) + return (size_t)SOX_EOF; + + while (!error && copied < len) + { + LPWAVEHDR header = &priv->headers[priv->current]; + if (0 == (header->dwFlags & WHDR_INQUEUE) || + 0 != (header->dwFlags & WHDR_DONE)) + { + size_t length = header->dwBytesRecorded >> priv->sample_shift; + size_t ready = min(len - copied, length - header->dwUser); + size_t i; + + switch (priv->sample_shift) + { + case 0: + for (i = 0; i < ready; ++i) + { + buf[copied++] = SOX_UNSIGNED_8BIT_TO_SAMPLE(((uint8_t *)header->lpData)[header->dwUser++], dummy); + } + break; + case 1: + for (i = 0; i < ready; ++i) + { + buf[copied++] = SOX_SIGNED_16BIT_TO_SAMPLE(((int16_t *)header->lpData)[header->dwUser++], dummy); + } + break; + case 2: + for (i = 0; i < ready; ++i) + { + buf[copied++] = SOX_SIGNED_32BIT_TO_SAMPLE(((int32_t *)header->lpData)[header->dwUser++], dummy); + } + break; + } + + if (header->dwUser == length) + { + error = waveInAddBuffer(priv->hin, header, sizeof(*header)); + priv->current = (priv->current + 1) % num_buffers; + priv->headers[priv->current].dwUser = 0; + if (error) + { + fail(ft, error, "waveInAddBuffer"); + copied = 0; + } + } + } + else + { + WaitForSingleObject(priv->block_finished_event, INFINITE); + } + } + + return copied; +} + +static size_t wavewrite(sox_format_t * ft, const sox_sample_t* buf, size_t len) +{ + size_t copied = 0; + priv_t *priv = (priv_t*)ft->priv; + unsigned error = 0; + unsigned clips = 0; + + if (priv == NULL) + return (size_t)SOX_EOF; + + while (!error && copied < len) + { + LPWAVEHDR header = &priv->headers[priv->current]; + if (0 == (header->dwFlags & WHDR_INQUEUE) || + 0 != (header->dwFlags & WHDR_DONE)) + { + size_t ready = min(len - copied, priv->buf_len - header->dwUser); + size_t i; + + switch (priv->sample_shift) + { + case 0: + for (i = 0; i < ready; ++i) + { + SOX_SAMPLE_LOCALS; + ((uint8_t *)header->lpData)[header->dwUser++] = SOX_SAMPLE_TO_UNSIGNED_8BIT(buf[copied++], clips); + } + break; + case 1: + for (i = 0; i < ready; ++i) + { + SOX_SAMPLE_LOCALS; + ((int16_t *)header->lpData)[header->dwUser++] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[copied++], clips); + } + break; + case 2: + for (i = 0; i < ready; ++i) + { + ((int32_t *)header->lpData)[header->dwUser++] = SOX_SAMPLE_TO_SIGNED_32BIT(buf[copied++], clips); + } + break; + } + + header->dwBufferLength = header->dwUser << priv->sample_shift; + error = waveOutWrite(priv->hout, header, sizeof(*header)); + priv->current = (priv->current + 1) % num_buffers; + priv->headers[priv->current].dwUser = 0; + + if (error) + { + fail(ft, error, "waveOutWrite"); + copied = 0; + } + } + else + { + WaitForSingleObject(priv->block_finished_event, INFINITE); + } + } + + return copied; +} + +LSX_FORMAT_HANDLER(waveaudio) +{ + static const char * const names[] = {"waveaudio", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_SIGN2, 32, 24, 16, 8, 0, + 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Windows Multimedia Audio", names, + SOX_FILE_DEVICE | SOX_FILE_NOSTDIO, + start, waveread, stop, + start, wavewrite, stop, + NULL, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/wavpack.c b/app/src/main/cpp/sox/wavpack.c new file mode 100644 index 0000000..b7e8daf --- /dev/null +++ b/app/src/main/cpp/sox/wavpack.c @@ -0,0 +1,206 @@ +/* libSoX file format: WavPack (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +#ifdef HAVE_WAVPACK_H +#define HAVE_WAVPACK 1 +#endif + +#ifdef HAVE_WAVPACK + +#ifdef HAVE_WAVPACK_H +#include +#else +#include +#endif + +typedef struct { + WavpackContext * codec; + size_t first_block_size; +} priv_t; + +static int32_t ft_read_b_buf(void * ft, void * buf, int32_t len) { + return (int32_t)lsx_read_b_buf((sox_format_t *)ft, buf, (size_t)len);} +static uint32_t ft_tell(void * ft) { + return lsx_tell((sox_format_t *)ft);} +static int ft_seek_abs(void * ft, uint32_t offset) { + return lsx_seeki((sox_format_t *)ft, (off_t)offset, SEEK_SET);} +static int ft_seek_rel(void * ft, int32_t offset, int mode) { + return lsx_seeki((sox_format_t *)ft, (off_t)offset, mode);} +static int ft_unreadb(void * ft, int b) { + return lsx_unreadb((sox_format_t *)ft, (unsigned)b);} +static uint32_t ft_filelength(void * ft) { + return (uint32_t)lsx_filelength((sox_format_t *)ft);} +static int ft_is_seekable(void *ft) { + return ((sox_format_t *)ft)->seekable;} +static int32_t ft_write_b_buf(void * ft, void * buf, int32_t len) { + priv_t * p = (priv_t *)((sox_format_t *)ft)->priv; + if (!p->first_block_size) + p->first_block_size = len; + return (int32_t)lsx_write_b_buf((sox_format_t *)ft, buf, (size_t)len);} + +static WavpackStreamReader io_fns = { + ft_read_b_buf, ft_tell, ft_seek_abs, ft_seek_rel, + ft_unreadb, ft_filelength, ft_is_seekable, ft_write_b_buf +}; + +static int start_read(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + char msg[80]; + + p->codec = WavpackOpenFileInputEx(&io_fns, ft, NULL, msg, OPEN_NORMALIZE, 0); + if (!p->codec) { + lsx_fail_errno(ft, SOX_EHDR, "%s", msg); + return SOX_EOF; + } + ft->encoding.bits_per_sample = WavpackGetBytesPerSample(p->codec) << 3; + ft->signal.channels = WavpackGetNumChannels(p->codec); + if (WavpackGetSampleRate(p->codec) && ft->signal.rate && ft->signal.rate != WavpackGetSampleRate(p->codec)) + lsx_warn("`%s': overriding sample rate", ft->filename); + else ft->signal.rate = WavpackGetSampleRate(p->codec); + + ft->signal.length = (uint64_t)WavpackGetNumSamples(p->codec) * ft->signal.channels; + ft->encoding.encoding = (WavpackGetMode(p->codec) & MODE_FLOAT)? + SOX_ENCODING_WAVPACKF : SOX_ENCODING_WAVPACK; + return SOX_SUCCESS; +} + +static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len) +{ + priv_t * p = (priv_t *)ft->priv; + size_t i, actual = WavpackUnpackSamples(p->codec, buf, (uint32_t) len / ft->signal.channels) * ft->signal.channels; + for (i = 0; i < actual; ++i) switch (ft->encoding.bits_per_sample) { + SOX_SAMPLE_LOCALS; + case 8: buf[i] = SOX_SIGNED_8BIT_TO_SAMPLE(buf[i],); break; + case 16: buf[i] = SOX_SIGNED_16BIT_TO_SAMPLE(buf[i],); break; + case 24: buf[i] = SOX_SIGNED_24BIT_TO_SAMPLE(buf[i],); break; + case 32: buf[i] = ft->encoding.encoding == SOX_ENCODING_WAVPACKF? + SOX_FLOAT_32BIT_TO_SAMPLE(*(float *)&buf[i], ft->clips) : + SOX_SIGNED_32BIT_TO_SAMPLE(buf[i],); + break; + } + return actual; +} + +static int stop_read(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + WavpackCloseFile(p->codec); + return SOX_SUCCESS; +} + +static int start_write(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + WavpackConfig config; + uint64_t size64; + + p->codec = WavpackOpenFileOutput(ft_write_b_buf, ft, NULL); + if (!p->codec) { + lsx_fail_errno(ft, SOX_ENOMEM, "WavPack error creating output instance"); + return SOX_EOF; + } + memset(&config, 0, sizeof(config)); + config.bytes_per_sample = ft->encoding.bits_per_sample >> 3; + config.bits_per_sample = ft->encoding.bits_per_sample; + config.channel_mask = ft->signal.channels == 1? 4 : + ft->signal.channels == 2? 3 : (1 << ft->signal.channels) - 1; + config.num_channels = ft->signal.channels; + config.sample_rate = (int32_t)(ft->signal.rate + .5); + config.flags = CONFIG_VERY_HIGH_FLAG; + size64 = ft->signal.length / ft->signal.channels; + if (!WavpackSetConfiguration(p->codec, &config, size64 && size64 <= UINT_MAX ? (uint32_t)size64 : (uint32_t)-1)) { + lsx_fail_errno(ft, SOX_EHDR, "%s", WavpackGetErrorMessage(p->codec)); + return SOX_EOF; + } + WavpackPackInit(p->codec); + return SOX_SUCCESS; +} + +static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, size_t len) +{ + priv_t * p = (priv_t *)ft->priv; + size_t i; + int32_t * obuf = lsx_malloc(len * sizeof(*obuf)); + int result; + + for (i = 0; i < len; ++i) switch (ft->encoding.bits_per_sample) { + SOX_SAMPLE_LOCALS; + case 8: obuf[i] = SOX_SAMPLE_TO_SIGNED_8BIT(buf[i], ft->clips); break; + case 16: obuf[i] = SOX_SAMPLE_TO_SIGNED_16BIT(buf[i], ft->clips); break; + case 24: obuf[i] = SOX_SAMPLE_TO_SIGNED_24BIT(buf[i], ft->clips) << 8; + obuf[i] >>= 8; break; + case 32: obuf[i] = ft->encoding.encoding == SOX_ENCODING_WAVPACKF? + SOX_SAMPLE_TO_SIGNED_24BIT(*(float *)&buf[i], ft->clips) : + SOX_SAMPLE_TO_SIGNED_32BIT(buf[i], ft->clips); + break; + } + result = WavpackPackSamples(p->codec, obuf, (uint32_t) len / ft->signal.channels); + free(obuf); + return result? len : 0; +} + +static int stop_write(sox_format_t * ft) +{ + priv_t * p = (priv_t *)ft->priv; + WavpackFlushSamples(p->codec); + if (!WavpackFlushSamples(p->codec)) { + lsx_fail_errno(ft, SOX_EINVAL, "%s", WavpackGetErrorMessage(p->codec)); + return SOX_EOF; + } + if (ft->seekable && WavpackGetNumSamples(p->codec) != WavpackGetSampleIndex(p->codec) && p->first_block_size >= 4) { + char * buf = lsx_malloc(p->first_block_size); + lsx_rewind(ft); + lsx_readchars(ft, buf, p->first_block_size); + if (!memcmp(buf, "wvpk", (size_t)4)) { + WavpackUpdateNumSamples(p->codec, buf); + lsx_rewind(ft); + lsx_writebuf(ft, buf, p->first_block_size); + } + free(buf); + } + p->codec = WavpackCloseFile(p->codec); + return SOX_SUCCESS; +} + +static int seek(sox_format_t * ft, uint64_t offset) +{ + priv_t * p = (priv_t *)ft->priv; + + return WavpackSeekSample(p->codec, (uint32_t) (offset / ft->signal.channels))? SOX_SUCCESS : SOX_EOF; +} + +LSX_FORMAT_HANDLER(wavpack) +{ + static char const * const names[] = {"wv", NULL}; + static unsigned const write_encodings[] = { + SOX_ENCODING_WAVPACK, 8, 16, 24, 32, 0, + SOX_ENCODING_WAVPACKF, 32, 0, + 0}; + static sox_format_handler_t handler = {SOX_LIB_VERSION_CODE, + "Lossless, lossy, and hybrid audio compression", + names, 0, + start_read, read_samples, stop_read, + start_write, write_samples, stop_write, + seek, write_encodings, NULL, sizeof(priv_t) + }; + return &handler; +} + +#endif /* HAVE_WAVPACK */ diff --git a/app/src/main/cpp/sox/win32/glob.c b/app/src/main/cpp/sox/win32/glob.c new file mode 100644 index 0000000..d1cf375 --- /dev/null +++ b/app/src/main/cpp/sox/win32/glob.c @@ -0,0 +1,170 @@ +/* libSoX minimal glob for MS-Windows: (c) 2009 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "glob.h" +#include +#include +#include +#define WIN32_LEAN_AND_MEAN 1 +#include + +typedef struct file_entry +{ + char name[MAX_PATH]; + struct file_entry *next; +} file_entry; + +static int +insert( + const char* path, + const char* name, + file_entry** phead) +{ + int len; + file_entry* cur = malloc(sizeof(file_entry)); + if (!cur) + { + return ENOMEM; + } + + len = _snprintf(cur->name, MAX_PATH, "%s%s", path, name); + cur->name[MAX_PATH - 1] = 0; + cur->next = *phead; + *phead = cur; + + return len < 0 || len >= MAX_PATH ? ENAMETOOLONG : 0; +} + +static int +entry_comparer( + const void* pv1, + const void* pv2) +{ + const file_entry* const * pe1 = pv1; + const file_entry* const * pe2 = pv2; + return _stricmp((*pe1)->name, (*pe2)->name); +} + +int +glob( + const char *pattern, + int flags, + void *unused, + glob_t *pglob) +{ + char path[MAX_PATH]; + file_entry *head = NULL; + int err = 0; + size_t len; + unsigned entries = 0; + WIN32_FIND_DATAA finddata; + HANDLE hfindfile; + + if (!pattern || flags != (flags & GLOB_FLAGS) || unused || !pglob) + { + errno = EINVAL; + return EINVAL; + } + + path[MAX_PATH - 1] = 0; + strncpy(path, pattern, MAX_PATH); + if (path[MAX_PATH - 1] != 0) + { + errno = ENAMETOOLONG; + return ENAMETOOLONG; + } + + len = strlen(path); + while (len > 0 && path[len - 1] != '/' && path[len - 1] != '\\') + len--; + path[len] = 0; + + hfindfile = FindFirstFileA(pattern, &finddata); + if (hfindfile == INVALID_HANDLE_VALUE) + { + if (flags & GLOB_NOCHECK) + { + err = insert("", pattern, &head); + entries++; + } + } + else + { + do + { + err = insert(path, finddata.cFileName, &head); + entries++; + } while (!err && FindNextFileA(hfindfile, &finddata)); + + FindClose(hfindfile); + } + + if (err == 0) + { + pglob->gl_pathv = malloc((entries + 1) * sizeof(char*)); + if (pglob->gl_pathv) + { + pglob->gl_pathc = entries; + pglob->gl_pathv[entries] = NULL; + for (; head; head = head->next, entries--) + pglob->gl_pathv[entries - 1] = (char*)head; + qsort(pglob->gl_pathv, pglob->gl_pathc, sizeof(char*), entry_comparer); + } + else + { + pglob->gl_pathc = 0; + err = ENOMEM; + } + } + else if (pglob) + { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } + + if (err) + { + file_entry *cur; + while (head) + { + cur = head; + head = head->next; + free(cur); + } + + errno = err; + } + + return err; +} + +void +globfree( + glob_t* pglob) +{ + if (pglob) + { + char** cur; + for (cur = pglob->gl_pathv; *cur; cur++) + { + free(*cur); + } + + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + } +} diff --git a/app/src/main/cpp/sox/win32/glob.h b/app/src/main/cpp/sox/win32/glob.h new file mode 100644 index 0000000..30f4179 --- /dev/null +++ b/app/src/main/cpp/sox/win32/glob.h @@ -0,0 +1,49 @@ +/* libSoX minimal glob for MS-Windows: (c) 2009 SoX contributors + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef GLOB_H +#define GLOB_H 1 + +#define GLOB_NOCHECK (16) +#define GLOB_FLAGS (GLOB_NOCHECK) + +typedef struct glob_t +{ + unsigned gl_pathc; + char **gl_pathv; +} glob_t; + +#ifdef __cplusplus +extern "C" { +#endif + +int +glob( + const char *pattern, + int flags, + void *unused, + glob_t *pglob); + +void +globfree( + glob_t* pglob); + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef GLOB_H */ diff --git a/app/src/main/cpp/sox/wve.c b/app/src/main/cpp/sox/wve.c new file mode 100644 index 0000000..d0f639b --- /dev/null +++ b/app/src/main/cpp/sox/wve.c @@ -0,0 +1,63 @@ +/* libSoX file format: Psion wve (c) 2008 robs@users.sourceforge.net + * + * See http://filext.com/file-extension/WVE + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +static char const ID1[18] = "ALawSoundFile**\0\017\020"; +static char const ID2[] = {0,0,0,1,0,0,0,0,0,0}; /* pad & repeat info: ignore */ + +static int start_read(sox_format_t * ft) +{ + char buf[sizeof(ID1)]; + uint32_t num_samples; + + if (lsx_readchars(ft, buf, sizeof(buf)) || lsx_readdw(ft, &num_samples) || + lsx_skipbytes(ft, sizeof(ID2))) + return SOX_EOF; + if (memcmp(ID1, buf, sizeof(buf))) { + lsx_fail_errno(ft, SOX_EHDR, "wve: can't find Psion identifier"); + return SOX_EOF; + } + return lsx_check_read_params(ft, 1, 8000., SOX_ENCODING_ALAW, 8, (uint64_t)num_samples, sox_true); +} + +static int write_header(sox_format_t * ft) +{ + uint64_t size64 = ft->olength? ft->olength:ft->signal.length; + unsigned size = size64 > UINT_MAX ? 0 : (unsigned)size64; + return lsx_writechars(ft, ID1, sizeof(ID1)) + || lsx_writedw(ft, size) + || lsx_writechars(ft, ID2, sizeof(ID2))? SOX_EOF:SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(wve) +{ + static char const * const names[] = {"wve", NULL}; + static sox_rate_t const write_rates[] = {8000, 0}; + static unsigned const write_encodings[] = {SOX_ENCODING_ALAW, 8, 0, 0}; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "Psion 3 audio format", + names, SOX_FILE_BIG_END | SOX_FILE_MONO | SOX_FILE_REWIND, + start_read, lsx_rawread, NULL, + write_header, lsx_rawwrite, NULL, + lsx_rawseek, write_encodings, write_rates, 0 + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/xa.c b/app/src/main/cpp/sox/xa.c new file mode 100644 index 0000000..9fc086e --- /dev/null +++ b/app/src/main/cpp/sox/xa.c @@ -0,0 +1,297 @@ +/* libSoX xa.c Support for Maxis .XA file format + * + * Copyright (C) 2006 Dwayne C. Litzenberger + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Thanks to Valery V. Anisimovsky for the + * "Maxis XA Audio File Format Description", dated 5-01-2002. */ + +#include "sox_i.h" + +#include +#include +#include + +#define HNIBBLE(byte) (((byte) >> 4) & 0xf) +#define LNIBBLE(byte) ((byte) & 0xf) + +/* .xa file header */ +typedef struct { + char magic[4]; /* "XA\0\0", "XAI\0" (sound/speech), or "XAJ\0" (music) */ + uint32_t outSize; /* decompressed size of the stream (in bytes) */ + + /* WAVEFORMATEX structure for the decompressed data */ + uint16_t tag; /* 0x0001 - PCM data */ + uint16_t channels; /* number of channels */ + uint32_t sampleRate; /* sample rate (samples/sec) */ + uint32_t avgByteRate; /* sampleRate * align */ + uint16_t align; /* bits / 8 * channels */ + uint16_t bits; /* 8 or 16 */ +} xa_header_t; + +typedef struct { + int32_t curSample; /* current sample */ + int32_t prevSample; /* previous sample */ + int32_t c1; + int32_t c2; + unsigned int shift; +} xa_state_t; + +/* Private data for .xa file */ +typedef struct { + xa_header_t header; + xa_state_t *state; + unsigned int blockSize; + unsigned int bufPos; /* position within the current block */ + unsigned char *buf; /* buffer for the current block */ + unsigned int bytesDecoded; /* number of decompressed bytes read */ +} priv_t; + +/* coefficients for EA ADPCM */ +static const int32_t EA_ADPCM_Table[]= { + 0, 240, 460, 392, + 0, 0, -208, -220, + 0, 1, 3, 4, + 7, 8, 10, 11, + 0, -1, -3, -4 +}; + +/* Clip sample to 16 bits */ +static inline int32_t clip16(int32_t sample) +{ + if (sample > 32767) { + return 32767; + } else if (sample < -32768) { + return -32768; + } else { + return sample; + } +} + +static int startread(sox_format_t * ft) +{ + priv_t * xa = (priv_t *) ft->priv; + char *magic = xa->header.magic; + + /* Check for the magic value */ + if (lsx_readbuf(ft, xa->header.magic, (size_t)4) != 4 || + (memcmp("XA\0\0", xa->header.magic, (size_t)4) != 0 && + memcmp("XAI\0", xa->header.magic, (size_t)4) != 0 && + memcmp("XAJ\0", xa->header.magic, (size_t)4) != 0)) + { + lsx_fail_errno(ft, SOX_EHDR, "XA: Header not found"); + return SOX_EOF; + } + + /* Read the rest of the header */ + if (lsx_readdw(ft, &xa->header.outSize) != SOX_SUCCESS) return SOX_EOF; + if (lsx_readw(ft, &xa->header.tag) != SOX_SUCCESS) return SOX_EOF; + if (lsx_readw(ft, &xa->header.channels) != SOX_SUCCESS) return SOX_EOF; + if (lsx_readdw(ft, &xa->header.sampleRate) != SOX_SUCCESS) return SOX_EOF; + if (lsx_readdw(ft, &xa->header.avgByteRate) != SOX_SUCCESS) return SOX_EOF; + if (lsx_readw(ft, &xa->header.align) != SOX_SUCCESS) return SOX_EOF; + if (lsx_readw(ft, &xa->header.bits) != SOX_SUCCESS) return SOX_EOF; + + /* Output the data from the header */ + lsx_debug("XA Header:"); + lsx_debug(" szID: %02x %02x %02x %02x |%c%c%c%c|", + magic[0], magic[1], magic[2], magic[3], + (magic[0] >= 0x20 && magic[0] <= 0x7e) ? magic[0] : '.', + (magic[1] >= 0x20 && magic[1] <= 0x7e) ? magic[1] : '.', + (magic[2] >= 0x20 && magic[2] <= 0x7e) ? magic[2] : '.', + (magic[3] >= 0x20 && magic[3] <= 0x7e) ? magic[3] : '.'); + lsx_debug(" dwOutSize: %u", xa->header.outSize); + lsx_debug(" wTag: 0x%04x", xa->header.tag); + lsx_debug(" wChannels: %u", xa->header.channels); + lsx_debug(" dwSampleRate: %u", xa->header.sampleRate); + lsx_debug(" dwAvgByteRate: %u", xa->header.avgByteRate); + lsx_debug(" wAlign: %u", xa->header.align); + lsx_debug(" wBits: %u", xa->header.bits); + + /* Populate the sox_soundstream structure */ + ft->encoding.encoding = SOX_ENCODING_SIGN2; + + if (!ft->encoding.bits_per_sample || ft->encoding.bits_per_sample == xa->header.bits) { + ft->encoding.bits_per_sample = xa->header.bits; + } else { + lsx_report("User options overriding size read in .xa header"); + } + + if (ft->signal.channels == 0 || ft->signal.channels == xa->header.channels) { + ft->signal.channels = xa->header.channels; + } else { + lsx_report("User options overriding channels read in .xa header"); + } + + if (ft->signal.rate == 0 || ft->signal.rate == xa->header.sampleRate) { + ft->signal.rate = xa->header.sampleRate; + } else { + lsx_report("User options overriding rate read in .xa header"); + } + + if (ft->signal.channels == 0 || ft->signal.channels > UINT16_MAX) { + lsx_fail_errno(ft, SOX_EFMT, "invalid channel count %d", + ft->signal.channels); + return SOX_EOF; + } + + /* Check for supported formats */ + if (ft->encoding.bits_per_sample != 16) { + lsx_fail_errno(ft, SOX_EFMT, "%d-bit sample resolution not supported.", + ft->encoding.bits_per_sample); + return SOX_EOF; + } + + /* Validate the header */ + if (xa->header.bits != ft->encoding.bits_per_sample) { + lsx_report("Invalid sample resolution %d bits. Assuming %d bits.", + xa->header.bits, ft->encoding.bits_per_sample); + xa->header.bits = ft->encoding.bits_per_sample; + } + if (xa->header.align != (ft->encoding.bits_per_sample >> 3) * xa->header.channels) { + lsx_report("Invalid sample alignment value %d. Assuming %d.", + xa->header.align, (ft->encoding.bits_per_sample >> 3) * xa->header.channels); + xa->header.align = (ft->encoding.bits_per_sample >> 3) * xa->header.channels; + } + if (xa->header.avgByteRate != (xa->header.align * xa->header.sampleRate)) { + lsx_report("Invalid dwAvgByteRate value %d. Assuming %d.", + xa->header.avgByteRate, xa->header.align * xa->header.sampleRate); + xa->header.avgByteRate = xa->header.align * xa->header.sampleRate; + } + + /* Set up the block buffer */ + xa->blockSize = ft->signal.channels * 0xf; + xa->bufPos = xa->blockSize; + + /* Allocate memory for the block buffer */ + xa->buf = lsx_calloc(1, (size_t)xa->blockSize); + + /* Allocate memory for the state */ + xa->state = lsx_calloc(sizeof(xa_state_t), ft->signal.channels); + + /* Final initialization */ + xa->bytesDecoded = 0; + + return SOX_SUCCESS; +} + +/* + * Read up to len samples from a file, converted to signed longs. + * Return the number of samples read. + */ +static size_t read_samples(sox_format_t * ft, sox_sample_t *buf, size_t len) +{ + priv_t * xa = (priv_t *) ft->priv; + int32_t sample; + unsigned char inByte; + size_t i, done, bytes; + + ft->sox_errno = SOX_SUCCESS; + done = 0; + while (done < len) { + if (xa->bufPos >= xa->blockSize) { + /* Read the next block */ + bytes = lsx_readbuf(ft, xa->buf, (size_t) xa->blockSize); + if (bytes < xa->blockSize) { + if (lsx_eof(ft)) { + if (done > 0) { + return done; + } + lsx_fail_errno(ft,SOX_EOF,"Premature EOF on .xa input file"); + return 0; + } else { + /* error */ + lsx_fail_errno(ft,SOX_EOF,"read error on input stream"); + return 0; + } + } + xa->bufPos = 0; + + for (i = 0; i < ft->signal.channels; i++) { + inByte = xa->buf[i]; + xa->state[i].c1 = EA_ADPCM_Table[HNIBBLE(inByte)]; + xa->state[i].c2 = EA_ADPCM_Table[HNIBBLE(inByte) + 4]; + xa->state[i].shift = LNIBBLE(inByte) + 8; + } + xa->bufPos += ft->signal.channels; + } else { + /* Process the block */ + for (i = 0; i < ft->signal.channels && done < len; i++) { + /* high nibble */ + sample = HNIBBLE(xa->buf[xa->bufPos+i]); + sample = (sample << 28) >> xa->state[i].shift; + sample = (sample + + xa->state[i].curSample * xa->state[i].c1 + + xa->state[i].prevSample * xa->state[i].c2 + 0x80) >> 8; + sample = clip16(sample); + xa->state[i].prevSample = xa->state[i].curSample; + xa->state[i].curSample = sample; + + buf[done++] = SOX_SIGNED_16BIT_TO_SAMPLE(sample,); + xa->bytesDecoded += (ft->encoding.bits_per_sample >> 3); + } + for (i = 0; i < ft->signal.channels && done < len; i++) { + /* low nibble */ + sample = LNIBBLE(xa->buf[xa->bufPos+i]); + sample = (sample << 28) >> xa->state[i].shift; + sample = (sample + + xa->state[i].curSample * xa->state[i].c1 + + xa->state[i].prevSample * xa->state[i].c2 + 0x80) >> 8; + sample = clip16(sample); + xa->state[i].prevSample = xa->state[i].curSample; + xa->state[i].curSample = sample; + + buf[done++] = SOX_SIGNED_16BIT_TO_SAMPLE(sample,); + xa->bytesDecoded += (ft->encoding.bits_per_sample >> 3); + } + + xa->bufPos += ft->signal.channels; + } + } + if (done == 0) { + return 0; + } + return done; +} + +static int stopread(sox_format_t * ft) +{ + priv_t * xa = (priv_t *) ft->priv; + + ft->sox_errno = SOX_SUCCESS; + + /* Free memory */ + free(xa->buf); + xa->buf = NULL; + free(xa->state); + xa->state = NULL; + + return SOX_SUCCESS; +} + +LSX_FORMAT_HANDLER(xa) +{ + static char const * const names[] = {"xa", NULL }; + static sox_format_handler_t const handler = {SOX_LIB_VERSION_CODE, + "16-bit ADPCM audio files used by Maxis games", + names, SOX_FILE_LIT_END, + startread, read_samples, stopread, + NULL, NULL, NULL, + NULL, NULL, NULL, sizeof(priv_t) + }; + return &handler; +} diff --git a/app/src/main/cpp/sox/xi.c b/app/src/main/cpp/sox/xi.c new file mode 100644 index 0000000..1033378 --- /dev/null +++ b/app/src/main/cpp/sox/xi.c @@ -0,0 +1,30 @@ +/* libSoX file format: XI Copyright (c) 2008 robs@users.sourceforge.net + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" + +LSX_FORMAT_HANDLER(xi) +{ + static char const * const names[] = {"xi", NULL}; + static unsigned const write_encodings[] = {SOX_ENCODING_DPCM, 16, 8, 0, 0}; + static sox_format_handler_t handler; + handler = *lsx_sndfile_format_fn(); + handler.description = "Fasttracker 2"; + handler.names = names; + handler.write_formats = write_encodings; + return &handler; +} diff --git a/app/src/main/cpp/sox/xmalloc.c b/app/src/main/cpp/sox/xmalloc.c new file mode 100644 index 0000000..72c9ea4 --- /dev/null +++ b/app/src/main/cpp/sox/xmalloc.c @@ -0,0 +1,73 @@ +/* SoX Memory allocation functions + * + * Copyright (c) 2005-2006 Reuben Thomas. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sox_i.h" +#include + +static void *lsx_checkptr(void *ptr) +{ + if (!ptr) { + lsx_fail("out of memory"); + exit(2); + } + + return ptr; +} + +/* Resize an allocated memory area; abort if not possible. + * + * For malloc, `If the size of the space requested is zero, the behavior is + * implementation defined: either a null pointer is returned, or the + * behavior is as if the size were some nonzero value, except that the + * returned pointer shall not be used to access an object' + */ +void *lsx_realloc(void *ptr, size_t newsize) +{ + if (ptr && newsize == 0) { + free(ptr); + return NULL; + } + + return lsx_checkptr(realloc(ptr, newsize)); +} + +void *lsx_malloc(size_t size) +{ + return lsx_checkptr(malloc(size + !size)); +} + +void *lsx_calloc(size_t n, size_t size) +{ + return lsx_checkptr(calloc(n + !n, size + !size)); +} + +void *lsx_realloc_array(void *p, size_t n, size_t size) +{ + if (n > (size_t)-1 / size) { + lsx_fail("malloc size overflow"); + exit(2); + } + + return lsx_realloc(p, n * size); +} + +char *lsx_strdup(const char *s) +{ + return lsx_checkptr(strdup(s)); +} diff --git a/app/src/main/cpp/sox/xmalloc.h b/app/src/main/cpp/sox/xmalloc.h new file mode 100644 index 0000000..21ff663 --- /dev/null +++ b/app/src/main/cpp/sox/xmalloc.h @@ -0,0 +1,36 @@ +/* libSoX Memory allocation functions + * + * Copyright (c) 2005-2006 Reuben Thomas. All rights reserved. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser + * General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef LSX_MALLOC_H +#define LSX_MALLOC_H + +#include +#include + +LSX_RETURN_VALID void *lsx_malloc(size_t size); +LSX_RETURN_VALID void *lsx_calloc(size_t n, size_t size); +LSX_RETURN_VALID void *lsx_realloc_array(void *p, size_t n, size_t size); +LSX_RETURN_VALID char *lsx_strdup(const char *s); + +#define lsx_Calloc(v,n) v = lsx_calloc(n,sizeof(*(v))) +#define lsx_memdup(p,s) ((p)? memcpy(lsx_malloc(s), p, s) : NULL) +#define lsx_valloc(v,n) v = lsx_realloc_array(NULL, n, sizeof(*(v))) +#define lsx_revalloc(v,n) v = lsx_realloc_array(v, n, sizeof(*(v))) + +#endif